It should be stressed that all identifiers other than the template placeholders should be known when the generic class is declared. This works in 2 ways. First, all types must be known, that is, a type identifier with the same name must exist. The following unit will produce an error:
unit myunit;
interface type Generic TMyClass<T> = Class(TObject) Procedure DoSomething(A : T; B : TSomeType); end; Type TSomeType = Integer; TSomeTypeClass = specialize TMyClass<TSomeType>; Implementation Procedure TMyClass.DoSomething(A : T; B : TSomeType); begin // Some code. end; end. |
The above code will result in an error, because the type TSomeType is not known when the declaration is parsed:
home: >fpc myunit.pp
myunit.pp(8,47) Error: Identifier not found "TSomeType" myunit.pp(11,1) Fatal: There were 1 errors compiling module, stopping |
The second way in which this is visible, is the following. Assume a unit
unit mya;
interface type Generic TMyClass<T> = Class(TObject) Procedure DoSomething(A : T); end; Implementation Procedure DoLocalThings; begin Writeln(’mya.DoLocalThings’); end; Procedure TMyClass.DoSomething(A : T); begin DoLocalThings; end; end. |
and a program
program myb;
uses mya; procedure DoLocalThings; begin Writeln(’myb.DoLocalThings’); end; Type TB = specialize TMyClass<Integer>; Var B : TB; begin B:=TB.Create; B.DoSomething(1); end. |
Despite the fact that generics act as a macro which is replayed at specialization time, the reference to DoLocalThings is resolved when TMyClass is defined, not when TB is defined. This means that the output of the program is:
home: >fpc -S2 myb.pp
home: >myb mya.DoLocalThings |
This is dictated by safety and necessity: