Difference between revisions of "Generics"
m |
(from Howto Use Interfaces) |
||
Line 69: | Line 69: | ||
== Other Points == | == 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. | 1. The compiler parses a generic, but instead of generating code it stores all tokens in a token buffer inside the PPU file. | ||
Line 76: | Line 75: | ||
Therefore in theory there should be no speed differences between a "normal" class and a generic one. | Therefore in theory there should be no speed differences between a "normal" class and a generic one. | ||
+ | |||
+ | == 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. | ||
+ | |||
+ | |||
+ | <syntaxhighlight> | ||
+ | program UseGenerics; | ||
+ | |||
+ | {$mode objfpc}{$H+} | ||
+ | |||
+ | 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 | ||
+ | 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 | ||
+ | //using the generated generics function | ||
+ | writeln('Integer GMax:', TFakeClassInt.gmax(23,56)); | ||
+ | writeln('Double GMax:', TFakeClassDouble.gmax(23.89,56.5)); | ||
+ | readln; | ||
+ | end. | ||
+ | </syntaxhighlight> | ||
==See also== | ==See also== | ||
− | |||
* [[Templates]] | * [[Templates]] | ||
* [[Generics proposals]] | * [[Generics proposals]] | ||
Line 84: | Line 119: | ||
==External links== | ==External links== | ||
− | |||
* [http://www.freepascal.org/docs-html/ref/refch8.html Free Pascal: Reference guide - Generics] | * [http://www.freepascal.org/docs-html/ref/refch8.html Free Pascal: Reference guide - Generics] | ||
− |
Revision as of 14:53, 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
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.
program UseGenerics;
{$mode objfpc}{$H+}
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
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
//using the generated generics function
writeln('Integer GMax:', TFakeClassInt.gmax(23,56));
writeln('Double GMax:', TFakeClassDouble.gmax(23.89,56.5));
readln;
end.