Operator overload resolution with arrays

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Operator overload resolution with arrays

Martok
Hi all,

I'm having some logical problems with fgl generic lists and operator overloads.
This is essentially the same issue as discussed last year on the forum as
<http://forum.lazarus.freepascal.org/index.php?topic=36089.0>.
I know how to work around it, just... it doesn't seem very consistent.

Take the following simple declaration:
--------
type
  TTriangleIndex = array[0..2] of Integer;
  TFacetList = specialize TFPGList<TTriangleIndex>;

  operator = (A, B: TTriangleIndex): boolean;
--------
This will not work:
fgl.pp(948,50) Error: Operator is not overloaded: "TTriangleIndex" =
"TTriangleIndex"

So, for arrays, the overloaded operator is not found, even though it is in the
same interface section.

However, this arcane beast would work (although Codetools bail on the double
specialization):
--------
  TTriangleIndex = array[0..2] of Integer;
  generic TArrayContainer<T> = record
    x: T;
    class operator = (A, B: specialize TArrayContainer<T>): boolean;
    // mimic 'default' attribute on x
    class operator := (A: T): specialize TArrayContainer<T>; inline;
    class operator := (A: specialize TArrayContainer<T>): T; inline;
  end;
  TFacetList = specialize TFPGList<specialize TArrayContainer<TTriangleIndex>>;
--------

Class operators defined on the used type itself are taken into account. That
feels a bit inconsistent, given that their scope is equivalent in any other use?

I know it's been like that forever, but... should it be?

--
Regards,
Martok

Ceterum censeo b32079 esse sanandam.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

denisgolovan

> Take the following simple declaration:
> --------
> type
> TTriangleIndex = array[0..2] of Integer;
> TFacetList = specialize TFPGList<TTriangleIndex>;
>
> operator = (A, B: TTriangleIndex): boolean;
> --------
> This will not work:
> fgl.pp(948,50) Error: Operator is not overloaded: "TTriangleIndex" =
> "TTriangleIndex"

Hi, I believe https://bugs.freepascal.org/view.php?id=27690 is all about it.

--
Regards,
Denis Golovan
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Maciej Izak
2018-02-05 13:59 GMT+01:00 denisgolovan <[hidden email]>:
Hi, I believe https://bugs.freepascal.org/view.php?id=27690 is all about it.

IMHO this code shouldn't ever work. Any fix means really mess and hell and more problems. The proper workaround is:

* use TTriangleIndex inside record with class operator Equal
* use Generics.Collections

-- 
Best regards,
Maciej Izak

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Free Pascal - General mailing list
In reply to this post by Martok
Am 05.02.2018 13:02 schrieb "Martok" <[hidden email]>:
Hi all,

I'm having some logical problems with fgl generic lists and operator overloads.
This is essentially the same issue as discussed last year on the forum as
<http://forum.lazarus.freepascal.org/index.php?topic=36089.0>.
I know how to work around it, just... it doesn't seem very consistent.

While specializing the compiler only uses operator overloads (and helpers) that have been in scope during the declaration of the generic or those that are part of the types that are used for the specialization. This is definitely consistent. 
While I do plan to test what happens if I allow units that were not part of the generic's scope during its declaration that has the potential to open a whole new can of bugs. 

Regards, 
Sven 

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Martok
In reply to this post by Maciej Izak
>     Hi, I believe https://bugs.freepascal.org/view.php?id=27690
>     <https://bugs.freepascal.org/view.php?id=27690> is all about it.
Looks like it.

> IMHO this code shouldn't ever work. Any fix means really mess and hell and more
> problems.
Why? As the specialized interface gets "inserted" into the specializing unit at
that point, so should the implementation be - and at that point, the operator
*is* overloaded.
Instead, the overload has to be available in the implementation section of the
generic type, /unless/ it is a class or record. That seems odd. You know I
generally prefer consistency over obscure formal differences ;-)

