[fpc-devel] Question about generics / what is checked, and what not -- and why?
Martin Frb
lazarus at mfriebe.de
Sun Oct 19 17:27:50 CEST 2025
Just out of curiosity....
I understand when the generic is parsed, the compiler makes checks that
it compiles. So certain things must be known.
Some things the compiler happily assumes to be ok.
Given an non-constrained param, then (in code) any member is assumed to
be ok.
But in declarations, members of the param can only be used if the
compiler knows them.
generic TGenA<T1,T2> = class
X: T1;
Y: T2.unknown;
end;
What reason may there be to reject the line for Y?
"X: T1" shows that the compiler can continue with a field of unknown
type (because T1 is not known, until a specialize happens).
"Y" would be exactly as unknown as "X", or wouldn't it?
Also, in code you can do
n := T2.foo.bar;
and this can later be a field or a method, or even a constant....
The reason why I got curious is that, I can imagine (and that may be to
limited) 2 reasons:
- technical => the compiler can't do it (but I don't see how, since
"T2.unknown" is as indeterminable as "T1"
(the compiler just needs to parse the members, as it already does
when it compiles code in the begin...end)
- checking early for errors. Ensuring that the generic can be specialized
I.e. ensuring that "T2" has that field.
The 2nd option (if it is) does however IMHO not ensure anything.
(Ignoring that error can still happen in the begin..end), they can also
still happen in the declaration when being specialized.
E.g. when having
generic TGenA<T2: TMyClass> = class // TMyClass has "public type
unknown = byte;"
Y: T2.unknown;
end;
Then that does guarantee (almost) nothing.
Since TGen can be specialized with any sublclass of TMyClass, any such
subclass may redefine or hide what "unknown" is.
So when specialising, it can still fail. (it only can't be completely
absent, as then the base class will provide).
So what did I miss, what is the gain of that check?
Example
"TX2" will fail, because a field can not be used as type. (the presence
in the base class does not prevent this)
program Project1; {$mode objfpc}
uses Unit1;
type
TClassA1 = class(TClassA)
private type T1 = byte;
end;
TClassA2 = class(TClassA)
T1: integer;
end;
TX1 = specialize TGenA<TClassA1>;
// TX2 = specialize TGenA<TClassA2>;
begin {} end.
unit Unit1; {$mode ObjFPC}
interface
type
TClassA = class
private type T1 = record a: byte; end;
end;
generic TGenA<T_A: TClassA> = class
F1: T_A.T1;
end;
implementation
end.
More information about the fpc-devel
mailing list