Overview of Generics

From RAD Studio
Jump to: navigation, search

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.

Code Examples

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 compilers.

Run-time type identification

In Win32, generics and methods do not have run-time type information (RTTI), but instantiated types do have RTTI. An instantiated type is the combination of a generic with a set of parameters. The RTTI for methods of a class is a subset of the RTTI for that class as a whole. If a non-generic class has a generic method, that method will not be included in the RTTI generated for the class because generics are instantiated at compile time, not at run time.

Interface GUID

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.

Instantiation timing

Generic types are instantiated at compile time and emitted into executables and relocatable files. Instance variables of a generic type are instantiated at run time for classes and at compile time for generic records. The RTTI for generic classes is only generated when the classes are instantiated. RTTI for instantiated classes follows just as for non-generic classes. If the generic class has a generic method, then the instantiated generic class will not have RTTI for that generic method.

Dynamic instantiation

Dynamic instantiation at run time is not supported.

Interface constraints

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.

See Also