I'd like to declare a type like this:
type
TDynMatrix<T> = TArray<TArray<T>>;
The compiler rejects this with:
[dcc32 Error] E2508 Type parameters not allowed on this type
I wondered whether the issue was related to the nesting of generics. But it seems not:
type
TDynArray<T> = TArray<T>;//pointless type I know, but for the sake of the Q
also results in the same compiler error.
The documentation for the compiler error left me knowing perhaps even less than I knew before I read it:
E2508 type parameters not allowed on this type (Delphi)
When using class references, you cannot use generic classes directly. You need to use a wrapper class to be able to use generics.
program E2508; {$APPTYPE CONSOLE} uses SysUtils; type TMyClass = class end; TMyClassClass<T> = class of TMyClass; begin Writeln('FAIL - E2508 type parameters not allowed on this type'); end.
Can anyone explain why I cannot declare generic types in this way?
Your code is invalid because you cannot re-declare a generic type as open generic type.
I would declare this as:
type
TDynMatrix<T> = array of TArray<T>;
This way you still have compatibility that you probably need: the elements of one dimension to a TArray<T>
.
So then you can write
var
matrix: TDynMatrix<Integer>;
values: TArray<Integer>;
....
SetLength(matrix, 2, 2);
values := matrix[0];
values := Copy(matrix[1]);
etc.
Sorry no reasons, but this one is not limited to TArray,
Using the following type definitions:
TGenClass<T> = class fx: T; end;
TGenArray<T> = array of T;
TGenRecord<T> = record fx: T; end;
TGenProc<T> = procedure(const A: T);
I have tried all combinations:
TGenClassClass<T> = TGenClass<TGenClass<T>>;
TGenClassArray<T> = TGenClass<TGenArray<T>>;
TGenClassRecord<T> = TGenClass<TGenClass<T>>;
TGenClassProc<T> = TGenClass<TGenClass<T>>;
TGenArrayClass<T> = TGenArray<TGenClass<T>>;
TGenArrayArray<T> = TGenArray<TGenArray<T>>;
TGenArrayRecord<T> = TGenArray<TGenClass<T>>;
TGenArrayProc<T> = TGenArray<TGenClass<T>>;
TGenRecordClass<T> = TGenRecord<TGenClass<T>>;
TGenRecordArray<T> = TGenRecord<TGenArray<T>>;
TGenRecordRecord<T> = TGenRecord<TGenClass<T>>;
TGenRecordProc<T> = TGenRecord<TGenClass<T>>;
TGenProcClass<T> = TGenProc<TGenClass<T>>;
TGenProcArray<T> = TGenProc<TGenArray<T>>;
TGenProcRecord<T> = TGenProc<TGenClass<T>>;
TGenProcProc<T> = TGenClass<TGenProc<T>>;
They all fail.
You can declare types with complex type expressions, if those types are not generic themself:
TClassClass = TGenClass<TGenClass<Integer>>;
TClassArray = TGenClass<TGenArray<Integer>>;
TClassRecord = TGenClass<TGenClass<Integer>>;
TClassProc = TGenClass<TGenClass<Integer>>;
TArrayClass = TGenArray<TGenClass<Integer>>;
TArrayArray = TGenArray<TGenArray<Integer>>;
TArrayRecord = TGenArray<TGenClass<Integer>>;
TArrayProc = TGenArray<TGenClass<Integer>>;
TRecordClass = TGenRecord<TGenClass<Integer>>;
TRecordArray = TGenRecord<TGenArray<Integer>>;
TRecordRecord = TGenRecord<TGenClass<Integer>>;
TRecordProc = TGenRecord<TGenClass<Integer>>;
TProcClass = TGenProc<TGenClass<Integer>>;
TProcArray = TGenProc<TGenArray<Integer>>;
TProcRecord = TGenProc<TGenClass<Integer>>;
TProcProc = TGenClass<TGenProc<Integer>>;
There is a circumvention. You can declare the type within a class with a type parameter.
type
TTheClass<T> = class
type
TGenClassClass = TGenClass<TGenClass<T>>;
end;
So you can use TTheClass<T>.TGenClassClass
as a type.
FWIW, inspired by the various comments and answers, this is the code that I believe is the most effective:
type
TDynMatrix<T> = array of TArray<T>;
TDynMatrix = class
public
class function New<T>(const Source: array of TArray<T>): TDynMatrix<T>; static;
end;
class function TDynMatrix.New<T>(const Source: array of TArray<T>): TDynMatrix<T>;
var
i: Integer;
begin
SetLength(Result, Length(Source));
for i := 0 to high(Result) do begin
Result[i] := Copy(Source[i]);
end;
end;
This allows be to declared variables like this:
var
RealM: TDynMatrix<Real>;
ComplexM: TDynMatrix<TComplex>;
And make new instances like this:
RealM := TDynMatrix.New<Real>([TArray<Real>.Create(...)]);
ComplexM := TDynMatrix.New<TComplex>([TArray<TComplex>.Create(...)]);
Now, if only the compiler's generic inference capabilities were a little better.
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