Jump to page: 1 217  
Page
Thread overview
WAT: opCmp and opEquals woes
Jul 23, 2014
H. S. Teoh
Jul 23, 2014
Ary Borenszweig
Jul 23, 2014
Dicebot
Jul 23, 2014
David Gileadi
Jul 23, 2014
Ali Çehreli
Jul 23, 2014
Dicebot
Jul 23, 2014
H. S. Teoh
Jul 23, 2014
Brad Roberts
Jul 24, 2014
Jonathan M Davis
Jul 24, 2014
Jonathan M Davis
Jul 24, 2014
deadalnix
Jul 24, 2014
Jonathan M Davis
Aug 16, 2014
Fool
Jul 23, 2014
Brian Schott
Oct 15, 2014
Martin Nowak
Oct 15, 2014
Marco Leise
Jul 24, 2014
Jonathan M Davis
Jul 24, 2014
Jonathan M Davis
Jul 24, 2014
H. S. Teoh
Jul 24, 2014
Dicebot
Jul 24, 2014
w0rp
Jul 24, 2014
Jonathan M Davis
Jul 24, 2014
Jonathan M Davis
Jul 24, 2014
H. S. Teoh
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Walter Bright
Jul 25, 2014
Manu
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Walter Bright
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Walter Bright
Aug 17, 2014
deadalnix
Jul 25, 2014
H. S. Teoh
Re: opCmp and opEquals woes
Jul 25, 2014
Daniel Murphy
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Daniel Gibson
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Marc Schütz
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Walter Bright
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Walter Bright
Jul 25, 2014
Walter Bright
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Walter Bright
Jul 28, 2014
Iain Buclaw
Jul 25, 2014
Walter Bright
Re: opCmp and opEquals woes
Jul 25, 2014
Daniel Murphy
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Daniel Murphy
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Walter Bright
Jul 25, 2014
Manu
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Walter Bright
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Walter Bright
Jul 25, 2014
Ary Borenszweig
Jul 25, 2014
Walter Bright
Jul 26, 2014
Manu
Jul 26, 2014
Walter Bright
Jul 26, 2014
H. S. Teoh
Jul 26, 2014
Manu
Jul 26, 2014
Marc Schütz
Jul 26, 2014
Marc Schütz
Jul 26, 2014
Marc Schütz
Jul 27, 2014
Manu
Re: opCmp and opEquals woes
Jul 27, 2014
Tobias Müller
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Walter Bright
Jul 25, 2014
Regan Heath
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Tobias Pankrath
Jul 25, 2014
Tobias Pankrath
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Walter Bright
Jul 26, 2014
Manu
Jul 26, 2014
Manu
Jul 26, 2014
Walter Bright
Jul 26, 2014
H. S. Teoh
Jul 26, 2014
Walter Bright
Jul 27, 2014
H. S. Teoh
Jul 27, 2014
Fool
Jul 27, 2014
Fool
Jul 27, 2014
Fool
Jul 27, 2014
Fool
Jul 28, 2014
Fool
Jul 28, 2014
H. S. Teoh
Jul 28, 2014
Fool
Jul 28, 2014
Ola Fosheim Gr
Jul 28, 2014
Don
Jul 27, 2014
Walter Bright
Jul 26, 2014
Fool
Jul 26, 2014
Fool
Jul 27, 2014
Fool
Jul 27, 2014
Ola Fosheim Gr
Jul 27, 2014
Fool
Jul 28, 2014
Regan Heath
Jul 28, 2014
Regan Heath
Jul 25, 2014
Jonathan M Davis
Re: opCmp and opEquals woes
Jul 25, 2014
Daniel Murphy
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Manu
Jul 25, 2014
Walter Bright
Jul 25, 2014
Daniel Gibson
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Walter Bright
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Walter Bright
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Walter Bright
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Marc Schütz
Jul 25, 2014
Daniel Gibson
Jul 25, 2014
Marc Schütz
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Walter Bright
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Walter Bright
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
Jacob Carlborg
Jul 25, 2014
Jonathan M Davis
Jul 25, 2014
H. S. Teoh
Jul 25, 2014
Walter Bright
Jul 25, 2014
Walter Bright
Jul 26, 2014
H. S. Teoh
Jul 26, 2014
Walter Bright
Jul 28, 2014
Timon Gehr
July 23, 2014
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
        }
}

void main() {
        auto s1 = S(1,2);
        auto s2 = S(1,3);
        auto s3 = S(2,1);

        assert(s1 < s3); // OK
        assert(s2 < s3); // OK
        assert(s3 > s1); // OK
        assert(s3 > s2); // OK
        assert(s1 <= s2 && s2 >= s1); // OK
        assert(s1 == s2); // FAIL -- WAT??
}
----

