[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