Jump to content

Stefan Glienke

Members
  • Content Count

    1442
  • Joined

  • Last visited

  • Days Won

    145

Everything posted by Stefan Glienke

  1. Stefan Glienke

    DevEx VCL Components & VCL Styles??

    There seems to be an adapter to apply VCLStyles to DevExpress components: https://www.almdev.com/prods/stylecontrols/stylecontrols.html - I have no experience with this but at some point we will have to look into this as customers keep asking for Dark mode in our application 😎 🙈
  2. Stefan Glienke

    What new features would you like to see in Delphi 13?

    You are comparing Win32/Debug with Win64/Release *cough*
  3. Stefan Glienke

    What new features would you like to see in Delphi 13?

    Delphi developers.... one half still uses Delphi 7 and the other one does not even do 32-bit anymore
  4. Stefan Glienke

    CreateObservableList example in Spring4D

    All collections have events for getting notified of addition/removal via the OnChanged event - observable lists are something different. On those if the objects implement INotifyPropertyChanged they communicate to the list that a property has changed so the list then gets caChanged from those items.
  5. Most simple case to repro to compiler error: procedure X(i: Integer); begin end; procedure Y; begin var f: TFunc<Integer>; X(f); end;
  6. Stefan Glienke

    Get Index of enumeration in spring4D

    https://bitbucket.org/sglienke/spring4d/src/2.0.1/Source/Base/Collections/Spring.Collections.pas#lines-6391
  7. Stefan Glienke

    Get Index of enumeration in spring4D

    First of all, you can already achieve what you asked for in two different ways. (As I said, I will look into adding a similar method as .NET 9 did, but it's not as easy due to Delphi's limitations - it most likely will be a static method on TEnumerable and not on IEnumerable because it returns a differently typed IEnumerable, and that causes the Delphi compiler to complain with E2604.) Apart from the obvious use of a classic for-to loop if you already have an indexable collection such as IList where that new method IMHO would make no sense and just add overhead you can do this: var indexedColl := TEnumerable.Zip<Integer,TMyClass>(TEnumerable.Range(0, myColl.Count), myColl); for var curItem in indexedColl do Writeln('index: ', curItem.Value1, ' - item: ', curItem.Value2.ToString); If you want more control over index generation you can write this: var indexedColl := TEnumerable.Select<TMyClass, Tuple<Integer,TMyClass>>(myColl, function(const item: TMyClass; const index: Integer): Tuple<Integer,TMyClass> begin Result := Tuple<integer,TMyClass>.Create(index, item); end); for var curItem in indexedColl do Writeln('index: ', curItem.Value1, ' - item: ', curItem.Value2.ToString); If you then want to filter only certain indexes you just call Where on indexedColl: var oddIndexes := indexedColl.Where( function(const tuple: Tuple<Integer,TMyClass>): Boolean begin Result := Odd(tuple.Value1); end); for var curItem in oddIndexes do Writeln('index: ', curItem.Value1, ' - item: ', curItem.Value2.ToString);
  8. Stefan Glienke

    Get Index of enumeration in spring4D

    This would be a duplication of the already existing Where
  9. Stefan Glienke

    How to access/modify underlying records of IList<T>

    I have something like that in the works already. It does create a copy (records are value types, what else should it do?) - what you are proposing is dangerous and error-prone. That is not the case anymore in 2.0 - that interface has been removed from lists.
  10. Stefan Glienke

    Get Index of enumeration in spring4D

    No, but I see that .NET 9 added this. I might consider it.
  11. Stefan Glienke

    ISet<T> in spring4D

    FWIW if your type is an enum already it makes no sense to use ISet<T> because you can use the enum set. ISet<T> is for types that are no enums, such as string for example.
  12. Stefan Glienke

    Understanding DUnitX.Assert.WillRaise

    Passing parameters like that does not work in DUnitX - it silently ignores the string name for the exception class and then passes nil. Calling Assert.WillRaise with nil as exceptionClass succeeds when any exception was raised. @Vincent Parrett should be able to tell the best way to pass any parameters that cannot be easily converted from string.
  13. Stefan Glienke

    chatgpt can convert 32bit asm into 64bit

    Converting source code that won any challenge over 15 years ago is questionable regardless of correctness. Anyway, for this particular example, implementing a faster System.Move for Windows (other platforms use their libc memory) has been solved since Delphi 11.3. I sincerely challenge everyone to come up with a faster/better implementation.
  14. Stefan Glienke

    Strict type checking for tObject.

    It is pretty simple - imagine if the code below would work that way: procedure ReplacePet(var pet: TPet); begin pet.Free; pet := TCat.Create; end; procedure Main; var dog: TDog; begin ReplacePet(dog); dog.Bark; // meow?! end; FreeAndNil is special because it just destroys and assigns nil. But a var parameter does not give that guarantee.
  15. Stefan Glienke

    Double, default value

    Which - fun fact - does not happen on the method call (unless it's a virtual method) but when accessing any member inside of it. You could still have some method which does not access any member and it will not AV at all. We can argue all day about this - any runtime behavior one might slap onto it will not save the language from being inherently unsafe. It needs to be built into the language/compiler itself (Hi, Rust)
  16. Stefan Glienke

    Double, default value

    The main issue with memory safety in Delphi is not non-initialized local variables, which the compiler warns about, but use-after-free.
  17. Stefan Glienke

    Double, default value

    First, it's wrong to assume that all local variables reside on the stack, depending on optimization they might be in registers. Second, rep stosd is terribly slow for small sizes (see https://stackoverflow.com/a/33485055/587106 and also the discussions on this issue https://github.com/dotnet/runtime/issues/10744) Also, the Delphi compiler arranges managed local variables into one block that it zeroes (in many different and mostly terribly inefficient ways).
  18. Stefan Glienke

    Double, default value

    Why should the CPU waste time zeroing stuff that will be set shortly after anyway? Compilers are there to warn/error when any code path leads to a situation where a variable is not initialized.
  19. type TCustomItem = class; TCustomContainer = class abstract protected procedure HandleItemNotification(AItem: TCustomItem); virtual; abstract; end; TCustomItem = class protected FContainer: TCustomContainer; end; TCustomContainer<T: TCustomItem> = class abstract(TCustomContainer) protected FItems: TArray<T>; procedure HandleItemNotification(AItem: TCustomItem); overload; override; final; procedure HandleItemNotification(AItem: T); reintroduce; overload; end; TFooItem = class(TCustomItem) procedure SomeMethod; end; TFooContainer = class(TCustomContainer<TFooItem>); procedure TCustomContainer<T>.HandleItemNotification(AItem: T); begin // ... end; procedure TCustomContainer<T>.HandleItemNotification(AItem: TCustomItem); begin HandleItemNotification(T(AItem)); end; procedure TFooItem.SomeMethod; begin FContainer.HandleItemNotification(Self); end; var foo: TFooItem; begin foo := TFooItem.Create; foo.FContainer := TFooContainer.Create; foo.SomeMethod; end. I suggest moving as much code into the non generic base classes as possible. Given the constraint on TCustomItem this should even be reasonably easy to achieve. This will prevent causing larger than necessary binary sizes and longer than necessary compiletimes.
  20. Stefan Glienke

    Do you need an ARM64 compiler for Windows?

    Yes, pretty much - we all know they first ship a half-baked feature to generate marketing hype and then spend the next decade tinkering around the edges to make it work while representatives are telling us "eh, its complicated"
  21. It looks like whoever implemented that in the Delphi compiler was overly obsessed with codesize. If you compare what both gcc and clang do you can see that they rather produce a ton of mov instructions (which execute nicely in parallel on modern processors) before using memmov or rep: https://godbolt.org/z/Gjsqn7qas (change the size of the static array to see the assembly code change)
  22. Stefan Glienke

    win11 24h2 msheap fastest

    That benchmark proves almost (*) nothing, the only point where it allocates is during the form creation where it builds the card deck and later when it prints the output into the TListBox. (*) the only thing affected here is the possible layout of the card objects in the heap as they are all read during the hand-processing code. The difference that you can observe here between Delphi buids using different memory managers is most likely caused by the amount of overhead the respective memory manager is using thus fitting more card objects within the same memory pages, thus more of them (most likely all on modern processors) fitting into L1 cache. As for this particular code - removing the name of the Cards from the object and only building it when it is needed for some UI would probably speed up code more than anything else because you get rid of 20 Byte for every object (Name is a string[19]) - on my CPU this makes the code go down from ~900ms to ~680ms - simply because it does not need to copy the strings in CopyCardFromDeck. Circumventing the getter and setter of TList (which contribute around 25% of the remaining time) brings it down to 460ms. And after that we are not done with string stuff - in every loop iteration, it calls Hand.SetHighValues which produces a name for the cards on the hand - removing that gets me down to ~400. Now because I have a run and SamplingProfiler open already I see that now one of the scorers is TcaaPokerHand.CopyCardFromDeck - the Items getter is not inlined which causes it to be called 10 times for the same 2 card objects. Changing that gets me down to 270ms. But how about avoiding repeated access to the same object in the 2 lists altogether? 230ms I could go on because I see a lot more room to optimize - but I think I made my point. Instead of fiddling with the memory manager one should first look if heap allocations are even the issue. And then identify unnecessary work and eliminate that. ... change TcaaEvaluationCard to be 8 Byte size - (that avoids that the compiler creates a movsd/movsb instruction but simply does an 8 byte mov) -> 160ms
  23. Stefan Glienke

    String memory usage

    If you were using the RTL dictionary with its abysmal performance, that does not surprise me at all. Mostly because of its poor hash function, replacing that with a better one speeds it up significantly. However, string interning does not require a dictionary with key/value but just a hashtable for strings. DelphiAST has the option to use one for its parsing - we needed that when using it in the context of the IDE to avoid spikes in memory consumption.
  24. Clever way of introducing thread-unsafety 😉
  25. Stefan Glienke

    TParallelArray Sort Performance...

    Did you precompile Spring or are you compiling directly from the sources? If you precompile (recommended) then you need to precompile with release settings of course. If I had to bet I would say you still have range checking enabled (RTL has that disabled, so does your code) Also tbh I don't care about a 30% improvement of a handwritten algo specifically for one type over the generic one. Yes, compiler could do a better job with more aggressively inlining and stuff but nowadays I am happy already if it generates working code. Apart from the code not compiling I would say it depends on what you want to benchmark - how sort performs on completely cold data? Like some data that you loaded an hour ago, then did completely different things so it does not reside in the cache anymore and now you want to have the fastest sorting possible. Then yes, otherwise I would say that usually you typically are sorting data that is already in cache because you previously filled the array or list with it, or processed it followed by the sort operation. Some additional read on that "clear the LLC for some benchmark" topic: https://stackoverflow.com/a/49077734/587106
×