The reason for this is that the <, <=, >=, > operators are defined in terms of opCmp (which, btw, is defined to return 0 when the objects being compared are equal), but == is defined in terms of opEquals. When opEquals is not defined, it defaults to the built-in compiler definition, which is a membership equality test, even if opCmp *is* defined, and returns 0 when the objects are equal.

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

:-(


T

-- 
English has the lovely word "defenestrate", meaning "to execute by throwing someone out a window", or more recently "to remove Windows from a computer and replace it with something useful". :-) -- John Cowan
July 23, 2014
On 7/23/14, 1: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
>          }
> }
>
> void main() {
>          auto s1 = S(1,2);
>          auto s2 = S(1,3);
>          auto s3 = S(2,1);
>
>          assert(s1 < s3); // OK
>          assert(s2 < s3); // OK
>          assert(s3 > s1); // OK
>          assert(s3 > s2); // OK
>          assert(s1 <= s2 && s2 >= s1); // OK
>          assert(s1 == s2); // FAIL -- WAT??
> }
> ----
>
> The reason for this is that the <, <=, >=, > operators are defined in
> terms of opCmp (which, btw, is defined to return 0 when the objects
> being compared are equal), but == is defined in terms of opEquals. When
> opEquals is not defined, it defaults to the built-in compiler
> definition, which is a membership equality test, even if opCmp *is*
> defined, and returns 0 when the objects are equal.
>
> 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
>
> :-(
>
>
> T

Imagine you have a list of integers and strings denoting integers: [1, "2", 100, "38"]. Now you want to sort them according to their numeric value. Of course, 1 and "1" would have the same order. However, 1 and "1" are different, so "==" would give false, while 1.opCmp("1") would give 0.

Equality and comparison are different. opCmp is used for sorting objects, which has nothing to do with equality. Inferring equality from opCmp is wrong in my opinion.
July 23, 2014
On Wednesday, 23 July 2014 at 17:15:12 UTC, Ary Borenszweig wrote:
> Imagine you have a list of integers and strings denoting integers: [1, "2", 100, "38"]. Now you want to sort them according to their numeric value. Of course, 1 and "1" would have the same order. However, 1 and "1" are different, so "==" would give false, while 1.opCmp("1") would give 0.
>
> Equality and comparison are different. opCmp is used for sorting objects, which has nothing to do with equality. Inferring equality from opCmp is wrong in my opinion.

Well this is why you can actually override those :) I think automatic opCmd -> opEqual generation covers vast majority of use cases and as such will have a vary good effort / decreased annoyance ratio.
July 23, 2014
On 7/23/14, 11:09 AM, Dicebot wrote:
> On Wednesday, 23 July 2014 at 17:15:12 UTC, Ary Borenszweig wrote:
>> Imagine you have a list of integers and strings denoting integers: [1,
>> "2", 100, "38"]. Now you want to sort them according to their numeric
>> value. Of course, 1 and "1" would have the same order. However, 1 and
>> "1" are different, so "==" would give false, while 1.opCmp("1") would
>> give 0.
>>
>> Equality and comparison are different. opCmp is used for sorting
>> objects, which has nothing to do with equality. Inferring equality
>> from opCmp is wrong in my opinion.
>
> Well this is why you can actually override those :) I think automatic
> opCmd -> opEqual generation covers vast majority of use cases and as
> such will have a vary good effort / decreased annoyance ratio.

I agree. In fact I think if you've implemented opCmp to sort 1 and "1" as equal that in most cases you'd expect "1" and 1 to compare as logically equal. Automatic opCmp -> opEquals seems like a very sane default to me.
July 23, 2014
On 7/23/14, 9:45 AM, H. S. Teoh via Digitalmars-d wrote:
> 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
>
> :-(

It's a good decision. There are types that are comparable for equality but not compared for ordering. -- Andrei

July 23, 2014
On 7/23/14, 11:09 AM, Dicebot wrote:
> On Wednesday, 23 July 2014 at 17:15:12 UTC, Ary Borenszweig wrote:
>> Imagine you have a list of integers and strings denoting integers: [1,
>> "2", 100, "38"]. Now you want to sort them according to their numeric
>> value. Of course, 1 and "1" would have the same order. However, 1 and
>> "1" are different, so "==" would give false, while 1.opCmp("1") would
>> give 0.
>>
>> Equality and comparison are different. opCmp is used for sorting
>> objects, which has nothing to do with equality. Inferring equality
>> from opCmp is wrong in my opinion.
>
> Well this is why you can actually override those :) I think automatic
> opCmd -> opEqual generation covers vast majority of use cases and as
> such will have a vary good effort / decreased annoyance ratio.

