Recent

Author Topic: Specialized generic type of specialized generic types?  (Read 1202 times)

bolsen

  • New Member
  • *
  • Posts: 11
Specialized generic type of specialized generic types?
« on: September 13, 2025, 04:25:10 pm »
Hello,

I tried to find if this was brought up here and in the docs, but cannot find anything.

I tried to make a generic of generics type:

Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   generic SomeT<T> = class
  4.     ffield: T;
  5.   end;
  6.  
  7.   generic TLotsOfTs<T> = specialize TObjectList<specialize SomeT<T>>;
  8.  

On 3.3.1, I get these errors:

test_issue.pas(15,66) Error: Identifier not found "T"
test_issue.pas(15,67) Error: Type identifier expected
test_issue.pas(15,68) Error: Type identifier expected
test_issue.pas(15,69) Error: Error in type definition

I suppose thus that you really can't have a generic that specializes on another generic class. But maybe I am missing something? I presume I would just have to rethink what I am doing instead, I suppose.

LV

  • Sr. Member
  • ****
  • Posts: 359
Re: Specialized generic type of specialized generic types?
« Reply #1 on: September 13, 2025, 04:47:32 pm »
You need to introduce an intermediate type where you specialize the internal generic separately. Try it

Code: Pascal  [Select][+][-]
  1. type
  2.   generic SomeTRef<T> = specialize SomeT<T>;
  3.   generic TLotsOfTs<T> = specialize TObjectList<SomeTRef<T>>;
  4.  

I assume, but haven't checked.

ALLIGATOR

  • Sr. Member
  • ****
  • Posts: 302
  • I use FPC [main] 💪🐯💪
Re: Specialized generic type of specialized generic types?
« Reply #2 on: September 13, 2025, 04:48:22 pm »
Code: Diff  [Select][+][-]
  1. -  generic TLotsOfTs<T> = specialize TObjectList<specialize SomeT<T>>;
  2. +  generic TLotsOfTs<T> = class(specialize TObjectList<specialize SomeT<T>>);
  3.  
I may seem rude - please don't take it personally

VisualLab

  • Hero Member
  • *****
  • Posts: 693
Re: Specialized generic type of specialized generic types?
« Reply #3 on: September 13, 2025, 06:19:54 pm »
I suppose thus that you really can't have a generic that specializes on another generic class. But maybe I am missing something? I presume I would just have to rethink what I am doing instead, I suppose.

What compiler mode are you using? The specialize keyword is required in ObjFpc mode. But in Delphi mode it is not necessary to use it.

Thaddy

  • Hero Member
  • *****
  • Posts: 18372
  • Here stood a man who saw the Elbe and jumped it.
Re: Specialized generic type of specialized generic types?
« Reply #4 on: September 13, 2025, 06:49:51 pm »
In mode delphi it doesn't work at all? ......
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

jamie

  • Hero Member
  • *****
  • Posts: 7322
Re: Specialized generic type of specialized generic types?
« Reply #5 on: September 13, 2025, 07:00:18 pm »
@ALLIGATOR solution fixes the problem either way.

Not sure if the compiler should know better ?


Jamie
The only true wisdom is knowing you know nothing

bolsen

  • New Member
  • *
  • Posts: 11
Re: Specialized generic type of specialized generic types?
« Reply #6 on: September 13, 2025, 07:29:00 pm »
Thanks everyone for the help!

Code: Diff  [Select][+][-]
  1. -  generic TLotsOfTs<T> = specialize TObjectList<specialize SomeT<T>>;
  2. +  generic TLotsOfTs<T> = class(specialize TObjectList<specialize SomeT<T>>);
  3.  

This compiled :) Before I tried to make a class of this but wondered why the compiler didn't like that either.

In mode delphi it doesn't work at all? ......

I tried it in Delphi mode the above (of course without the extra keywords) and that's fine too.

bolsen

  • New Member
  • *
  • Posts: 11
Re: Specialized generic type of specialized generic types?
« Reply #7 on: September 13, 2025, 07:32:23 pm »
I suppose thus that you really can't have a generic that specializes on another generic class. But maybe I am missing something? I presume I would just have to rethink what I am doing instead, I suppose.

What compiler mode are you using? The specialize keyword is required in ObjFpc mode. But in Delphi mode it is not necessary to use it.

While writing a lot generic code, I decided that probably a very generics-oriented unit might look nicer in delphi mode. Just my opinion, but declaring generic types and specialization looks obvious from context (specifically the use of a type variable gives it away).

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11826
  • Debugger - SynEdit - and more
    • wiki
