100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Generics in Free Pascal

Understand how Free Pascal's generic types and routines let you write reusable, type-safe containers and algorithms with `generic` and `specialize`.

Practical PascalAdvanced10 min readJul 10, 2026
Analogies

Declaring Generic Types and Routines

Free Pascal supports generics using the generic keyword on the declaration and specialize at the point of use, in addition to Delphi-compatible syntax with angle brackets when {$mode delphi} is active. A generic type such as generic TStack<T> = class declares a placeholder type parameter T that stands in for any concrete type; the compiler generates a distinct specialized version — specialize TStack<Integer> versus specialize TStack<string> — the first time each unique type argument is used, a process called monomorphization. This gives you compile-time type safety with no runtime casting or boxing, unlike a container built around TObject or Variant.

🏏

Cricket analogy: A generic TStack<T> is like a standardized nets-practice drill template that can be run with any equipment — 'specialize' it with a cricket ball for pace practice or a tennis ball for reflex drills, and the coach gets a purpose-built session without rewriting the drill structure each time.

Constraints and Generic Containers

Free Pascal lets you constrain a type parameter to a class hierarchy or interface, written as generic TRepository<T: TObject> = class, which restricts T to TObject descendants and allows the compiler to safely call TObject methods like Free on values of type T. The RTL's Generics.Collections unit ships ready-made specializations such as specialize TList<T>, specialize TDictionary<TKey, TValue>, and specialize TObjectList<T>, mirroring .NET-style generic collections; TObjectList<T> additionally owns its elements and frees them automatically when the list is cleared or destroyed, provided OwnsObjects is true. Generic routines (standalone functions, not just types) are also supported, letting you write a single generic function Max<T>(A, B: T): T that works across any ordinal or comparable type without duplicating code for each type.

🏏

Cricket analogy: A type constraint 'T: TObject' is like a franchise rule that any overseas player (T) must at minimum be board-certified (a TObject descendant) before selection, letting the team management safely apply standard contract clauses (Free) to any player who qualifies.

Limitations and Practical Use

Free Pascal's generics have real limitations compared to C++ templates: operator constraints are limited, generic type inference for routines is weaker (you often must specify the type explicitly, e.g. specialize Max<Integer>(3, 5)), and generics cannot be combined with certain older RTTI features without extra {$modeswitch} directives. In practice, the most common use is via Generics.Collections for TList<T> and TDictionary<TKey, TValue> rather than authoring your own generic classes, since hand-rolled generics can trigger obscure compiler errors around forward-declared specializations and circular unit dependencies that are easy to hit but hard to diagnose for newcomers.

🏏

Cricket analogy: Weaker type inference is like a franchise not automatically knowing whether a trialist bats left or right-handed — you must explicitly state 'left-handed opener' (specify the type) rather than the selectors inferring it from a single net session.

pascal
uses
  Generics.Collections;

type
  generic TStack<T> = class
  private
    FItems: array of T;
  public
    procedure Push(const AValue: T);
    function Pop: T;
    function IsEmpty: Boolean;
  end;

procedure TStack.Push(const AValue: T);
begin
  SetLength(FItems, Length(FItems) + 1);
  FItems[High(FItems)] := AValue;
end;

function TStack.Pop: T;
begin
  Result := FItems[High(FItems)];
  SetLength(FItems, Length(FItems) - 1);
end;

function TStack.IsEmpty: Boolean;
begin
  Result := Length(FItems) = 0;
end;

var
  IntStack: specialize TStack<Integer>;
  Names: specialize TList<string>;
begin
  IntStack := specialize TStack<Integer>.Create;
  IntStack.Push(42);

  Names := specialize TList<string>.Create;
  Names.Add('Wirth');
  Names.Add('Kay');
end.

In {$mode delphi} or {$mode objfpc} with the appropriate modeswitch, you can often omit the specialize keyword and write TStack<Integer> directly, matching Delphi syntax. Free Pascal's classic {$mode fpc} requires the explicit specialize keyword everywhere a specialization is used.

  • Declare generics with generic and instantiate them with specialize, or use Delphi-style angle brackets under the right mode.
  • The compiler monomorphizes each unique type argument into its own concrete specialized type at compile time.
  • Type constraints like T: TObject restrict what T can be and unlock safe calls to base-class methods.
  • Generics.Collections provides ready-made TList<T>, TDictionary<TKey, TValue>, and TObjectList<T>.
  • TObjectList<T> with OwnsObjects := True automatically frees its elements on clear/destroy.
  • Generic routines exist too, but type inference is weaker than in some languages, often requiring explicit type arguments.
  • Prefer the RTL's built-in generic collections over hand-rolled generics to avoid obscure compiler errors.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#PascalStudyNotes#GenericsInFreePascal#Generics#Free#Pascal#Declaring#StudyNotes#SkillVeris#ExamPrep