Recent

Author Topic: TCollection wiki entry  (Read 1837 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 19499
  • Glad to be alive.
TCollection wiki entry
« on: July 05, 2026, 02:10:44 pm »
I am not quite satisfied with the wiki entry for TCollection since it is partially incorrect.
Especially the generics version seems at odds with how one should/must write a TCollection.
But before I change that entry, please shoot holes in this, but read the comment section carefully, it is not meant for people who can not read:
Code: Pascal  [Select][+][-]
  1. unit gencollection;
  2. {
  3.   This unit implements a generic collection
  4.   including an automatic generic enumerator.
  5.  
  6.   Some remarks:
  7.   Collections derived from TCollection only have an advantage in four ways:
  8.   - They are streamable by default since they inherit from TPersistent
  9.   - Specializations will show up in the object inspector because of that
  10.   - They have built-in change notifications
  11.   - And have full RTTI automatically
  12.  
  13.   Otherwise you would simply use a TList<T> as the underlying structure,
  14.   because that already has:
  15.   - a generic enumerator
  16.   - no need to derive from TCollectionItem
  17.   - It has Sort(IComparer<T>), IndexOf, Contains, BinarySearch, etc.
  18.   - Less internal typecasting necessary.  
  19.  
  20.   This unit is Delphi compatible, but written in FreePascal.
  21.  
  22.   Have fun, Thaddy.
  23. }
  24. {$ifdef fpc}{$mode delphi}{$endif}{$M+}
  25. interface
  26.   uses classes;
  27.  
  28. type
  29.   TGenericCollectionItem<T> = class(TCollectionItem)
  30.   private
  31.     FItem: T;
  32.   public
  33.     property Value: T read FItem write FItem;
  34.   end;
  35.  
  36.  TGenericCollectionEnumerator<T> = class
  37.   private
  38.     FCollection: TCollection;
  39.     FPosition: Integer;
  40.   public
  41.     constructor Create(ACollection: TCollection);// avoids forward
  42.     function GetCurrent: TGenericCollectionItem<T>;
  43.     function MoveNext: Boolean;
  44.     property Current: TGenericCollectionItem<T> read GetCurrent;
  45.   end;
  46.  
  47.   TGenericCollection<T> = class(TCollection)
  48.   protected
  49.     Function GetItem(index:integer):TGenericCollectionItem<T>;
  50.     procedure SetItem(Index:integer;Item:TGenericCollectionItem<T>);
  51.   public
  52.     constructor Create;
  53.     function Add: TGenericCollectionItem<T>;
  54.     property Items[Index:integer]:TGenericCollectionItem<T> read GetItem write SetItem;default;
  55.     function GetEnumerator: TGenericCollectionEnumerator<T>;
  56.   end;
  57.  
  58. implementation
  59.  
  60.   function TGenericCollection<T>.GetItem(Index:integer):TGenericCollectionItem<T>;
  61.   begin
  62.     Result := TGenericCollectionItem<T>(inherited GetItem(index));
  63.   end;
  64.  
  65.   procedure TGenericCollection<T>.SetItem(Index:integer;Item:TGenericCollectionItem<T>);
  66.   begin
  67.     inherited SetItem(Index,Item)
  68.   end;
  69.  
  70.   constructor TGenericCollection<T>.Create;
  71.   begin
  72.     inherited Create(TGenericCollectionItem<T>);
  73.   end;
  74.  
  75.   function TGenericCollection<T>.Add: TGenericCollectionItem<T>;
  76.   begin
  77.     Result := TGenericCollectionItem<T>(inherited Add);
  78.   end;
  79.  
  80.   function TGenericCollection<T>.GetEnumerator:TGenericCollectionEnumerator<T>;
  81.   begin
  82.     Result := TGenericCollectionEnumerator<T>.Create(self);
  83.   end;
  84.  
  85.   constructor TGenericCollectionEnumerator<T>.Create(ACollection: TCollection);
  86.   begin
  87.     inherited Create;
  88.     FCollection := ACollection;
  89.     FPosition := -1;
  90.   end;
  91.  
  92.   function TGenericCollectionEnumerator<T>.GetCurrent: TGenericCollectionItem<T>;
  93.   begin
  94.     Result := TGenericCollectionItem<T>(FCollection.Items[FPosition])
  95.   end;
  96.  
  97.   function TGenericCollectionEnumerator<T>.MoveNext: Boolean;
  98.   begin
  99.     Inc(FPosition);
  100.     Result := FPosition < FCollection.Count;
  101.   end;
  102.  
  103. end.

Example code:
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$endif}
  2. uses
  3.   Classes, GenCollection;
  4.  
  5. type
  6.   // define a custom collection item and a custom collection
  7.   TStringItem = TGenericCollectionItem<string>;
  8.   TStringCollection = TGenericCollection<string>;
  9.  
  10. var
  11.   StringCollection: TStringCollection;
  12.   Item:TStringItem ;
  13. begin
  14.   StringCollection := TStringCollection.Create;
  15.   try
  16.     StringCollection.Add.Value := 'First Item';
  17.     StringCollection.Add.Value := 'Second Item';
  18.     for Item in StringCollection do  // automatic support for for in do
  19.       writeln(Item.Value:10,Item.Id:4);
  20.   finally
  21.     StringCollection.Free;
  22.   end;
  23.   readln;
  24. end.

 