Re: Specialized generic type of specialized generic types?
« Reply #8 on: September 13, 2025, 08:15:34 pm »
While writing a lot generic code, I decided that probably a very generics-oriented unit might look nicer in delphi mode. Just my opinion, but declaring generic types and specialization looks obvious from context (specifically the use of a type variable gives it away).

I would argue the opposite.

Within the "type" declaration block it is possible to argue that the <> indicate a generic. But they already are easier to overlook, than the dedicated "specialize" (or "generic") keyword.

When you however specialize inside the code (which I personally dislike... / but generic function require it), then you could have code like
Code: Pascal  [Select][+][-]
  1. begin
  2.   if a<b>(c and d) then foo;
  3. end;

And, if you don't know what the identifiers are, then this could be

Code: Pascal  [Select][+][-]
  1. var a,b: cardinal; c,d: boolean;
  2. begin
  3.   if a<b>(c and d) then foo;
  4. end;

or it could be

Code: Pascal  [Select][+][-]
  1. function A<B>(x:B): boolean; begin {} end;
  2. type b=cardinal; var c,d: cardinal;
  3. begin
  4.   if a<b>(c and d) then foo;
  5. end;

So, in mode Delphi, you can't tell from the syntax alone. In mode objfpc the "specialize" keyword would tell you.


