Jump to content

Arnaud Bouchez

Members
  • Content Count

    316
  • Joined

  • Last visited

  • Days Won

    22

Posts posted by Arnaud Bouchez


  1. Just use a while loop!
    This is the clear and efficient way of writing such code, without messing with the "for" variable.

    var
      i: integer;
    begin
      i := 1;
      while i <= 10 do begin
        Writeln(i);
        inc(i, 2);
      end;
      Readln;
    end.

    Or a repeat .. until of course:

    var
      i: integer;
    begin
      i := 1;
      repeat
        Writeln(i);
        inc(i, 2);
      until i > 10;  
      Readln;
    end.
    • Like 1

  2. I think the compiler is lost since you didn't put any parameter to your external function definition.

    It is just the same for the result parameter in RAX as for regular parameters.

    Try with the exact function definition including all parameters, and I hope (crossed fingers!) it will be fine.

     

    The "stack frames" parameter in the Project Options is pointless on Win64 IIRC.

    Only with an `asm .noframe` directive you may have no stack frame.

     

    IMHO the redirection call won't be noticeable in performance, especially if you write:

    asm
        .noframe
        jmp AVXGENERATE_TSLIVERHELPER_NS
    end;

     

    I wouldn't play with inline + assembly with Delphi, which has a long history of problems when inlining code...


  3. The SQLite3 documentation you quoted didn't take into account that a client/server layer like mORMot.
    And for this use case (mORMot + SQlite3), it states the contrary in https://www.sqlite.org/whentouse.html

    Quote

    Server-side database

    Systems designers report success using SQLite as a data store on server applications running in the datacenter, or in other words, using SQLite as the underlying storage engine for an application-specific database server.

    With this pattern, the overall system is still client/server: clients send requests to the server and get back replies over the network. But instead of sending generic SQL and getting back raw table content, the client requests and server responses are high-level and application-specific. The server translates requests into multiple SQL queries, gathers the results, does post-processing, filtering, and analysis, then constructs a high-level reply containing only the essential information.

    Developers report that SQLite is often faster than a client/server SQL database engine in this scenario. Database requests are serialized by the server, so concurrency is not an issue. Concurrency is also improved by "database sharding": using separate database files for different subdomains. For example, the server might have a separate SQLite database for each user, so that the server can handle hundreds or thousands of simultaneous connections, but each SQLite database is only used by one connection.


  4. @Hans J. Ellingsgaard You are making assumption, I am afraid.

     

    On the server side, a single SQlite3 insert takes a few microseconds.
    A batched SQlite3 from our ORM (i.e. several inserts per requests) writes at 200,000 inserts per second on a laptop.
    See https://synopse.info/files/html/Synopse mORMot Framework SAD 1.18.html#TITL_59
    No remote client/server DB I know is so fast, even running on localhost.


    And from concurrent writers over HTTP, you got more than 6000 inserts per second on a laptop with 200 concurrent clients (one insert per request).
    See https://synopse.info/files/html/Synopse mORMot Framework SAD 1.18.html#TITL_4

    This is faster than regular client/server databases, and we tested it even with 50,000 clients - try to make it with a regular RBMS.

     

    We setup backup and replication in our framework for SQLite3 backup.
    As you stated, using an ORM like the one in mORMot would allow to switch to another DB, even a NoSQL one like MongoDB, with no code modification.
    But from all our tests, SQLite3 was the fastest when building MicroServices - i.e. Services which require a local storage.


  5. It is a perfect match for mORMot + SQLite3.

    But I am biased for sure! 😄

     

    You may even use easily one database per account, if you wish too... this ease maintenability and scaling a lot!

     

    And eventually you would be able to use FPC to compile your server application for Linux, if you need to.

     

    Performance will be much higher than with FireBird or other remote DB, and SQlite3 is perhaps the most well tested DB ever.  https://www.sqlite.org/testing.html
    We use it on production with DB of dozen of GB, with no problem - and it usually uses much less disk space than FireBird for instance.

     


  6. As backend, consider SQlite3 as a local database on the server side. It is perfect for such service storage.
    There are several SQLite3 libraries for Delphi, from FireDAC to Zeos/ZDBC or mORMot.

     

    In your code, if you don't know anything about SQL, consider using an ORM like Aurelius or mORMot to work with objects, and not SQL.


  7.  

    @Kryvich Changing the compiler requirements on such would break backward compatibility. This is why I doubt it would happen.

     

    Another problem is about the overloaded functions. The compiler will complain about ambiguous usage, and will abort compilation.
    And another is about type helpers: it is for a given type, so you can't use double.ToString as TDistanceMeters.ToString IIRC. I complained against that when they introduced type helpers - I guess noone at EMB uses user defined simple types (whereas I use it everywhere).

     

    @David Heffernan Defining records is indeed the proper way of ensuring very strong type checking. Especially with the implicit conversion introduced with Delphi 10.3. And you would gain methods, e.g. for making conversions explicit (which is even better).

    But in practice, I like the fact that "type double" gives at least some information in the IDE (e.g. code completion) which is not needed to be put as parameter or function name.


  8. 2 hours ago, Kryvich said:

    Regarding the naming of units. It makes sense to name a unit like this: ProjectName.UnitName.pas. ProjectName can be the abbreviated name of your project. And if the project is really big (like Delphi) - add the name of the subproject instead, for ex.: System.Types, Vcl.Forms, FMX.Forms etc. An even Subproject.Subproject.UnitName.pas: FMX.Forms.Border.pas, FMX.ListView.Appearances.pas... 

    Yes, camel-casing or using commas are options.
    Since some of the code is expected to run on Delphi 7 (for several convenient reasons, no technical ones) we didn't use comma.
    But the point of the proposal was that we won't use the project name, but the *folder* name within the unit name, to ensure 1. that the file is easy to locate in the SCM or at file level 2. the folder logic is not about projects, but to ensure data/ui/projects/etc... are uncoupled. Folder layout, therefore unit name layout, therefore the system architecture, should not be project-oriented, but domain-oriented - see https://martinfowler.com/tags/application architecture.html

    • Like 1
×