July 25, 2014
On 7/25/2014 2:55 PM, Jonathan M Davis wrote:
> Doesn't the compiler-generated opEquals do a memcmp when it can?

Yes.

July 25, 2014
On 7/25/2014 2:44 PM, H. S. Teoh via Digitalmars-d wrote:
> Uncommenting the const in opCmp fixes the problem.  WAT?

opCmp must be const in order to be recognized for TypeInfo.

July 25, 2014
On 7/25/2014 3:31 PM, Walter Bright wrote:
> On 7/25/2014 2:44 PM, H. S. Teoh via Digitalmars-d wrote:
>> Uncommenting the const in opCmp fixes the problem.  WAT?
>
> opCmp must be const in order to be recognized for TypeInfo.
>

See https://dlang.org/operatoroverloading#compare
July 25, 2014
On 7/25/2014 2:57 PM, Jonathan M Davis wrote:
> Well, that was the case in 2.065, whereas 2.066 currently gives an error if you
> use a type as a key in an AA without defining opEquals for it. That change needs
> to be reverted.

Do you remember which PR it was?

July 25, 2014
On 7/25/2014 1:47 PM, H. S. Teoh via Digitalmars-d wrote:
> On Fri, Jul 25, 2014 at 06:56:40PM +0000, Jonathan M Davis via Digitalmars-d wrote:
> [...]
>> So, if we remove the new check for a user-defined opEquals when opCmp
>> is defined, then you don't have to define opEquals.
>
> This is even worse, since it may silently introduce runtime breakage.
> The original type may have had opCmp defined just so it can be used with
> AA's, and now after the upgrade to 2.066, suddenly the custom opCmp code
> they wrote specifically to work with AA's doesn't get used anymore, yet
> the compiler silently accepts the code, and the problem won't be found
> until runtime.

Once again,

"The thing is, either this suffers from == behaving differently than AAs, or you've made opEquals superfluous by defining it to be opCmp==0. The latter is a mistake, as Andrei has pointed out, as opCmp may not have a concept of equality, and opEquals may not have a concept of ordering.
I.e. it's not just about AAs."

What you're defending is code of this sort running without error:

  S[T] aa;
  S s;
  aa[t] = s;
  assert(s != aa[t]);



> Which IMO fits the D motto of being correct first, and performant if you
> ask for it.

See the above snippet.

July 25, 2014
On Friday, 25 July 2014 at 22:34:41 UTC, Walter Bright wrote:
> On 7/25/2014 2:57 PM, Jonathan M Davis wrote:
>> Well, that was the case in 2.065, whereas 2.066 currently gives an error if you
>> use a type as a key in an AA without defining opEquals for it. That change needs
>> to be reverted.
>
> Do you remember which PR it was?

No idea, unfortunately. The only reason that I even know about it is this thread and https://issues.dlang.org/show_bug.cgi?id=13179 (which discusses basically the same thing as this thread).

- Jonathan M Davis
July 25, 2014
On Fri, Jul 25, 2014 at 03:33:24PM -0700, Walter Bright via Digitalmars-d wrote:
> On 7/25/2014 3:31 PM, Walter Bright wrote:
> >On 7/25/2014 2:44 PM, H. S. Teoh via Digitalmars-d wrote:
> >>Uncommenting the const in opCmp fixes the problem.  WAT?
> >
> >opCmp must be const in order to be recognized for TypeInfo.
> >
> 
> See https://dlang.org/operatoroverloading#compare

That page doesn't say anything about TypeInfo, though.  But even then, why doesn't the compiler reject opCmp signatures that don't match the compiler's expectations?


T

-- 
It's amazing how careful choice of punctuation can leave you hanging:
July 25, 2014
On 7/25/2014 4:28 PM, H. S. Teoh via Digitalmars-d wrote:
> That page doesn't say anything about TypeInfo, though.

It says to follow the form.

> But even then,
> why doesn't the compiler reject opCmp signatures that don't match the
> compiler's expectations?

Because you may want to use an opCmp for other purposes.

July 26, 2014
On 7/23/14, 9:45 AM, 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
>
> :-(

Getting back to the root of it: I don't think this is a WAT.

Types may choose to define lax ordering comparisons, such as case-insensitive ordering for sorting purposes. Such comparisons create large equivalence classes. Deeming two objects equal, on the other hand, must be quite a bit more stringent.

A WAT would be defining ordering comparison to be case insensitive and then finding stuff in a hashtable that wasn't put there.

Clearly for common arithmetic types, !(a < b) && !(b < a) is the same as a == b. However, that's not the case for a variety of types and orderings. The one relationship between the two operators would be that if a == b then !(a < b) && !(b < a).

I think we should remove the breakage introduced by requiring opEquals if opCmp is defined. It breaks good code for no good reason.


Andrei


July 26, 2014
On 26 July 2014 06:38, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 7/25/2014 4:10 AM, Regan Heath wrote:
>
>> Sure, Andrei makes a valid point .. for a minority of cases.  The
>> majority case
>> will be that opEquals and opCmp==0 will agree.  In those minority cases
>> where
>> they are intended to disagree the user will have intentionally defined
>> both, to
>> be different.  I cannot think of any case where a user will intend for
>> these to
>> be different, then not define both to ensure it.
>>
>
> You've agreed with my point, then, that autogenerating opEquals as memberwise equality (not opCmp==0) if one is not supplied will be correct unless the user code is already broken.
>

No, because there's no obvious reason to define opEquals if you do define opCmp, and the opEq