Discussion:
[fpc-devel] Generic class comparison operators
Ryan Joseph via fpc-devel
2021-04-17 20:02:26 UTC
Permalink
Since I'm working on generics right now can we finally, at the very least, allow class operators for comparison operators? This is literally the only way for a generic class to override the = operator (along with some others) so there's no reason not to allow this. I understand the objection to :=, + etc.. where it returns a copy of a class instance and people could in theory do memory unsafe things, with comparison operators there is no possibility for this. I already made a patch for "advanced records" which is in limbo but It's trivial to adapt this for classes and put restrictions on the type of operator.

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/f
Jonas Maebe via fpc-devel
2021-04-17 20:12:06 UTC
Permalink
Post by Ryan Joseph via fpc-devel
Since I'm working on generics right now can we finally, at the very
least, allow class operators for comparison operators? This is
literally the only way for a generic class to override the = operator
(along with some others) so there's no reason not to allow this. I
understand the objection to :=, + etc.. where it returns a copy of a
class instance and people could in theory do memory unsafe things,
with comparison operators there is no possibility for this. I already
made a patch for "advanced records" which is in limbo but It's trivial
to adapt this for classes and put restrictions on the type of
operator.
The issue with allowing it for classes (generic or not) is that the the
= operator already has a meaning for them (pointer equality). I think in
general we don't allow overloading operators that have a built-in
meaning.

It would work very well either, because if you'd pass such a class
instance as a TObject parameter and that called routine performs a
comparison, then suddenly the comparison would happen again based on
pointer equality rather than with this custom operator. This means that
e.g. any non-generic container class that uses comparisons (for sorting
or for detecting duplicates) would fail to work, or at least work
differently than generic container classes. That's something you don't
want at all in a programming language, as it means you constantly have
to keep in mind how something you call was implemented to know how it
will behave (the called routine may even have your class type as
parameter type, but then call something else that uses TObject).


Jonas
_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
https://lists.freepascal.org/cgi-
Ryan Joseph via fpc-devel
2021-04-17 20:39:51 UTC
Permalink
The issue with allowing it for classes (generic or not) is that the the = operator already has a meaning for them (pointer equality). I think in general we don't allow overloading operators that have a built-in meaning.
I see your point about there being a conflict for pointer quality but you can actually resolve it by casting to TObject, however as you note it could be confusing also. That's an interesting question I'd need to think about more but even so that is only the = operator with other pointer types.

Here's the list of possible operators that don't have side effects to the caller and are worth considering and may be safe.

class operator = (left: TSelf; right: TRight): boolean;
class operator not (left: TSelf): boolean;
class operator <> (left: TSelf; right: TRight): boolean;
class operator < (left: TSelf; right: TRight): boolean;
class operator > (left: TSelf; right: TRight): boolean;
class operator <= (left: TSelf; right: TRight): boolean;
class operator >= (left: TSelf; right: TRight): boolean;
class operator >< (left: TSelf; right: TRight): boolean;
class operator in (left: TSelf; right: TRight): boolean;


Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fp
Benito van der Zander via fpc-devel
2021-04-21 13:44:33 UTC
Permalink
Hi,

 what about overloading operators for OBJECTs?

They do not conflict with any default operators.

I expected this to work, but it did not compile:


  type generic TXQHashset<TKey, TInfo> = object //(specialize
TXQBaseHashmap<TKey,TXQVoid,TInfo>)...
    class operator =(const a, b: TXQHashset): boolean;
  end;


Cheers,
Benito
Post by Jonas Maebe via fpc-devel
Post by Ryan Joseph via fpc-devel
Since I'm working on generics right now can we finally, at the very
least, allow class operators for comparison operators? This is
literally the only way for a generic class to override the = operator
(along with some others) so there's no reason not to allow this. I
understand the objection to :=, + etc.. where it returns a copy of a
class instance and people could in theory do memory unsafe things,
with comparison operators there is no possibility for this. I already
made a patch for "advanced records" which is in limbo but It's trivial
to adapt this for classes and put restrictions on the type of
operator.
The issue with allowing it for classes (generic or not) is that the
the = operator already has a meaning for them (pointer equality). I
think in general we don't allow overloading operators that have a
built-in meaning.
It would work very well either, because if you'd pass such a class
instance as a TObject parameter and that called routine performs a
comparison, then suddenly the comparison would happen again based on
pointer equality rather than with this custom operator. This means
that e.g. any non-generic container class that uses comparisons (for
sorting or for detecting duplicates) would fail to work, or at least
work differently than generic container classes. That's something you
don't want at all in a programming language, as it means you
constantly have to keep in mind how something you call was implemented
to know how it will behave (the called routine may even have your
class type as parameter type, but then call something else that uses
TObject).
Jonas
_______________________________________________
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Ryan Joseph via fpc-devel
2021-04-21 14:21:24 UTC
Permalink
Post by Benito van der Zander via fpc-devel
Hi,
what about overloading operators for OBJECTs?
They do not conflict with any default operators.
type generic TXQHashset<TKey, TInfo> = object //(specialize TXQBaseHashmap<TKey,TXQVoid,TInfo>)...
class operator =(const a, b: TXQHashset): boolean;
end;
yes I have patch to enable this via a mode switch (https://bugs.freepascal.org/view.php?id=36350) but it has been acknowledged and then ignored without explanation since 2019. This is still the only way we can use operator overloads for generic objects and objects are the only way to have record inheritance so it's a critical missing feature in my opinion.

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
https://lists.freepascal.o
Sven Barth via fpc-devel
2021-04-21 18:57:03 UTC
Permalink
Post by Benito van der Zander via fpc-devel
Hi,
 what about overloading operators for OBJECTs?
They do not conflict with any default operators.
  type generic TXQHashset<TKey, TInfo> = object //(specialize
TXQBaseHashmap<TKey,TXQVoid,TInfo>)...
    class operator =(const a, b: TXQHashset): boolean;
  end;
