Step 1 of 5 · Reading · ~2 min
Learn
Object Pascal Classes
Generics and Containers
A container that stores Pointer and hands you back Pointer forces a cast at every use site, and
a wrong cast is a crash rather than a compile error. Generics move that check to compile time: you
name the element type once, and the compiler refuses every mismatched Add and every mismatched
read.
The container you have on this grader
FreePascal ships two generic container libraries, and which one you get depends on the compiler
version. Generics.Collections (TList<T>, TDictionary<K,V>) arrived in FPC 3.2. The grader
behind this course runs FPC 3.0.4, where that unit does not exist at all — uses Generics.Collections fails with Fatal: Can't find unit Generics.Collections. What 3.0.4 does
have is fgl, the Free Generic Library:
program demo;
{$mode objfpc}{$H+}
uses fgl;
type
TIntList = specialize TFPGList<integer>;
var
list: TIntList;
begin
list := TIntList.Create;
try
list.Add(10);
list.Add(20);
WriteLn(list[1]); // 20
WriteLn(list.Count); // 2
finally
list.Free;
end;
end.
The specialize keyword is the trap
In {$mode objfpc} you cannot write TFPGList<integer> directly the way Delphi or C# lets you.
Object Pascal spells the instantiation out: specialize at the use site, generic at the
declaration site.
type
TIntList = specialize TFPGList<integer>; { correct in objfpc mode }
TBadList = TFPGList<integer>; { Error: generic type without specialization }
generic TBox<T> = class { declaring your own }
private
FValue: T;
public
property Value: T read FValue write FValue;
end;
TIntBox = specialize TBox<integer>;
Giving the specialization a named type (TIntList) rather than repeating it inline is the usual
style, and it is what keeps the rest of the program readable.
What fgl gives you
TFPGList<T>— a growable array:Add,Count,[i],Delete,IndexOf,Sort.TFPGObjectList<T>— the same, but it frees the objects it holds when it is freed.TFPGMap<K, V>— a sorted key/value map:Add,KeyData[k],IndexOf.
A TFPGList is enumerable, so for x in list do is the idiomatic read loop — you do not need the
index unless you actually want it:
total := 0;
for x in list do
total := total + x;
Memory still belongs to you
Generics change the type system, not the memory model. TIntList.Create allocates, and you free it
in a finally exactly as with any other class. A TFPGList of objects frees the list, not the
objects in it — that is what TFPGObjectList is for, and confusing the two is the standard leak in
Pascal code that has just discovered containers.
Generics here are monomorphized: each specialize compiles its own copy of the code, the way C++
templates do. That is why the type checking is complete and why nothing is boxed.
Your exercise
Build a specialize TFPGList<integer>, fill it from stdin, and sum it with for x in list do. The
mistake the compiler catches first is dropping specialize: TFPGList<integer> on its own is a
syntax error in objfpc mode, not a subtle bug.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…