And it's not like we don't already have absurd operator chains without that, see
31215.

> * use Generics.Collections
I'd like to stick with fcl units, and rtl-generics seems pretty outdated
compared to your repo?

Of course, the issue itself also occurs with any user code, not just containers.
That kind of lookup means *no* overload on non-object types is available to
generics declared in other units: arithmetic, Implicit, Explicit etc.


--
Regards,
Martok

Ceterum censeo b32079 esse sanandam.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Martok
In reply to this post by Free Pascal - General mailing list
Ah sorry, hadn't seen your message before my last.

> While specializing the compiler only uses operator overloads (and helpers) that
> have been in scope during the declaration of the generic or those that are part
> of the types that are used for the specialization. This is definitely consistent.
Unintuitive, but consistent, okay.

Type helpers for the used type that are in scope at the time of specialization
are also not applied. But I guess they don't count as "part of the type", so
that's technically true.

I may have missed something important about how generics are specialized
internally. That would explain what I wrote in my answer to Maciej.



--
Regards,
Martok

Ceterum censeo b32079 esse sanandam.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Martok
Am 05.02.2018 um 15:26 schrieb Martok:
> Ah sorry, hadn't seen your message before my last.
>
>> While specializing the compiler only uses operator overloads (and helpers) that
>> have been in scope during the declaration of the generic or those that are part
>> of the types that are used for the specialization. This is definitely consistent.
> Unintuitive, but consistent, okay.

I only just noticed (and I read that page before writing the first message
here...): the documentation says this is indeed not intentional?

<https://www.freepascal.org/docs-html/ref/refse57.html>
""" Currently, due to an implementation restriction, it will not work using a
global operator, i.e. the following does not work yet:
...
Support for this construct is expected in a future version of Free Pascal."""


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Maciej Izak
In reply to this post by Martok
2018-02-05 15:00 GMT+01:00 Martok <[hidden email]>:
Why? ...

Default property / field or/and aspects is better solution. The way mentioned by Sven with extending generic's scope means almost no control over used operators (or really hard to predict), IMO bad design >.<. Now we have a lot of problems with type/class/record helpers scope, for extending generic's scope I can guarantee "exponentially" more non-fixable problems + destruction of consistency of language and problems with implementation of default property / field and aspects... Pandora's box is nothing in comparison to extending generic's scope in such way :P. Simple example:

specialization for the same generic type can behaves in different way!

for example final code for TFoo< TSomeArray> will be different than for TFoo<TSomeArray> declared in other module (!). What if TFoo<T> has some class var + class constructor ? What if inside is used some dictionary (declared as class var and handled in class constructor/destructor) to handle different specializations (where as key of that dictionary is used TypeInfo(T)) and some logic is hidden behind of type which behaves in different way for the same specialization?

Totally nuclear destruction and non-fixable problems for language and libraries. I will repeat it again : definitely non-consistent and destructive feature. This can't work in proper way.

> * use Generics.Collections
I'd like to stick with fcl units, and rtl-generics seems pretty outdated
compared to your repo?

I'am working on Generics.Collections 2.0 it is not ready for trunk yet (anyway https://github.com/maciej-izak/generics.collections is full functional for 3.0.4 and trunk - just few tests are missing and part of interface for T*AVLTree*<> types). 
Generics.Collections 2.0 is much improved, with many fixes, full of tests and ready/optimized for Smart Pointers / Nullable types. I found also many new compiler bugs related to generics types and I want to try to fix part of them before I decide to update rtl-generics.

--
Best regards,
Maciej Izak

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Free Pascal - General mailing list
Am 05.02.2018 15:49 schrieb "Maciej Izak" <[hidden email]>:
specialization for the same generic type can behaves in different way!

for example final code for TFoo< TSomeArray> will be different than for TFoo<TSomeArray> declared in other module (!). What if TFoo<T> has some class var + class constructor ? What if inside is used some dictionary (declared as class var and handled in class constructor/destructor) to handle different specializations (where as key of that dictionary is used TypeInfo(T)) and some logic is hidden behind of type which behaves in different way for the same specialization?