I'd say let's leave things as they are. opEquals may need to do less work than opCmp, and it often sees intensive use. -- Andrei
July 23, 2014
On 07/23/2014 11:26 AM, David Gileadi wrote:
> On 7/23/14, 11:09 AM, Dicebot wrote:
>> On Wednesday, 23 July 2014 at 17:15:12 UTC, Ary Borenszweig wrote:
>>> Imagine you have a list of integers and strings denoting integers: [1,
>>> "2", 100, "38"]. Now you want to sort them according to their numeric
>>> value. Of course, 1 and "1" would have the same order. However, 1 and
>>> "1" are different, so "==" would give false, while 1.opCmp("1") would
>>> give 0.
>>>
>>> Equality and comparison are different. opCmp is used for sorting
>>> objects, which has nothing to do with equality. Inferring equality
>>> from opCmp is wrong in my opinion.
>>
>> Well this is why you can actually override those :) I think automatic
>> opCmd -> opEqual generation covers vast majority of use cases and as
>> such will have a vary good effort / decreased annoyance ratio.
>
> I agree. In fact I think if you've implemented opCmp to sort 1 and "1"
> as equal that in most cases you'd expect "1" and 1 to compare as
> logically equal. Automatic opCmp -> opEquals seems like a very sane
> default to me.

To add, C++ is getting "= default" versions:

  http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3950.html

Ali

July 23, 2014
On Wednesday, 23 July 2014 at 18:49:49 UTC, Andrei Alexandrescu wrote:
> I'd say let's leave things as they are. opEquals may need to do less work than opCmp, and it often sees intensive use. -- Andrei

You will be the one answering user complaints ;)
July 23, 2014
On Wed, Jul 23, 2014 at 11:49:58AM -0700, Andrei Alexandrescu via Digitalmars-d wrote:
> On 7/23/14, 11:09 AM, Dicebot wrote:
> >On Wednesday, 23 July 2014 at 17:15:12 UTC, Ary Borenszweig wrote:
> >>Imagine you have a list of integers and strings denoting integers: [1, "2", 100, "38"]. Now you want to sort them according to their numeric value. Of course, 1 and "1" would have the same order. However, 1 and "1" are different, so "==" would give false, while 1.opCmp("1") would give 0.
> >>
> >>Equality and comparison are different. opCmp is used for sorting objects, which has nothing to do with equality. Inferring equality from opCmp is wrong in my opinion.
> >
> >Well this is why you can actually override those :) I think automatic opCmd -> opEqual generation covers vast majority of use cases and as such will have a vary good effort / decreased annoyance ratio.
> 
> I'd say let's leave things as they are. opEquals may need to do less work than opCmp, and it often sees intensive use. -- Andrei

If autogenerating opEquals to be opCmp()==0 is a no-go, then I'd much rather say it should be a compile error if the user defines opCmp but not opEquals. Currently, we have the bad situation where == behaves inconsistently w.r.t. <, <=, >=, > because we allow opCmp to be defined but opEquals not, and the default compiler implementation of opEquals may or may not match the meaning of opCmp.

In short, what I'd like to see, in order of preference, is:

(1) If opCmp is defined but opEquals not, then opEquals should be
defined to be opCmp()==0.

(2) If (1) is a no-go, then the next best situation is that if opCmp is defined but opEquals isn't, then the compiler should issue an error, rather than implicitly generating a default opEquals that probably does not match the programmer's expectations.

(3) If (2) is also a no-go, the 3rd best situation is that if opCmp is defined but opEquals isn't, then the compiler should issue an error if the user ever writes "a==b". That is, we allow the user to not define opEquals as long as it's not actually used, but it's an error if it is used.

(4) Do nothing, and allow the current hidden breakage to perpetuate and make people hate D when they suddenly discover it when they forget to implement opEquals.

I really hope we don't have to resort to (4).


T

-- 
All men are mortal. Socrates is mortal. Therefore all men are Socrates.
July 23, 2014
As of about 2 minutes ago, D-Scanner can help with this.

---
struct A {
	int opCmp() const;
}
---

$ ./dscanner --styleCheck ~/tmp/test.d
test.d(1:8)[warn]: 'A' has method 'opCmp', but not 'opEquals'.
« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10 11