Lazarus

Free Pascal => General => Topic started by: Чебурашка on March 02, 2023, 12:51:18 pm

Title: syntax problem when using generics
Post by: Чебурашка on March 02, 2023, 12:51:18 pm
Hello,

I noted a syntax problem (maybe?) in usage of generics.

Code: Pascal  [Select][+][-]
  1. program Test;
  2. uses
  3.   SysUtils, Classes
  4.   , fgl;
  5.  
  6. type
  7.   TIntegerFPGList = specialize fgl.TFPGList<Integer>;
  8. begin
  9. end.
  10.  

When compiling it gives an error:

Code: Text  [Select][+][-]
  1. Fatal: Syntax error, "<" expected but "." found
  2.  

In other cases, when I put the unit name before the type it is ok.

Code: Pascal  [Select][+][-]
  1. program Test;
  2. uses
  3.   SysUtils, Classes
  4.  
  5.   , MyUnit // where TSomeType is defined
  6.   ;
  7.  
  8. var
  9.   x: MyUnit.TSomeType;
  10. begin
  11. end.
  12.  
Title: Re: syntax problem when using generics
Post by: Bogen85 on March 02, 2023, 12:58:52 pm
I noted a syntax problem (maybe?) in usage of generics.
...
In other cases, when I put the unit name before the type it is ok.

Same for the main branch. 3.3.1-12518-g40f23030dc

Code: Text  [Select][+][-]
  1. Free Pascal Compiler version 3.3.1 [2023/03/01] for x86_64
  2. Copyright (c) 1993-2023 by Florian Klaempfl and others
  3. Target OS: Linux for x86-64
  4. Compiling gen.pas
  5. gen.pas(7,35) Fatal: Syntax error, "<" expected but "." found
  6. Fatal: Compilation aborted
  7. Error: /home/dev/fpc_usr/lib/fpc/3.3.1/ppcx64 returned an error exitcode

I would consider this a bug...
Title: Re: syntax problem when using generics
Post by: Warfley on March 02, 2023, 03:03:56 pm
It's not a bug, you are just using the wrong syntax:
Code: Pascal  [Select][+][-]
  1. var
  2.   lst : fgl.specialize TFPGList<Integer>;
  3. begin
  4.   lst := fgl.specialize TFPGList<Integer>.Create;
  5. end.
Title: Re: syntax problem when using generics
Post by: Чебурашка on March 02, 2023, 03:45:20 pm
It's not a bug

Thank you
Title: Re: syntax problem when using generics
Post by: Thaddy on March 02, 2023, 03:47:06 pm
or just drop fgl. .. not the library, but the prefix
Code: Pascal  [Select][+][-]
  1. var
  2.   lst : specialize TFPGList<Integer>;

even better, declare a type first. Keeps your code cleaner.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. uses fgl;
  3. type
  4.   Tlst = specialize TFPGList<Integer>;
  5. var
  6.   lst : Tlst;
  7. begin
  8.   lst := Tlst.Create;
  9.   Lst.Free;
  10. end.

The unit prefix only makes sense if you combine multiple generics libraries, like fgl, lgenerics and or rtl-generics and all of that also in the same unit....
Like so:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. uses fgl, generics.collections;
  3. type
  4.   Tlst1 = fgl.specialize TFPGList<Integer>;
  5.   Tlst2 = generics.collections.specialize Tlist<integer>;
  6. var
  7.   lst1 : Tlst1;
  8.   lst2 : TLst2;
  9. begin
  10.   lst1 := Tlst1.Create;
  11.   lst2 := Tlst2.Create;
  12.   Lst1.Free;
  13.   Lst2.free;
  14. end.

Title: Re: syntax problem when using generics
Post by: Bogen85 on March 02, 2023, 03:53:22 pm
It's not a bug, you are just using the wrong syntax:
Code: Pascal  [Select][+][-]
  1. var
  2.   lst : fgl.specialize TFPGList<Integer>;
  3. begin
  4.   lst := fgl.specialize TFPGList<Integer>.Create;
  5. end.