Add to that overloaded operators, so "<" (smaller) can return other than boolean, and then the use of ">" (greater) after such an expression becomes more plausible (than the above "bool > bool" comparison
Code: Pascal  [Select][+][-]
  1. {$Mode objfpc} // declare in diff unit
  2. operator < (a:byte; b:pointer): integer; begin end;

And generics allow a lot of tricks of their own, to produce "interesting" syntactic constructs....

So, detecting them, just based on the presence of <>, that can be challenging.

bolsen

  • New Member
  • *
  • Posts: 11
Re: Specialized generic type of specialized generic types?
« Reply #9 on: September 13, 2025, 08:44:22 pm »
While writing a lot generic code, I decided that probably a very generics-oriented unit might look nicer in delphi mode. Just my opinion, but declaring generic types and specialization looks obvious from context (specifically the use of a type variable gives it away).

I would argue the opposite.

Within the "type" declaration block it is possible to argue that the <> indicate a generic. But they already are easier to overlook, than the dedicated "specialize" (or "generic") keyword.

When you however specialize inside the code (which I personally dislike... / but generic function require it), then you could have code like
Code: Pascal  [Select][+][-]
  1. begin
  2.   if a<b>(c and d) then foo;
  3. end;

And, if you don't know what the identifiers are, then this could be

Code: Pascal  [Select][+][-]
  1. var a,b: cardinal; c,d: boolean;
  2. begin
  3.   if a<b>(c and d) then foo;
  4. end;

or it could be

Code: Pascal  [Select][+][-]
  1. function A<B>(x:B): boolean; begin {} end;
  2. type b=cardinal; var c,d: cardinal;
  3. begin
  4.   if a<b>(c and d) then foo;
  5. end;

So, in mode Delphi, you can't tell from the syntax alone. In mode objfpc the "specialize" keyword would tell you.


Add to that overloaded operators, so "<" (smaller) can return other than boolean, and then the use of ">" (greater) after such an expression becomes more plausible (than the above "bool > bool" comparison
Code: Pascal  [Select][+][-]
  1. {$Mode objfpc} // declare in diff unit
  2. operator < (a:byte; b:pointer): integer; begin end;

And generics allow a lot of tricks of their own, to produce "interesting" syntactic constructs....

So, detecting them, just based on the presence of <>, that can be challenging.


These are good points. I had this sort of in the back of my mind after I wrote what I said: are there specific cases where it would not be so obvious? But it was more of a question if variables could act as type parameters (but that wouldn't make sense, since this happens at compile-time, no?)

I presume as a defensive measure in Delphi code, one has to really rely more on naming convention instead of the clear indicators (which for my own code, I liberally use :) )

(I have been hacking in Pascal for a little under a year now, so my opinion might not mean so much :D

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11826
  • Debugger - SynEdit - and more
    • wiki
Re: Specialized generic type of specialized generic types?
« Reply #10 on: September 13, 2025, 08:54:31 pm »
These are good points. I had this sort of in the back of my mind after I wrote what I said: are there specific cases where it would not be so obvious? But it was more of a question if variables could act as type parameters (but that wouldn't make sense, since this happens at compile-time, no?)

I presume as a defensive measure in Delphi code, one has to really rely more on naming convention instead of the clear indicators (which for my own code, I liberally use :) )

(I have been hacking in Pascal for a little under a year now, so my opinion might not mean so much :D )

Well, generics can take values for certain of their params (FPC 3.3.1).

E.g. it is possible to specify that a generic takes a number in the specialization => but that would still have to be a constant (could be "const foo = 1;"). Because as you said, it has to be able to be done at compile time.


If you want to see what "heave" generic usage can look like, look at "TDictionary" in
  fpc\packages\rtl-generics\src\inc\generics.dictionariesh.inc
(oh, and yes that is mode delphi)
Start reading at the bottom of the file. Enjoy.

Warfley

  • Hero Member
  • *****
  • Posts: 2021
Re: Specialized generic type of specialized generic types?
« Reply #11 on: September 13, 2025, 11:42:41 pm »
To answer the original question: FPC does not support generic parameter forwarding. The reason for that is not semantics but solely that in the current way the typesystem and generics is implemented it's not really easy to do.

What you can do us to create an intermediate type, like how this was solved by creating a new class type that inherits from the generic specialization.
Another alternative is to use a class or record for scoping:
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TMyDummy<T> = record
  3.     type TMyType = specialize TSomeType<T>
  4.   end;
  5.  
  6. // use
  7. specialize TMyDummy<T>.TMyType

Its simply that FPC cannot directly forward generic parameters but simply needs some intermediate definition.

About requiring specialize, the main issue here is one that you may encounter multiple times when looking into pascal syntax, unlike C-like languages pascal does not require brackets for function calls. The dilemma Martin brought up would not be an issue if brackets for functions are always necessary. In C++, if a is a function and it is followed by <, it is a generic specialization, because otherwise it would need to be a (. In pascal if a is a 0-ary function you can call it without brackets so there is indeed ambiguity.
This is why avoiding a special keyword works easily in C++ but can lead to problems in pascal (note this is not just there a problem but also for other syntactic constructs like function pointers where FPC introduced the @ operator for the same reason)

bolsen

  • New Member
  • *
  • Posts: 11
Re: Specialized generic type of specialized generic types?
« Reply #12 on: September 14, 2025, 09:48:45 am »
About requiring specialize, the main issue here is one that you may encounter multiple times when looking into pascal syntax, unlike C-like languages pascal does not require brackets for function calls. The dilemma Martin brought up would not be an issue if brackets for functions are always necessary. In C++, if a is a function and it is followed by <, it is a generic specialization, because otherwise it would need to be a (. In pascal if a is a 0-ary function you can call it without brackets so there is indeed ambiguity.
This is why avoiding a special keyword works easily in C++ but can lead to problems in pascal (note this is not just there a problem but also for other syntactic constructs like function pointers where FPC introduced the @ operator for the same reason)

This has been enlightening :) It seems like then that Delphi specifically made a bit of a trade-off here?

For the case of @, it's really not obvious if you might be calling a procedure or you are trying to compare it with something, so not having that feels like a mistake given Pascal syntax. I had this small issue:

Code: Pascal  [Select][+][-]
  1. if funcvar <> Nil then
  2.   funcvar(values);
  3.  

funcvar gets evaluated in the if statement. It would seem that you require a lot more contextual clues to just avoid the @ operator here (like if it is in an if-statement and parentheses are not used, then it is a pointer.) I haven't used Delphi here, so I wouldn't know ... an operator here is very obvious.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11826
  • Debugger - SynEdit - and more
    • wiki
Re: Specialized generic type of specialized generic types?
« Reply #13 on: September 14, 2025, 10:02:41 am »
Martin brought up would not be an issue if brackets for functions are always necessary. In C++, if a is a function and it is followed by <, it is a generic specialization, because otherwise it would need to be a (. In pascal if a is a 0-ary function you can call it without brackets so there is indeed ambiguity.

Actually, I my example does not omit brackets, nor does it rely on it.

The brackets for the function call are there, right after the specialization ends at the ">".

Warfley

  • Hero Member
  • *****
  • Posts: 2021
Re: Specialized generic type of specialized generic types?
« Reply #14 on: September 14, 2025, 12:51:59 pm »
Yeah but your examples are not ambiguous if you consider that the user knows whether a is a function or a variable. Something I think is a very basic requirement when working with code. But if a is a 0-ary function, it is actually ambiguous, a shift-reduce conflict in the parser

 

TinyPortal © 2005-2018