Overview of Generics
Go Up to Generics Index
Delphi supports the use of generics.
How Generics Work
The terms generics or generic types describe the set of things in a platform that can be parameterized by type. The term generics can refer to either generic types or generic methods, i.e., generic procedures and generic functions.
Generics are a set of abstraction tools that permit the decoupling of an algorithm (such as a procedure or function) or a data structure (such as a class, interface or record) from one or more particular types that the algorithm or data structure uses.
A method or data type that uses other types in its definition can be made more general by substituting one or more particular types with type parameters. Then you add those type parameters to a type parameter list in the method or data structure declaration. This is similar to the way that you can make a procedure more general by substituting instances of a literal constant in its body with a parameter name and adding the parameter to the parameter list of the procedure.
For example, a TMyList class that maintains a list of objects (of the TObject type) can be made more reusable and type-safe by substituting uses of TObject with a type parameter name (such as 'T'), and adding the type parameter to the class's type parameter list so that it becomes TMyList<T>.
Particular uses (instantiations) of a generic type or method can be made by supplying type arguments to the generic type or method at the point of use. The act of supplying type arguments effectively constructs a new type or method by substituting instances of the type parameter in the generic definition with the corresponding type argument.
For example, the list might be used as TMyList<Double>. This creates a new type, TMyList<Double>, whose definition is identical to TMyList<T> except that all instances of 'T' in the definition are replaced with 'Double'.
It should be noted that generics as an abstraction mechanism duplicates much of the functionality of polymorphism, but with different characteristics. Since a new type or method is constructed at instantiation time, you can find type errors sooner, at compile time rather than at run time. This also increases the scope for optimization, but with a trade-off - each instantiation increases the memory usage of the final running application, possibly resulting in lower performance.
For example, TSIPair is a class holding two data types, String and Integer:
type TSIPair = class private FKey: String; FValue: Integer; public function GetKey: String; procedure SetKey(Key: String); function GetValue: Integer; procedure SetValue(Value: Integer); property Key: TKey read GetKey write SetKey; property Value: TValue read GetValue write SetValue; end;
To make a class independent of data type, replace the data type with a type parameter:
type TPair<TKey,TValue>= class // declares TPair type with two type parameters private FKey: TKey; FValue: TValue; public function GetKey: TKey; procedure SetKey(Key: TKey); function GetValue: TValue; procedure SetValue(Value: TValue); property Key: TKey read GetKey write SetKey; property Value: TValue read GetValue write SetValue; end; type TSIPair = TPair<String,Integer>; // declares instantiated type TSSPair = TPair<String,String>; // declares with other data types TISPair = TPair<Integer,String>; TIIPair = TPair<Integer,Integer>; TSXPair = TPair<String,TXMLNode>;
Platform Requirements and Differences
Generics are supported by the Delphi for Win32 compiler.
Runtime type identification
In Win32, generics and methods do not have runtime type identification (RTTI), but instantiated types do have RTTI. An instantiated type is the combination of a generic with a set of parameters.
In Win32, an instantiated interface type does not have an interface GUID.
Parameterized method in interface
A parameterized method (method declared with type parameters) cannot be declared in an interface.
Generic types are instantiated at compile-time and emitted into executables and relocatable files. Instance variables of a generic type are instantiated at runtime for classes and at compile time for generic records.
Dynamic instantiation at runtime is not supported.
The Win32 interface is not a "light" interface. This means all type parameters with interface constraints always support the COM IUnknown methods _AddRef, _Release and QueryInterface or inherit from TInterfacedObject. Record types cannot specify an interface constraint parameter.