Awesome! Thanks!

I would consider this a bug...

...if there was no way specify the unit prefix!  :D
Title: Re: syntax problem when using generics
Post by: Thaddy on March 02, 2023, 03:58:50 pm
See my editted example. It only makes sense for the third and specializing on a var is usualy not a good idea anyway.
Title: Re: syntax problem when using generics
Post by: VisualLab on March 02, 2023, 06:25:08 pm
This is a rather bizarre notation:

Code: Pascal  [Select][+][-]
  1. var
  2.   lst : fgl.specialize TFPGList<Integer>;
  3. begin
  4.   lst := fgl.specialize TFPGList<Integer>.Create;
  5. end.

Is there an alternative notation that would be more "pascalish"? For example like this:

Code: Pascal  [Select][+][-]
  1. var
  2.   lst : specialize fgl.TFPGList<Integer>;
  3. begin
  4.   lst := specialize fgl.TFPGList<Integer>.Create;
  5. end.

The first way, where the keyword specialize is "mixed in" into part of the name, is not very readable. Delphi mode does not use this keyword. So was it really necessary to add this keyword? Perhaps the rule of "don't multiply entities beyond necessity" should have worked here (i.e. if the syntax of the language is readable without additional syntax elements, then you probably shouldn't add them).

However, if there are any reasons to use this word, then perhaps it should appear before the type name? After all, the fgl prefix only specifies the name of the module from which this class comes (it becomes part of the type name).

So what with this specialize keyword?

Title: Re: syntax problem when using generics
Post by: KodeZwerg on March 02, 2023, 06:37:40 pm
So what with this specialize keyword?
Does the documentation (https://lazarus-ccr.sourceforge.io/fpcdoc/ref/refse51.html) answer your question?
Title: Re: syntax problem when using generics
Post by: Bogen85 on March 02, 2023, 06:41:12 pm
So what with this specialize keyword?
Does the documentation (https://lazarus-ccr.sourceforge.io/fpcdoc/ref/refse51.html) answer your question?

Quote
So what with this...

Translation:

So what the  :o :o :o is up with this...   O:-)

EDIT: Toned down my exaggerated reaction...

Title: Re: syntax problem when using generics
Post by: Bogen85 on March 02, 2023, 06:44:16 pm
Especially when it might result in
Code: Pascal  [Select][+][-]
  1. unit_name.specialize ...
Title: Re: syntax problem when using generics
Post by: VisualLab on March 02, 2023, 07:22:31 pm
So what with this specialize keyword?
Does the documentation (https://lazarus-ccr.sourceforge.io/fpcdoc/ref/refse51.html) answer your question?

Quote
So what with this...

Translation:

So what the  :o :o :o is up with this...   O:-)

I don't quite understand what it is. Was my final question understood as a so-called "litigiousness" or "nitpicking"? If so, there was a misunderstanding.

I'd really like to know more about the need to use the "specialize" keyword than is covered in the documentation. The documentation usually gives some concise explanation, without digression. I find the forum to be a quite natural place to ask more specific questions. Of course, it may happen that there will be no answers to such detailed questions :)

EDIT: changes in quotation
Title: Re: syntax problem when using generics
Post by: Bogen85 on March 02, 2023, 07:27:49 pm
I don't quite understand what it is. Was my final question understood as a so-called "litigiousness" or "nitpicking"? If so, there was a misunderstanding.

I apologize. I understood what you asked as being what is up with it, if it results in such a bizarre syntax with name space prefixing, and also what is up with it as it is not needed to be understood.

I did not think you were over reacting, I was replying to KodeZwerg putting more of my emphasis into it...

EDIT: I toned down my "translation" in Reply #10
Title: Re: syntax problem when using generics
Post by: VisualLab on March 02, 2023, 07:32:51 pm
So what with this specialize keyword?
Does the documentation (https://lazarus-ccr.sourceforge.io/fpcdoc/ref/refse51.html) answer your question?

Short answer: no

Longer answer: there were three questions.

1. first question:

Is there an alternative notation that would be more "pascalish"? For example like this:

Code: Pascal  [Select][+][-]
  1. var
  2.   lst : specialize fgl.TFPGList<Integer>;
  3. begin
  4.   lst := specialize fgl.TFPGList<Integer>.Create;
  5. end.

The first way, where the keyword specialize is "mixed in" into part of the name, is not very readable. Delphi mode does not use this keyword.

The text below the code is an additional clarification to question #1.

2. second question:

So was it really necessary to add this keyword? Perhaps the rule of "don't multiply entities beyond necessity" should have worked here (i.e. if the syntax of the language is readable without additional syntax elements, then you probably shouldn't add them).

3. three question:

However, if there are any reasons to use this word, then perhaps it should appear before the type name? After all, the fgl prefix only specifies the name of the module from which this class comes (it becomes part of the type name).

And this is summary question:

So what with this specialize keyword?

which (as it turned out) was entered unnecessarily, because it confused some people.
Title: Re: syntax problem when using generics
Post by: Thaddy on March 02, 2023, 07:33:43 pm
And all of you should learn to specialize as a type not on a var. That is plain stupid, although it is allowed.
Anyway, when unit scope is necessary and you want to want the obvious certainty your routine gets called in a proper way:
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. uses fgl, generics.collections;
  3. type
  4.   Tlst1 = fgl.TFPGList<Integer>;
  5.   Tlst2 = generics.collections.Tlist<integer>;
  6. var
  7.   lst1 : Tlst1;
  8.   lst2 : TLst2;
  9. begin
  10.   lst1 := Tlst1.Create;
  11.   lst2 := Tlst2.Create;
  12.   Lst1.Free;
  13.   Lst2.free;
  14. end.
The modes are unit scope, so you can mix and match in units or programs with either mode... <sigh>
@tt was put on the wrong track by you lot.. >:D
Title: Re: syntax problem when using generics
Post by: VisualLab on March 02, 2023, 07:54:16 pm
And all of you should learn to specialize as a type not on a var.

That's what I do. I try to avoid unreadable, ambiguous or convoluted code. And for these reasons, when I use generics, I also use Delphi mode. And that's also why I asked these three questions. So far, I have barely used the specialize keyword. More precisely - I tried, but after several attempts I gave up this practice.

That is plain stupid, although it is allowed.

I think so too.
Title: Re: syntax problem when using generics
Post by: PascalDragon on March 03, 2023, 07:48:42 am
This is a rather bizarre notation:

Code: Pascal  [Select][+][-]
  1. var
  2.   lst : fgl.specialize TFPGList<Integer>;
  3. begin
  4.   lst := fgl.specialize TFPGList<Integer>.Create;
  5. end.

Is there an alternative notation that would be more "pascalish"? For example like this:

Code: Pascal  [Select][+][-]
  1. var
  2.   lst : specialize fgl.TFPGList<Integer>;
  3. begin
  4.   lst := specialize fgl.TFPGList<Integer>.Create;
  5. end.

The first way, where the keyword specialize is "mixed in" into part of the name, is not very readable.

You are not thinking far ahead enough: the problem is if you have multiple specialization in one statement. E.g. SomeUnit.specialize SomeTypeA<TypeX>.specialize SomeTypeB<TypeY>.specialize SomeClassFunc<TypeZ>. By having the specialize be part of the identifier to be specialized things are much clearer.

Delphi mode does not use this keyword. So was it really necessary to add this keyword? Perhaps the rule of "don't multiply entities beyond necessity" should have worked here (i.e. if the syntax of the language is readable without additional syntax elements, then you probably shouldn't add them).

First of the keyword was added way before Delphi added generics. And second FPC still does not support all situations where Delphi supports specializations (e.g. expressions with inline specializations that involve operators), simply because the syntax of using “<” is ambiguous especially due to Delphi also allowing overloads of generics types with variables, constants and functions.

However, if there are any reasons to use this word, then perhaps it should appear before the type name? After all, the fgl prefix only specifies the name of the module from which this class comes (it becomes part of the type name).

No, that was originally the case, but was changed with 3.2.0 when generic functions were introduced for the above reason.

or just drop fgl. .. not the library, but the prefix
Code: Pascal  [Select][+][-]
  1. var
  2.   lst : specialize TFPGList<Integer>;

even better, declare a type first. Keeps your code cleaner.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. uses fgl;
  3. type
  4.   Tlst = specialize TFPGList<Integer>;
  5. var
  6.   lst : Tlst;
  7. begin
  8.   lst := Tlst.Create;
  9.   Lst.Free;
  10. end.

The unit prefix only makes sense if you combine multiple generics libraries, like fgl, lgenerics and or rtl-generics and all of that also in the same unit....

Also this simply won't work in FPC < 3.3.1 due to it not handling unit names together with generics correctly (it will pick the generic from one of the two units, not necessarily the one you specified, assuming it's indeed available in multiple units).
Title: Re: syntax problem when using generics
Post by: Warfley on March 03, 2023, 08:13:55 am
You are not thinking far ahead enough: the problem is if you have multiple specialization in one statement. E.g. SomeUnit.specialize SomeTypeA<TypeX>.specialize SomeTypeB<TypeY>.specialize SomeClassFunc<TypeZ>. By having the specialize be part of the identifier to be specialized things are much clearer.
There could be other solutions, e.g. . could have precedence over specialize, so it would be:
Code: Pascal  [Select][+][-]
  1. specialize (specialize A.B<T>).C<U>
Alternatively, specialize could be binding to the first unspecialized generic in a chain, so:
Code: Pascal  [Select][+][-]
  1. specialize specialize A.B<T>.C<U>
But I'm not sure if this is going to be better readable in chain (and is probably much harder to implement robustly in the compiler).

Or, just as a special case, when there is only one specialize, it could be put in front, and to only have specialize in chains required when more than one generic occurs:
Code: Pascal  [Select][+][-]
  1. specialize A.B<T>
  2. vs
  3. A.specialize B<T>.specialze C<U>

But TBH, while I also think this syntax isn't the prettiest, it occurs so rarely, that I don't think it is really a problem.
Title: Re: syntax problem when using generics
Post by: Thaddy on March 03, 2023, 10:59:28 am
Also this simply won't work in FPC < 3.3.1 due to it not handling unit names together with generics correctly (it will pick the generic from one of the two units, not necessarily the one you specified, assuming it's indeed available in multiple units).
Well, it does in 3.2.0 because fgl.TFPGList<> and generics.collections.Tlist<> are resolved correctly?
If not, I stand corrected, again... But that is in the context of my example not the the case because the roots differ in name.
Or, as usual, am I missing something?
Title: Re: syntax problem when using generics
Post by: marcov on March 03, 2023, 11:51:04 am
Or specialize could only be used to disambiguate instead of being mandatory.
Title: Re: syntax problem when using generics
Post by: PascalDragon on March 04, 2023, 05:23:05 pm
Also this simply won't work in FPC < 3.3.1 due to it not handling unit names together with generics correctly (it will pick the generic from one of the two units, not necessarily the one you specified, assuming it's indeed available in multiple units).
Well, it does in 3.2.0 because fgl.TFPGList<> and generics.collections.Tlist<> are resolved correctly?
If not, I stand corrected, again... But that is in the context of my example not the the case because the roots differ in name.
Or, as usual, am I missing something?

It works in those cases, because only one TFPGList<> or TList<> exists anyway. If you have two units with a generic with the same name then you'll have the problem.
TinyPortal © 2005-2018