You can only use global operators with objects.

Regards,
Sven
Ryan Joseph via fpc-devel
2021-04-21 19:03:43 UTC
Permalink
Post by Sven Barth via fpc-devel
You can only use global operators with objects.
yes but not with *generic* objects. I find it very hard to understand why this is being blocked for objects. Without this there is no way to have *generic* record inheritance in Pascal. Is this seen as a problem or something that people would make a generic inheritable record type? Without this we have stupid things like having to reimplement TVec2<T>, TVec3<T>, TVec4<T> etc... because we can't simply inherit from the previous type.

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
https://lists.freepascal.

Sven Barth via fpc-devel
2021-04-18 07:37:29 UTC
Permalink
Post by Ryan Joseph via fpc-devel
Since I'm working on generics right now can we finally, at the very least,
allow class operators for comparison operators? This is literally the only
way for a generic class to override the = operator (along with some others)
so there's no reason not to allow this. I understand the objection to :=, +
etc.. where it returns a copy of a class instance and people could in
theory do memory unsafe things, with comparison operators there is no
possibility for this. I already made a patch for "advanced records" which
is in limbo but It's trivial to adapt this for classes and put restrictions
on the type of operator.
It has been decided back when operator overloads were introduced that they
do not replace existing, built in operators. This decision still stands.
And we see no reason to change that. This way a user can *rely* on what a
certain operator means based on the language reference guide. This is more
important than some convenience for certain use cases.

Regards,
Sven
Ryan Joseph via fpc-devel
2021-04-21 14:54:59 UTC
Permalink
It has been decided back when operator overloads were introduced that they do not replace existing, built in operators. This decision still stands. And we see no reason to change that. This way a user can *rely* on what a certain operator means based on the language reference guide. This is more important than some convenience for certain use cases.
We still have some inconsistencies though because of the many other comparison operators which can already be overloaded but simply lack a class operator syntax and thus are not available to classes.

// impossible overload
operator = (left: TObject; right: TObject): boolean;

// possible overload
operator = (left: TObject; right: integer): boolean;

// possible overload
operator < (left: TObject; right: TObject): boolean;

In fact other binary operators that don't have side effects (i.e. don't return the class type) are safe and could be allowed in generic classes also.

// only way to overload + for TSomeClass<T>
operator + (left, right: TSomeClass<T>): String;

So it's really just about a number of inconsistencies with classes and that's why I wanted to fix it. Same with Objects as Benito has just pointed out again.

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
https://lists.freepascal.
Sven Barth via fpc-devel
2021-04-21 18:54:36 UTC
Permalink
Post by Ryan Joseph via fpc-devel
It has been decided back when operator overloads were introduced that they do not replace existing, built in operators. This decision still stands. And we see no reason to change that. This way a user can *rely* on what a certain operator means based on the language reference guide. This is more important than some convenience for certain use cases.
We still have some inconsistencies though because of the many other comparison operators which can already be overloaded but simply lack a class operator syntax and thus are not available to classes.
// impossible overload
operator = (left: TObject; right: TObject): boolean;
// possible overload
operator = (left: TObject; right: integer): boolean;
// possible overload
operator < (left: TObject; right: TObject): boolean;
In fact other binary operators that don't have side effects (i.e. don't return the class type) are safe and could be allowed in generic classes also.
// only way to overload + for TSomeClass<T>
operator + (left, right: TSomeClass<T>): String;
So it's really just about a number of inconsistencies with classes and that's why I wanted to fix it. Same with Objects as Benito has just pointed out again.
You miss the point. The point is that the way it is now *always*
guarantees that e.g. TObject = TObject *always* behaves the same no
matter what unit one includes. Same for e.g. String + String, String >
String, Integer < Integer, etc. And *that* is the consistency that is
important, *not* that every operator can be overloaded for each
combination of types. The set of overloadable operators is essentially
different for each pair of types.
This will not change, because the base rules of the language take higher
precedence and that would even be something that we likely wouldn't copy
from Delphi if they'd introduce that.

Regards,
Sven
_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo
Continue reading on narkive:
Loading...