I would like to define a class type (type alias) for a generic class. I would like to do this so users of unit b can have access to TMyType without using unit a. I have units like this:
unit a;
interface
type
TMyNormalObject = class
FData: Integer;
end;
TMyType<T> = class
FData: <T>;
end;
implementation
end.
unit b;
interface
type
TMyNormalObject = a.TMyNormalObject; // works
TMyType<T> = a.TMyType<T>; // E2508 type parameters not allowed on this type
implementation
end.
I already found a possible workaround which I don't like because it can introduce hard to find bugs:
TMyType<T> = class(a.TMyType<T>);
The problem with this approach is that it introduces a new class type and an a.TMyType instance is not a b.TMyType (while a.TMyNormallClass is a b.TMyNormalClass and vice versa - they are referring to the same class).
To use Java generics effectively, you must consider the following restrictions: Cannot Instantiate Generic Types with Primitive Types. Cannot Create Instances of Type Parameters. Cannot Declare Static Fields Whose Types are Type Parameters.
It's currently not possible to declare a class type for a generic class.
See QC76605 for more information. Also the update below.
Example :
TMyClass<T> = class
end;
TMyClassClass<T> = class of TMyClass<T>; //E2508 type parameters not allowed on this type
The workaround that is presented looks like this :
TMyIntClass = TMyType<Integer>;
TMyIntClassClass = Class of TMyIntClass;
But as commented, that would defeat the whole idea of generics, since the class would have to be subclassed for every generic instantiation.
Here is also a link to a similar workaround on generating a specialized subclass of a generic type: derive-from-specialized-generic-types. In this case it would look like this :
TMySpecialClass = Class(TMyType<Integer>);
Update :
The workaround proposed by RM:
TMyType<T> = class(a.TMyType<T>);
can be implemented with type safety using following scheme:
unit Unita;
interface
type
TMyType<T> = class
Constructor Create;
end;
implementation
uses
Unitb;
constructor TMyType<T>.Create;
begin
Inherited Create;
//WriteLn( Self.QualifiedClassName,' ',Unitb.TMyType<T>.QualifiedClassName);
Assert(Self.QualifiedClassName = Unitb.TMyType<T>.QualifiedClassName);
end;
end.
unit Unitb;
interface
uses Unita;
type
TMyType<T> = class(Unita.TMyType<T>);
implementation
end.
Project Test;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Unita in 'Unita.pas',
Unitb in 'Unitb.pas';
var
t1 : Unita.TMyType<Integer>;
t2 : Unitb.TMyType<Integer>;
t3 : TMyType<Integer>;
begin
try
//t1 := Unita.TMyType<Integer>.Create; //Exception EAssertionFailed !!
t2 := Unitb.TMyType<Integer>.Create;
t3 := TMyType<Integer>.Create;
ReadLn;
finally
//t1.Free;
t2.Free;
t3.Free;
end;
end.
When creating the generic class, a test is made to check that the created class is derived from the type declared in unit b. Thereby all attempts to create this class from unit a is detected.
Update 2:
Just to be clear, a reference to a generic class, "class of type<T>
" is not possible, but a copy of a generic class is fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With