« Last Edit: July 06, 2026, 06:56:58 am by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

Thaddy

  • Hero Member
  • *****
  • Posts: 19499
  • Glad to be alive.
Re: TCollection wiki entry
« Reply #1 on: July 05, 2026, 09:10:46 pm »
If nobody complains I will replace the generics part of the wiki entry, but I will add the streaming.
That seems the best way.
« Last Edit: July 07, 2026, 03:55:05 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

mas steindorff

  • Hero Member
  • *****
  • Posts: 603
Re: TCollection wiki entry
« Reply #2 on: July 06, 2026, 08:30:22 pm »
one of the things that I was looking when I started looking at built in list managers was a comparisons between
  • Tcollection
  • Tlist
  • TFPlist
  • Tlist
  • TObjectList
  • TFPGObjectList
  • ...
And a simple summery on how they differ, target use, minimum code (create,free..), how each can be customize...
Mas

[/list]
windows 10 &11, Ubuntu 21+ IDE 3.4 general releases

jamie

  • Hero Member
  • *****
  • Posts: 7857
Re: TCollection wiki entry
« Reply #3 on: July 06, 2026, 09:04:47 pm »
minus the collection-generic, I've got a rather large app built using those Gens and so far, they have worked as advertised without causing some unknown compiler error.

 Now using the Generics.Collections is a different story, that bombs the compiler if I tried to build anything thing significant with it, I get things like errors that the compiler can't find Label addresses in the code etc.


Jamie


The only true wisdom is knowing you know nothing

dbannon

  • Hero Member
  • *****
  • Posts: 3858
    • tomboy-ng, a rewrite of the classic Tomboy
Re: TCollection wiki entry
« Reply #4 on: July 07, 2026, 05:01:11 am »
Thaddy, I take it you are not thinking of removing the non-generics section ?

Although, I have to add that I have, on several occasions, read that page, shook my head sadly and went back to using a FPList. A some what more practical example in both case would be good !

Davo
Lazarus 4, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Thaddy

  • Hero Member
  • *****
  • Posts: 19499
  • Glad to be alive.
Re: TCollection wiki entry
« Reply #5 on: July 07, 2026, 07:46:37 am »
@dbannon

No of course not. The non-generic part stays. Practical example: of course, added three examples, the latter based on the old entry, but expanded.. The second example also shows how to use the generic collection Component.
The third example shows how to interact between multiple collections: a poor man's database.
https://wiki.freepascal.org/index.php?title=TCollection#Generics
The gencollection unit is now fully generic, not a hybrid and only uses standard units: no need to derive from TCollectionItem, no strange libraries. Works from 3.2.2 +

I will add a fourth example showing the change notification features of TCollection later, because that feature is also missing in the non-generic part. I will probably move the component to the gencollection unit.
« Last Edit: July 07, 2026, 11:26:37 am by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

Zvoni

  • Hero Member
  • *****
  • Posts: 3444
Re: TCollection wiki entry
« Reply #6 on: July 07, 2026, 10:50:03 am »
my 2 cents:
The only thing i dislike is that the Getter for Property Current in the Enumerator is Public instead of Protected

All said: No verdict from me, since i've never had to use something like this.
OTOH, i trust Thaddy to come up with precise code and reasoning (most times  :P except when it's about Databases  ;))
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Thaddy

  • Hero Member
  • *****
  • Posts: 19499
  • Glad to be alive.
Re: TCollection wiki entry
« Reply #7 on: July 07, 2026, 11:31:23 am »
Well, now it is protected.
Change:
Code: Pascal  [Select][+][-]
  1.  TGenericCollectionEnumerator<T> = class
  2.   private
  3.     FCollection: TCollection;
  4.     FPosition: Integer;
  5.   protected
  6.     function GetCurrent: TGenericCollectionItem<T>;virtual;
  7.   public
  8.     constructor Create(ACollection: TCollection);// avoids forward
  9.     function MoveNext: Boolean;
  10.     property Current: TGenericCollectionItem<T> read GetCurrent;
  11.   end;

I also moved the component to the gencollection unit.
« Last Edit: July 07, 2026, 11:37:43 am by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

dbannon

  • Hero Member
  • *****
  • Posts: 3858
    • tomboy-ng, a rewrite of the classic Tomboy
Re: TCollection wiki entry
« Reply #8 on: July 07, 2026, 11:53:41 am »
Yep, nice clear examples Thaddy.  I read, and to some extent, understood them. But, honestly, I'll still use FPList !

Davo
Lazarus 4, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Thaddy

  • Hero Member
  • *****
  • Posts: 19499
  • Glad to be alive.
Re: TCollection wiki entry
« Reply #9 on: July 07, 2026, 12:24:41 pm »
Thanks.

Added the observer for the change notifications as demo 4:
Code: Pascal  [Select][+][-]
  1. program ObserveCollection;
  2. {$mode delphi}
  3. uses gencollection, classes;
  4.  
  5. type
  6.   TGenericCollectionObserver<T> = class(TInterfacedObject, IFPObserver)
  7.   public
  8.     procedure FPOObservedChanged(ASender: TObject;
  9.       Operation: TFPObservedOperation;
  10.       Data: Pointer
  11.     );
  12.   end;
  13.   // define a custom collection item and a custom collection
  14.   TStringItem = TGenericCollectionItem<string>;
  15.   TStringCollection = TGenericCollection<string>;
  16.   TStringCollectionObserver = TGenericCollectionObserver<string>;
  17.  
  18. procedure TGenericCollectionObserver<T>.FPOObservedChanged(
  19.   ASender: TObject;Operation: TFPObservedOperation;Data: Pointer);
  20. var
  21.   Item: TCollectionItem;
  22. begin
  23.   Item := TCollectionItem(Data);
  24.   case Operation of
  25.     ooAddItem:Writeln('Item ',Item.ID,' added to the collection');
  26.     ooDeleteItem:Writeln('Item ',Item.ID,' deleted from the collection');
  27.     ooChange:
  28.       begin
  29.         if Assigned(Item) then
  30.           Writeln('collection changed: item #', Item.Index,
  31.                   ' = ', Item.DisplayName)
  32.         else
  33.           Writeln('collection changed');
  34.       end;
  35.     ooFree:Writeln('observed collection is being freed');      
  36.   else
  37.     Writeln(Operation);
  38.   end;
  39. end;
  40.  
  41. var
  42.   StringCollection: TStringCollection;
  43.   Item:TStringItem ;
  44.   Observer:TStringCollectionObserver;
  45.  
  46. begin
  47.   Observer := TStringCollectionObserver.Create;
  48.   StringCollection := TStringCollection.Create;
  49.   try
  50.     StringCollection.FPOAttachObserver(Observer);
  51.     StringCollection.Add.Value := 'First Item';
  52.     StringCollection.Add.Value := 'Second Item';
  53.     for Item in StringCollection do  // automatic support for for in do
  54.       with Item do writeln(Value:10,Id:4);
  55.     StringCollection.Delete(1);
  56.     for Item in StringCollection do  // automatic support for for in do
  57.       with Item do writeln(Value:10,Id:4);
  58.   finally
  59.     StringCollection.Free;
  60.     Observer.Free;
  61.   end;
  62.   readln;
  63. end.

This is also relevant for non-generic use of TCollection.
« Last Edit: July 07, 2026, 03:59:44 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

cdbc

  • Hero Member
  • *****
  • Posts: 2875
    • http://www.cdbc.dk
Re: TCollection wiki entry
« Reply #10 on: July 07, 2026, 01:45:07 pm »
Hi Thaddy
I'll join @dbannon: +1
I especially like that you're giving the FPOObserve(d/r) some well deserved love, that has been neglegted for a while now =^
Good on you mate  8)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

Thaddy

  • Hero Member
  • *****
  • Posts: 19499
  • Glad to be alive.
Re: TCollection wiki entry
« Reply #11 on: July 07, 2026, 03:58:26 pm »
I especially like that you're giving the FPOObserve(d/r) some well deserved love, that has been neglegted for a while now =^
Thanks Benny, it is well documented, but almost everybody either forgets or does not understand that feature.
And it is so simple.. 8-)
Any "programmer" that knows only one programming language is not a programmer

cdbc

  • Hero Member
  • *****
  • Posts: 2875
    • http://www.cdbc.dk
Re: TCollection wiki entry
« Reply #12 on: July 07, 2026, 04:06:38 pm »
Hi
Yeah, I find it a small stroke of genius from Sarah/Sven, stuffing it in there, so __every__ LCL-app has built-in Observer-pattern =^
But it is as you say, most people forget, don't know, don't know how or component-writers simply forget to utilize them... A bit sad really, 'cause they're so simple and easy to use  8-)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

Thaddy

  • Hero Member
  • *****
  • Posts: 19499
  • Glad to be alive.
Re: TCollection wiki entry
« Reply #13 on: July 07, 2026, 04:36:33 pm »
The wiki entry code has now been processed to reflect all comments thus far, so is now leading.
Use the code from the wiki, not the initial code posted here.

You can still shoot holes in it...... ;D

https://wiki.freepascal.org/TCollection#Generics
« Last Edit: July 07, 2026, 05:01:09 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

paweld

  • Hero Member
  • *****
  • Posts: 1685
Re: TCollection wiki entry
« Reply #14 on: July 08, 2026, 06:15:24 am »
In my opinion, the previous version was easier to understand and perfectly sufficient. I don't see the point of introducing an intermediate class TGenericCollectionItem (unless you’re using records, but then you should explain that) or using the delphi mode instead of objfpc. The enumerator and observer are definitely a plus.

Thank you also for your post, because it sparked my interest in a generic approach to TCollection and helped me stop duplicating the same methods when defining each collection.
Best regards / Pozdrawiam
paweld

 

TinyPortal © 2005-2018