Difference between revisions of "Generics"

From Free Pascal wiki
Jump to navigationJump to search
(from Howto Use Interfaces)
Line 77: Line 77:
  
 
== Example ==
 
== Example ==
Copy the text below and it will demonstrate how to use interfaces to write less code, avoid code repetition,..., this is a fully working program.
+
An example of how to use generics to write a function gmax() that takes the maximum of two not-yet-typed variables.
 
+
As a bonus they are namespaced by the classname. A disadvantage may be that generocs can't be overloaded./
  
 
<syntaxhighlight>
 
<syntaxhighlight>
Line 86: Line 86:
  
 
type
 
type
    //An example of how to use generics to write
 
    //general use like procedures
 
    //as a bonus they are namespaced by the classname
 
    //disadvantage: can't be overloaded
 
 
   generic TFakeClass<_GT> = class
 
   generic TFakeClass<_GT> = class
 
     class function gmax(a,b: _GT):_GT;
 
     class function gmax(a,b: _GT):_GT;
Line 106: Line 102:
  
 
begin
 
begin
     //using the generated generics function
+
     // show max of two integers
   writeln('Integer GMax:', TFakeClassInt.gmax(23,56));
+
   writeln( 'Integer GMax:', TFakeClassInt.gmax( 23, 56 ) );
   writeln('Double GMax:', TFakeClassDouble.gmax(23.89,56.5));
+
    // show max of two doubles
   readln;
+
   writeln( 'Double GMax:', TFakeClassDouble.gmax( 23.89, 56.5) );
 +
   readln();
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>

Revision as of 14:58, 22 March 2017

English (en) français (fr) 한국어 (ko) polski (pl) русский (ru)

Introduction

The Free Generics Library or FGL is a native implementation of class templates. Generics are sometimes called parametrized types. FPC has had official support for generics since version 2.2.

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:

  • TFPGList
  • TFPGObjectList
  • TFPGInterfacedObjectList
  • TFPGMap

Getting Started

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

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:

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

Example of generic class implementation:

implementation

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

A generic class can be simply specialized for a particular type by using the specialize keyword.

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

An example of how to use generics to write a function gmax() that takes the maximum of two not-yet-typed variables. As a bonus they are namespaced by the classname. A disadvantage may be that generocs can't be overloaded./

program UseGenerics;

{$mode objfpc}{$H+}

type
  generic TFakeClass<_GT> = class
    class function gmax(a,b: _GT):_GT;
  end;

  TFakeClassInt = specialize TFakeClass<integer>;
  TFakeClassDouble = specialize TFakeClass<double>;

  class function TFakeClass.gmax(a,b: _GT):_GT;
  begin
    if a > b then 
      result := a
    else 
      result := b;
  end;

begin
    // show max of two integers
  writeln( 'Integer GMax:', TFakeClassInt.gmax( 23, 56 ) );
    // show max of two doubles
  writeln( 'Double GMax:', TFakeClassDouble.gmax( 23.89, 56.5) );
  readln();
end.

See also

External links