Sign in Join
Wiki copytemporary

Generics

한국어 · English · Français · Polski · Русский

Generics are sometimes called parameterized types.

Introduction

FPC has had official support for generics in {$mode ObjFPC} since version 2.2.0, and in {$mode Delphi} since version 2.6.0.

The reason that FPC supports two different dialects is simply that FPC implemented generics several years before Delphi.

It is possible to use units written in {$mode ObjFPC} syntax in other units that use {$mode Delphi}, and vice versa.

The Free Generics Library or FGL is an FPC-native collection of generic containers written in {$mode ObjFPC}.

The rtl-generics package is a larger, somewhat more featureful collection of generic containers written in {$mode Delphi} that tries to be compatible with the Delphi generics library. This package is provided as standard in FPC 3.1.1+, but there is a version for FPC 3.0.4 available as well.

Both FGL and rtl-generics can be used in both syntax modes.

FGL unit

The easiest way to get started with generics is to use the fgl unit, which is a prototype unit for base system generic classes. So far it contains a few basic classes:

Getting started

The following simple example shows how to store multiple instances of a user defined class in a list:

pascal
{$mode objfpc}
uses fgl;

type
   TMyClass = class(TObject)
      fld1 : string;
   end;

   TMyList = specialize TFPGObjectList<TMyClass>;

var
   list : TMyList;
   c : TMyClass;

begin
   // create the list and add an element
   list := TMyList.Create;
   c := TMyClass.Create;
   c.fld1 := 'c1';
   list.Add(c);
   // retrieve an element from the list
   c := list[0];

Custom generic classes

If the generics defined in the fgl unit do not suit your needs, you may need to define your own generic classes from scratch using the underlying language primitives.

A generic class is defined using the keyword generic before the class name and use in class declaration:

pascal
type
  generic TList<T> = class
    Items: array of T;
    procedure Add(Value: T);
  end;

Here's an example of a generic class implementation:

pascal
implementation

procedure TList.Add(Value: T);
begin
  SetLength(Items, Length(Items) + 1);
  Items[Length(Items) - 1] := Value;
end;

A generic class, object, record, interface or method can be simply specialized for a particular type by using the specialize keyword.

pascal
Type  
  TIntegerList = specialize TList<Integer>;
  TPointerList = specialize TList<Pointer>;
  TStringList = specialize TList<string>;

Other points

  1. The compiler parses a generic, but instead of generating code it stores all tokens in a token buffer inside the PPU file.
  2. The compiler parses a specialization; for this it loads the token buffer from the PPU file and parses that again. It replaces the generic parameters (in most examples "T") by the particular given type (e.g. LongInt, TObject). The code basically appears as if the same class had been written as the generic but with T replaced by the given type.

Therefore, in theory, there should be no speed differences between a "normal" class and a generic one.

Example

See also

External links


From the Free Pascal wiki, page "Generics", as it stood on 2024-03-28 after a change by Raskaton, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 1, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.