A generic class definition is much like a class definition, with the exception that it contains a list of
placeholders for types, and can contain a series of local variable blocks or local type blocks, as can
be seen in the following syntax diagram:
The generic class declaration should be followed by a class implementation. It is the same as a
normal class implementation with a single exception, namely that any identifier with the same
name as one of the template identifiers must be a type identifier.
The generic class declaration is much like a normal class declaration, except for the local variable
and local type block. The local type block defines types that are type placeholders: they are not
actualized until the class is specialized.
The local variable block is just an alternate syntax for ordinary class fields. The reason for
introducing is the introduction of the Type block: just as in a unit or function declaration, a class
declaration can now have a local type and variable block definition.
The following is a valid generic class definition:
Type
generic TList<_T>=class(TObject)
type public
TCompareFunc = function(const Item1, Item2: _T): Integer;
var public
data : _T;
procedure Add(item: _T);
procedure Sort(compare: TCompareFunc);
end;
This class could be followed by an implementation as follows:
procedure TList.Add(item: _T);
begin
data:=item;
end;
procedure TList.Sort(compare: TCompareFunc);
begin
if compare(data, 20) <= 0 then
halt(1);
end;
There are some noteworthy things about this declaration and implementation:
- There is a single placeholder _T. It will be substituted by a type identifier when the generic
class is specialized. The identifier _T may not be used for anything else than a placehoder.
This means that the following would be invalid:
procedure TList.Sort(compare: TCompareFunc);
Var
_t : integer;
begin
// do something.
end;
- The local type block contains a single type TCompareFunc. Note that the actual type is not
yet known inside the generic class definition: the definition contains a reference to the
placeholder _T. All other identifier references must be known when the generic class is
defined, not when the generic class is specialized.
- The local variable block is equivalent to the following:
generic TList<_T>=class(TObject)
type public
TCompareFunc = function(const Item1, Item2: _T): Integer;
Public
data : _T;
procedure Add(item: _T);
procedure Sort(compare: TCompareFunc);
end;
- Both the local variable block and local type block have a visibility specifier. This is optional;
if it is omitted, the current visibility is used.