Jump to content


Popular Content

Showing content with the highest reputation since 07/14/24 in all areas

  1. Darian Miller

    Is there a Delphi "subprocess" library?

    There's quite a few options out there. I wrote a related blog post and provided some example code: https://ideasawakened.com/post/use-createprocess-and-capture-the-output-in-windows
  2. dummzeuch

    Release or Debug?

    I am taking yet another different approach: The "If you download the sources, the buildnumber will 0. Live with it." approach.
  3. Hey my challenge peeps!! We have finally arrived at the end of the challenge!! It's been a fun ride, to say the least. The final results have been posted, with the usual minor ooopss, of course. Like stated before, I'll be accepting entries until I'm no longer in this plane of existence. A new results table for those entries will be made, and it will include all of the entries, old and new. Eventually, I'll also publish a results table for 400 Stations and 8 threads. Just need a bit of breathing space to get that done. But it will come. Let's hope this repository, and the effort of the participants, can stand as an example of the power that still resides in Object Pascal. Let's hope we can all shut up the nay sayers by merely pointing at it. All the best for you all in your future Object Pascal endeavours!! Cheers, Gus
  4. Hey my challenge peeps!! Looks like we have the results of the comparison back and Object Pascal is quicker than Java. Reference: https://github.com/gcarreno/1brc-ObjectPascal/discussions/103#discussioncomment-9359820 Cheers, Gus
  5. My dear challenge peeps!! Now that the Blaise Pascal Magazine new edition is out, I can finally talk about this: Ian Barker has written an article that mentions our little challenge. I would provide a link to this new edition if I could. Their site is a bit sub-par, to put it quite politely. Cheers, Gus
  6. And don't forget the command line parser available in mORMot 2. - Works on all OS; - Works on Delphi and FPC; - Can auto-generate the help content with proper formatting; - Minimal code writing. In practice, resulting code is short and efficient: https://github.com/synopse/1brc-ObjectPascal/blob/main/entries/abouchez/src/brcmormot.lpr#L446
  7. Nice list, thanks 👍 You missed these few, probably: https://rosettacode.org/wiki/Parse_command-line_arguments#Delphi https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.SysUtils.FindCmdLineSwitch https://github.com/exilon/QuickLib/blob/d085aa28e5fd65bae766446f5355ec4dc80fae9e/Quick.Commons.pas#L1292 https://wiert.me/2015/05/13/on-the-delphi-tcommandparser-class-for-parsing-command-lines-and-arguments-via-suggestions-for-how-to-define-command-line-parameters-stack-overflow/ https://github.com/jackdp/JPLib/blob/master/Base/JPL.CmdLineParser.pas https://github.com/tokibito/delphi-argparse
  8. This is a "classical" problem with Delphi, overloaded functions, and floating points values. IMHO using currency is an awful workaround here, and should not be kept in any serious codebase. It works "by chance". Another workaround, still using the Math unit, is to make the computation in two steps: function RoundExDouble(x: double): Double; begin x := x * 10; Result := Ceil(x) / 10; end; function RoundExInteger(x: double): Integer; begin x := x * 10; Result := Ceil(x); end; So the expected Ceil(double) overload is clearly picked up by the compiler. Or define our own unique Ceil() function, which does not depend on Math.pas and ensure we use the right value type: function ceil(x: double): integer; begin result := trunc(x) + ord(frac(x) > 0); end; This is this solution I used in my entry of the challenge: stay away from Math.pas. 😉
  9. Hey Cornelius, We are coordinating, live, on Discord. I'm not sure you're a Discord person, or even if you're into online chat things, but I thought you should have that piece of info. We are assembling on these: The "Delphi Community" Discord server on the events channel The "Unofficial Free Pascal" Discord server on the off-topic channel( mainly, because the server owner did not create a channel for the event ) Cheers, Gus
  10. Lots of options! Command-line parameter validation fixed for Delphi--pull request made. Generated a few different sized files for testing, the last two: 100-million row file created in 9 seconds 1-billion row file created in 2 minutes, 23 seconds.
  11. Hey Cornelius, I was actually considering this one: VSoft.CommandLineParser That one seems to be a self contained thing without dragging much more. But also had these in the back burner: rcmdline FDC.CommandLine.pas GpCommandLineParser.pas But now I need to add that one to my list since I don't have it 😃 Thanks !! Cheers, Gus
  12. So assuming that your code scales linearly it will only take 92 days for 1 billion rows
  13. Hey Gus, It seems like a fun challenge that people who have time and interest will look at and participate. We've got a couple of months, so plenty of time to get involved if you're so inclined. One question: the .CSV in the repository has only 44,691 entries. So, the idea is that we need to run the generator program first to generate the 1B file, right? I suppose this could also, then, be used to generate smaller files for development testing. Thanks for the links and for bringing it to the Delphi community!
  14. Hey Attila, I am know to go off in tangents and angry rants, sometimes, for not much. I'm also involved in a bunch of other communities like Telegram(English and Portuguese, Lazarus and Delphi), Discord( 3 Servers of Lazarus and Delphi) and the Lazarus Forums. In none of those have I ever had such a response. In all of the above I try really hard to welcome the padawans that wander in with the most devilishly incomplete and weird questions, trying to hang on to the patience of a saint. Heck, I even got made MVP by Ian because of that alone!! When I come to a new place and I'm greeted this way, welp, my short fuse did get lit, consumed and passed the spark to the gun powder!! I probably need to apologise for the words I've used. But I'm not apologising for the message conveyed! Cheers, Gus
  15. Hey dummzeuch, BTW... Writing 5 paragraphs with a conjecture of how to do it and then dismissing the entire thing as being "not much of a challenge" is a bit of a crappy dismissal, no? Instead of just resting on your thought experiment, why don't you put your money where your mouth is and prove what you claim? Shooting from the hip is rather easy, but making an entry and proving your chops is something entirely different, right? I'm a bit miffed and my choice of words may seem harsh, but the lack of usefulness or any point in the answers I got just gave me a very bad brogrammer machismo vibe that I've only seen in Stack Overflow. If this is the type of welcome you peeps extend to a newcomer... I dunno... It's pretty toxic... Even in the case that this could not be the type of thing that the regulars here have an interest in, at least a sense of community is the least to expect, no? I deeply regret the thought I had of attempting to post here! I just hope that name calling and dumb shaming is not the next thing I'm to be dealt... Cheers, Gus
  16. Hey Attila, Thank you very much !!! I don't see that as an issue. I see that as a fact of life, like everyone has a personal life. Then you chose to make the time for it or not, and that depends on your schedule and your will to participate. I'm not putting a gun on anyone's head, just proposing a fun, and quite optional, exercise in programming. Cheers, Gus
  17. dummzeuch

    Is there a Delphi "subprocess" library?

    If I understood this correctly, a Python subprocess starts an external program, connects its stdin/out/err to pipes and gets the return code when it exits. There is nothing like this in the standard Delphi RTL but there are multiple third party options. If I remember correctly one is in the JCL, another is my own TAsyncExec class in unit u_dzAsyncExec which is part of my dzlib library.
  18. DxDublin

    Looking for a localization tool

    I did a more thorough test with these four localization tools. Our application is huge. It contains hundreds of forms and thousands of units. Most of those units have resource strings. We also use visual form inheritance in every form. We use frames and inherited frames, too. Our forms have been designed such a way that there is plenty of room for string expansion. So, we do not need a form editor to change the layout. However, translators need a form preview to see the context of the strings. We use several freelance translators that need to work simultaneously with the developers. We use CI/CD and new content appears almost every week. Finally, we have both 32-bit and 64-bit version of our application. We target to 6 languages. Before we start, I would like to point it out that Delphi has a specific pattern how the localization should be done. It is to use forms, resource strings and resource DLLs. ITE uses this approach. Unfortunately, the implementation of ITE is just so bad that it is barely useable. Therefore, there is room for other tools. Let’s start write TsiLang. It is a component-based solution. It does not follow the standard VCL localization method but forces you to do major refactoring to your code. This means adding components to every form and replacing resource strings with TsiLang’s own implementation. The product works, and it is very cheap. I am sure TsiLang has its own fans. In a large project like ours, the price of the localization tool is not the prime factor. The features are. This is where TsiLang gets short. No form preview, propriety implementation, limited team work features, limited translation aids (TM, MT, terminology). This was the first to go. Korzh Localizer is a step forward. It allows you to use resource strings. It does not refactor your source code hardly at all. However, it is not based on resource DLL but uses its own language files. Like TsiLang it does not have form preview and has very limited translation aids. This was the second to go. Remaining two tools, BTM and Soluling, both works on the right principle: the standard VCL localization method. They are also totally decoupled from Delphi IDE that is very important. I like them both. BTM is a free tool and a very good one. It does the localization so much better than the TsiLang and Localizer. BTM is free and Anders has maintained it for three years. Huge respect for him. However, BTM lacks some very important features. First the form preview. Second is that if you have both 32-bit and 64-bit applications, you need to create two separate projects and somehow copy paste the translations. In addition, it scans all strings properties and you have to exclude them manually. There are no rules to configure what properties to localize and what to ignore. BTM has some translations aids but lots of features are missing, such as translation validation and interactive TM/MT/terms. My test sample contains TTreeView and TListView components. TsiLang, Localizer and BTM did not scan the nodes of those components. They were just ignored. What am I supposed to do in a case like that? Remove the design time data and populate the nodes on runtime using resource strings. No thanks. In most case you do not need (and should not) localize images but sometimes you have to. These tree tools cannot handle them either. This brings me to the last tool, Soluling. Soluling is more expensive than the above three tools. However, with that price, you get a tool that has all the features you need to localize a large VCL application. Soluling has a brilliant form editor. It is not only a preview, but you can change the layout. I would suggest not to go on that path but to pay some extra attention to your original UI design. However, if you need to do layout change, you can. Soluling localizes TTreeView, TListView and images. Soluling also has a concept of platform files. It means that you can add many variants of the same EXE file (e.g. 32-bit, 64-bit, debug, trial, etc.). No need to have a duplicate project file. No need to translate the same strings twice. Soluling’s translation aids are top level. Soluling’s features even exceed the features of the mainstream CAT tools like Passolo, MemoQ and Catalyst! Finally, in most cases you have also some other files but Delphi application to localize. For example, you might have some documentation files and web pages. Soluling can do those too. I quickly tested HTML, React and Markdown. All worked nicely. Both BTM and Soluling have a command-line tool to be used in the build pipeline. The both tools require zero changes to your source code and you are not forever bound to the tool you selected, such in the case you selected TsiLang or Localizer. Ultimately, this is a “battle“ between two Nordic guys: Anders and Jaakko. They both did it right. If you have a small Delphi-only project and small budget, go for Better Translation Manager. If you have a larger project or budget, or you also have other files but Delphi EXEs, go for Soluling. I have attached screnshots from each tool.
  19. Remy Lebeau

    Destroying TList with Managed Types

    No, because the as operator forces the compiler to create a hidden variable for the interface, before it is then passed to the const parameter. Had the code been written like this instead, THEN there would have been a problem: List.Add(TItem.Create); Correct.
  20. Remy Lebeau

    Destroying TList with Managed Types

    That is not the reason. Your test functions may simply be holding a hidden local reference to the IItem that you create and add to the list, so the item is not fully released until after the list has been freed first. Try this instead to isolate that reference so it gets released sooner: procedure TestDestroyOnly; var List: TItemList; procedure AddItem; begin List.Add(TItem.Create as IItem); end; begin Writeln( 'Start Test - Destroy Only'); List := TItemList.Create; try AddItem; finally List.Free; end; Writeln( 'End Test - Destroy Only'); end; procedure TestWithExplicitClear; var List: TItemList; procedure AddItem; begin List.Add(TItem.Create as IItem); end; begin Writeln( 'Start Test - Explicit Clear'); List := TItemList.Create; try AddItem; List.Clear; finally List.Free; end; Writeln( 'End Test - Explicit Clear'); end;
  21. Lars Fosdal

    How to use the FireDAC Monitor classes

    How to do FireDAC monitoring or logging to file. Here is a rough outline of what you need to do. The code is not ready to use as is and serves only to give you the general gist. Add FireDAC.Moni.Base, FireDAC.Moni.RemoteClient, FireDAC.Moni.FlatFile to your uses clause Somewhere appropriate, create the following - I keep them in my DatabasePool class. FTracing: Boolean // init to False FMonitorBy: TFDMonitorBy; // init to mbRemote FMonitorLink: TFDMoniClientLinkBase; // init to nil // Here is where the actual establishing of the tracing happens depending on the trace model. procedure TDBPool.SetMonitorBy(const Value: TFDMonitorBy); begin Lock; try if (FMonitorBy <> Value) and Assigned(MonitorLink) then FreeAndNil(FMonitorLink); FMonitorBy := Value; // mbNone or mbCustom disables the monitoring if MonitorBy = mbRemote then begin MonitorLink := TFDMoniRemoteClientLink.Create(nil); end else if MonitorBy = mbFlatFile then begin MonitorLink := TFDMoniFlatFileClientLink.Create(nil); TFDMoniFlatFileClientLink(MonitorLink).FileName := ParamStr(0)+'.'+FormatDateTime('yyyymmdd-hhnnss', Now)+'.FireDAC.log'; TFDMoniFlatFileClientLink(MonitorLink).FileAppend := False; end; if Assigned(MonitorLink) then MonitorLink.Tracing := Self.Tracing; finally Unlock; end; end; // Use Tracing to enable / disable the tracing function TDBPool.GetTracing: Boolean; begin Result := FTracing; end; procedure TDBPool.SetTracing(const Value: Boolean); begin FTracing := Value; if not Assigned(MonitorLink) then SetMonitorBy(FMonitorBy) else MonitorLink.Tracing := Self.Tracing; end; procedure TDBPool.SetMonitorLink( const Value: TFDMoniClientLinkBase); begin FMonitorLink := Value; end; // When the DB connection is created - it should assign the MonitorBy value procedure TDB_FD.CreateFireDACConnections; const OSAuthent = 'No'; begin if not Assigned(FConnection) then begin OnConnectionCreate; FConnection := TFDConnection.Create(nil); FConnection.DriverName := DBPool.DataBaseDriverName; // that you have selected - This example assumes an MSSQL driver - see other code block below FConnection.Params.Values[MSSQLParam.Server] := Trim(FHost); FConnection.Params.Values[MSSQLParam.Database] := Trim(FDatabaseName); FConnection.Params.Values[MSSQLParam.OSAuthent] := OSAuthent; FConnection.Params.Values[MSSQLParam.User_Name] := Trim(FUserName); FConnection.Params.Values[MSSQLParam.Password] := Trim(FPassword); FConnection.Params.MonitorBy := DBPool.MonitorBy; ... end; BTW - Selecting the right DatabaseDriverName can have a significant impact on performance. Here is how I currently pick my preferred MSSQL driver. Why are those constants are not in the interface section of FireDAC.Phys.MSSQL, @Dmitry Arefiev? class function TDBPoolMSSQL.FindBestDriver(const Link: TFDPhysMSSQLDriverLink): String; const // Constants copied from implementation section of FireDAC.Phys.MSSQL C_2018_ODBC = 'ODBC DRIVER 18 FOR SQL SERVER'; C_2017_ODBC = 'ODBC DRIVER 17 FOR SQL SERVER'; C_2016_ODBC = 'ODBC DRIVER 13 FOR SQL SERVER'; C_2012_ODBC = 'ODBC DRIVER 11 FOR SQL SERVER'; {$IFDEF POSIX} C_FreeTDS = 'FreeTDS'; {$ENDIF} {$IFDEF MSWINDOWS} C_2012_NC = 'SQL SERVER NATIVE CLIENT 11.0'; {$ENDIF} var DriverList : TStringList; WantedList : TArray<String>; begin Result := ''; // Blank = Default WantedList := {$IFDEF MSWINDOWS} {$IFDEF SQLNative} // defined if supposed to prioritize the old SQLNCLI11 [C_2012_NC, C_2017_ODBC, C_2016_ODBC, C_2012_ODBC] {$ELSE} [C_2018_ODBC, C_2017_ODBC, C_2016_ODBC, C_2012_NC, C_2012_ODBC] {$ENDIF} {$ENDIF} {$IFDEF POSIX} [C_2018_ODBC, C_2017_ODBC, C_2016_ODBC, C_2012_ODBC, C_FreeTDS] {$ENDIF}; DriverList := TStringList.Create; try Link.GetDrivers(DriverList); for var Wanted in WantedList do for var Driver in DriverList do begin // DebugOut('ODBC: "' + Driver + '"'); if CompareText(Wanted , Driver) = 0 then Exit(Wanted); end; finally DriverList.Free; end; end;
  22. Dalija Prasnikar

    Recursive anonymous functions

    var [weak] fib: TFunc<integer,int64>; Marking it as weak breaks the cycle. However, there was a bug with weak that is only recently fixed (not sure whether in 10.3 or 10.3.1)
  23. Yes, they work 🙂 (and why wouldn't they?). program RecursiveAnon; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; function MakeFib: TFunc<integer,int64>; var fib: TFunc<integer,int64>; begin fib := function (value: integer): int64 begin if value < 3 then Result := 1 else Result := fib(value - 1) + fib(value -2); end; Result := fib; end; begin var fib := MakeFib; for var i := 1 to 10 do Write(fib(i), ' '); Readln; end.
  24. Primož Gabrijelčič

    Recursive anonymous functions

    Of course it is! You can do this: for i := 1 to 10 do Writeln(MakeFib()(i), ' '); As Stefan noted on a side-channel, calling MakeFib causes a memory leak because the anonfunc interface now contains a cyclic reference to itself.
  25. Lars Fosdal

    Recursive anonymous functions

    You should read this post