WAT: opCmp and opEquals woes

Timon Gehr via Digitalmars-d digitalmars-d at puremagic.com
Mon Jul 28 12:00:13 PDT 2014


On 07/23/2014 06:45 PM, H. S. Teoh via Digitalmars-d wrote:
> This morning, I discovered this major WAT in D:
>
> ----
> struct S {
>          int x;
>          int y;
>          int opCmp(S s) {
>                  return x - s.x; // compare only x
>          }
> }
> ...

Not even transitive!

void main() {
     auto a=S(~0<<31);
     auto b=S(0);
     auto c=S(1);
     assert(a<b); // OK
     assert(b<c); // OK
     assert(a<c); // FAIL
}

=P


> ...
>
> Why isn't "a==b" rewritten as "a.opCmp(b)==0"?? I'm pretty sure TDPL
> says this is the case (unfortunately I'm at work so I can't check my
> copy of TDPL).
>
> https://issues.dlang.org/show_bug.cgi?id=13179
>
> :-(
> ...

My 5 cents:

There seems to be confusion about whether a.opCmp(b)==0 means that a and 
b are equal, or that a and b are unordered.

1. Based on the current rewrite rules, making operators <= and >= yield 
true if opCmp returns 0, a.opCmp(b)==0 means that a and b are equal, and 
one should follow the following general rules:

a < b ⇔ b > a
a.opCmp(b)==0 ⇒ a == b
a.opCmp(b)<>=0 && a == b ⇒ a.opCmp(b)==0

In particular, if opCmp returns a totally ordered type:

a.opCmp(b) ⇔ a == b

So, rewriting a == b to a.opCmp(b) would make sense in terms of 
semantics, given that opCmp returns such an ordered type.

2. If a.opCmp(b)==0 actually means that a and b are unordered, then <= 
and >= are currently rewritten the wrong way.

This is fixed, by eg making: a <= b → a<b||a.opEquals(b), avoiding 
repeated evaluation of side-effects.

To get the current behaviour of <= and >=, one should then use !> and !<.

To me, the current situation seems to be that DMD assumes meaning 1 and 
Phobos assumes meaning 2.




More information about the Digitalmars-d mailing list