Totally nuclear destruction and non-fixable problems for language and libraries. I will repeat it again : definitely non-consistent and destructive feature. This can't work in proper way.

Which is exactly what I had meant with the whole new can of bugs :P

I found also many new compiler bugs related to generics types and I want to try to fix part of them before I decide to update rtl-generics.

Would be good if you'd report them on Mantis nevertheless, cause generics are a bit of a sensitive area and I'd like to keep an overview there. 

Regards, 
Sven 

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Martok
In reply to this post by Maciej Izak
Am 05.02.2018 um 15:49 schrieb Maciej Izak:
> for example final code for TFoo< TSomeArray> will be different than for
> TFoo<TSomeArray> declared in other module (!).
Crap. True.

Now I see why it is how it is.

The maximum extent would be to accept overloads (and helpers) that are visible
at the parameter type's declaration, because they would necessarily be visible
in all specializations as well. That would be pretty much the same as how it
currently accepts operators defined on the type, just one symtable up. It would
also solve the "implementation restriction" from the manual - and only that. I
think?


--
Regards,
Martok

Ceterum censeo b32079 esse sanandam.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Free Pascal - General mailing list
Am 05.02.2018 17:50 schrieb "Martok" <[hidden email]>:
Am 05.02.2018 um 15:49 schrieb Maciej Izak:
> for example final code for TFoo< TSomeArray> will be different than for
> TFoo<TSomeArray> declared in other module (!).
Crap. True.

Now I see why it is how it is.

The maximum extent would be to accept overloads (and helpers) that are visible
at the parameter type's declaration, because they would necessarily be visible
in all specializations as well. That would be pretty much the same as how it
currently accepts operators defined on the type, just one symtable up. It would
also solve the "implementation restriction" from the manual - and only that. I
think?

That *could* be a possibility. I'd need to think about it a bit though to be sure that there are no caveats. 

Regards, 
Sven 

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Maciej Izak
2018-02-05 19:54 GMT+01:00 Sven Barth via fpc-pascal <[hidden email]>:
Now I see why it is how it is.

The maximum extent would be to accept overloads (and helpers) that are visible
at the parameter type's declaration, because they would necessarily be visible
in all specializations as well. That would be pretty much the same as how it
currently accepts operators defined on the type, just one symtable up. It would
also solve the "implementation restriction" from the manual - and only that. I
think?

That *could* be a possibility. I'd need to think about it a bit though to be sure that there are no caveats. 

It may be good feature or more troubles ;) The only acceptable types where "one symtable up" should be used, are types with own RTTI info:

type
  MyInteger = type Integer;
   { .. some operators for MyInteger  ... }
  TMyHelper = type helper for MyInteger
     { something } 
  end;

type alias declaration for our case is not an option:

type
  MyInteger = Integer;
  { .. some operators for MyInteger  ... }
  TMyHelper = type helper for MyInteger
     { something } 
  end;

for such case TMyHelper (or operator) should be invisible in specializations, otherwise compiled program will explode :P.

--
Best regards,
Maciej Izak

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Operator overload resolution with arrays

Maciej Izak
In reply to this post by Free Pascal - General mailing list
2018-02-05 17:12 GMT+01:00 Sven Barth via fpc-pascal <[hidden email]>:
Would be good if you'd report them on Mantis nevertheless, cause generics are a bit of a sensitive area and I'd like to keep an overview there. 

I was able to collect list of ~10 new bugs but part of them is probably related to 3.0.4, part is probably duplicated, part was not tested with trunk so final list might be shorter. Sometimes minimal test case, especially for generics is hard to expose. I will try to find enough motivation for new bug reports. :/ Compiler hates my code - internal errors, fatal errors, errors without source locations and false errors... New challenges/issues to fix :)

--
Best regards,
Maciej Izak

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal