www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - opCmp with template type not working.

reply Jonathan Levi <catanscout gmail.com> writes:
This is not working as expected:
 bool opCmp(string op, U)(U rhs) {
As it does work with:
 auto opBinary(string op, U)(U rhs) {
With:
 struct X {
     int x;
     auto opBinary(string op, U)(U rhs) {
             return mixin("x "~op~" rhs");
         }
     bool opCmp(string op, U)(U rhs) {
         return mixin("x "~op~" rhs");
     }
 }
This compiles:
 X(5) + 4
This does not:
 X(5) < 4
Full example code: https://run.dlang.io/is/Beflkt Is this a Bug?
Nov 02 2020
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
Two questions:

1) Why is opCmp returning a bool?
2) Why does opCmp have a template parameter called `op`?

https://dlang.org/spec/operatoroverloading.html#compare
Nov 02 2020
prev sibling parent reply user1234 <user1234 12.de> writes:
On Tuesday, 3 November 2020 at 02:55:46 UTC, Jonathan Levi wrote:
 This is not working as expected:
 bool opCmp(string op, U)(U rhs) {
As it does work with:
 auto opBinary(string op, U)(U rhs) {
With:
 struct X {
     int x;
     auto opBinary(string op, U)(U rhs) {
             return mixin("x "~op~" rhs");
         }
     bool opCmp(string op, U)(U rhs) {
         return mixin("x "~op~" rhs");
     }
 }
This compiles:
 X(5) + 4
This does not:
 X(5) < 4
Full example code: https://run.dlang.io/is/Beflkt Is this a Bug?
opCmp should return a signed integer. This allows to match well with the x86 flag register and do fast comparison with integers types (in which case just substract rhs to lhs and you're good)
Nov 02 2020
next sibling parent Jonathan Levi <catanscout gmail.com> writes:
On Tuesday, 3 November 2020 at 03:07:14 UTC, user1234 wrote:
 opCmp should return a signed integer. This allows to match well 
 with the x86 flag register and do fast comparison with integers 
 types (in which case just substract rhs to lhs and you're good)
Um, I missed that. Man, I have some old errors in my code. I had opCmp implemented that way for a while, and apparently never tested or used it. I see that now in the spec.
Nov 02 2020
prev sibling next sibling parent reply ag0aep6g <anonymous example.com> writes:
On 03.11.20 04:07, user1234 wrote:
 opCmp should return a signed integer. This allows to match well with the 
 x86 flag register and do fast comparison with integers types (in which 
 case just substract rhs to lhs and you're good)
Doing comparison by subtracting is a cute idea, but it doesn't actually work in general because of wraparound. Example: int.min < 1, but int.min - 1 > 0.
Nov 02 2020
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/3/20 1:56 AM, ag0aep6g wrote:
 On 03.11.20 04:07, user1234 wrote:
 opCmp should return a signed integer. This allows to match well with 
 the x86 flag register and do fast comparison with integers types (in 
 which case just substract rhs to lhs and you're good)
Doing comparison by subtracting is a cute idea, but it doesn't actually work in general because of wraparound. Example: int.min < 1, but int.min - 1 > 0.
druntime does it for integrals smaller than int. For others, you can do: return (a > b) - (b < a);
Nov 03 2020
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/3/20 8:48 AM, Andrei Alexandrescu wrote:
 On 11/3/20 1:56 AM, ag0aep6g wrote:
 On 03.11.20 04:07, user1234 wrote:
 opCmp should return a signed integer. This allows to match well with 
 the x86 flag register and do fast comparison with integers types (in 
 which case just substract rhs to lhs and you're good)
Doing comparison by subtracting is a cute idea, but it doesn't actually work in general because of wraparound. Example: int.min < 1, but int.min - 1 > 0.
druntime does it for integrals smaller than int. For others, you can do: return (a > b) - (b < a);
Ehm. return (a > b) - (a < b);
Nov 03 2020
prev sibling parent reply Dominikus Dittes Scherkl <dominikus scherkl.de> writes:
On Tuesday, 3 November 2020 at 03:07:14 UTC, user1234 wrote:

 opCmp should return a signed integer.
No. opCmp should return a float, to have all 4 possible comparison results available: greater (1) lower (-1) equal (0) and not comparable (NaN) Especially the last one is necessary if you like to have opCmp defined on some not completely ordered set.
Nov 04 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 4 November 2020 at 09:01:21 UTC, Dominikus Dittes 
Scherkl wrote:
 On Tuesday, 3 November 2020 at 03:07:14 UTC, user1234 wrote:

 opCmp should return a signed integer.
No. opCmp should return a float, to have all 4 possible comparison results available: greater (1) lower (-1) equal (0) and not comparable (NaN) Especially the last one is necessary if you like to have opCmp defined on some not completely ordered set.
opCmp can return whatever you want, as long as it is comparable with 0 using the `<`, `>`, `<=`, and `>=` operators: https://dlang.org/spec/operatoroverloading.html#compare IMO there's no reason to use a floating-point number unless you specifically need partial ordering. For the common case of a totally-ordered type, a signed integer is fine.
Nov 04 2020
parent reply Dominikus Dittes Scherkl <dominikus scherkl.de> writes:
On Wednesday, 4 November 2020 at 15:51:04 UTC, Paul Backus wrote:
 opCmp can return whatever you want, [...]
 IMO there's no reason to use a floating-point number unless you 
 specifically need partial ordering. For the common case of a 
 totally-ordered type, a signed integer is fine.
Yeah, but int is 32 bit, same as float. So why use a type that restricts the use cases without any benefit? Simply always use float, so you have no changes if you later detect that your type to compare is in fact _not_ totally ordered (e.g. has some special cases). And beliefe me, for most types you will earlier or later detect, that they are not totally ordered. Today when I look, most libraries do some ugly and non-performant special casing because their comparison operators didn't handle the not-comparable case correctly. In D we can do better, as we CAN handle it. So everybody should be taught to use float as the result of opCmp. The earlier we do it correct, the better for the language!
Nov 08 2020
parent Paul Backus <snarwin gmail.com> writes:
On Sunday, 8 November 2020 at 12:52:14 UTC, Dominikus Dittes 
Scherkl wrote:
 Yeah, but int is 32 bit, same as float. So why use a type that 
 restricts the use cases without any benefit?
For types that are totally ordered, it's easier for the user if they don't have to consider the possibility that opCmp will return NaN.
 Simply always use float, so you have no changes if you later 
 detect that your type to compare is in fact _not_ totally 
 ordered (e.g. has some special cases). And beliefe me, for most 
 types you will earlier or later detect, that they are not 
 totally ordered.
I'm skeptical of the idea that "most" types are partially ordered, but even if they are, so what? The only code that will break if you change the return type of opCmp from int to float after the fact is code that's calling `.opCmp` directly--and you probably *want* that code to break if you're switching from a total order to a partial one.
Nov 08 2020