Thread overview
opEquals default behaviour - poorly documented or am I missing something?
Nov 17, 2015
MichaelZ
Nov 17, 2015
Ali Çehreli
Nov 17, 2015
user123ABCabc
Nov 19, 2015
Jonathan M Davis
Nov 18, 2015
MichaelZ
November 17, 2015
In http://dlang.org/operatoroverloading.html#eqcmp it is stated that

"If opEquals is not specified, the compiler provides a default version that does member-wise comparison."

However, doesn't this only apply to structs, and not objects?  The default behaviour of opEquals for objects seems to be "is".


A few paragraphs later, in http://dlang.org/operatoroverloading.html#compare, the description of the default version is repeated:
""
If overriding Object.opCmp() for classes, the class member function signature should look like:
...
If structs declare an opCmp member function, it should have the following form:
...
Note that opCmp is only used for the inequality operators; expressions like a == b always uses opEquals. **If opCmp is defined but opEquals isn't, the compiler will supply a default version of opEquals that performs member-wise comparison.**
""

Even here, the fact that the described default opEquals behaviour appears to only apply to structs is far from clear.


Or am I missing something that should be obvious?

Thanks,
-- MichaelZ
November 17, 2015
On 11/17/2015 12:40 AM, MichaelZ wrote:
> In http://dlang.org/operatoroverloading.html#eqcmp it is stated that
>
> "If opEquals is not specified, the compiler provides a default version
> that does member-wise comparison."
>
> However, doesn't this only apply to structs, and not objects?

Correct. The behavior for class objects is the following algorithm on the same page:

  http://dlang.org/operatoroverloading.html#equals

This one:

bool opEquals(Object a, Object b)
{
    if (a is b) return true;
    if (a is null || b is null) return false;
    if (typeid(a) == typeid(b)) return a.opEquals(b);
    return a.opEquals(b) && b.opEquals(a);
}

Ali

November 17, 2015
On Tuesday, 17 November 2015 at 19:44:36 UTC, Ali Çehreli wrote:
>     if (typeid(a) == typeid(b)) return a.opEquals(b);

Wow this is terrible to compare two objects in D. The line I quoted means that two TypeInfoClass are likely to be allocated, right ?

But usually when comparing objects one rather cares about the reference itself, so a comparison of the two heap addresses is enough in this case. (meaning same or not same instance, regardless of the their members values).


November 17, 2015
On 11/17/15 3:25 PM, user123ABCabc wrote:
> On Tuesday, 17 November 2015 at 19:44:36 UTC, Ali Çehreli wrote:
>>     if (typeid(a) == typeid(b)) return a.opEquals(b);
>
> Wow this is terrible to compare two objects in D. The line I quoted
> means that two TypeInfoClass are likely to be allocated, right ?

No, those are immutable stored in the data segment. Fetching them costs only doing the fetch of the class info pointer.

-Steve
November 18, 2015
On Tuesday, 17 November 2015 at 19:44:36 UTC, Ali Çehreli wrote:
> On 11/17/2015 12:40 AM, MichaelZ wrote:
> > In http://dlang.org/operatoroverloading.html#eqcmp it is
> stated that
> >
> > "If opEquals is not specified, the compiler provides a
> default version
> > that does member-wise comparison."
> >
> > However, doesn't this only apply to structs, and not objects?
>
> Correct. The behavior for class objects is the following algorithm on the same page:
>
>   http://dlang.org/operatoroverloading.html#equals
>
> This one:
>
> bool opEquals(Object a, Object b)
> {
>     if (a is b) return true;
>     if (a is null || b is null) return false;
>     if (typeid(a) == typeid(b)) return a.opEquals(b);
>     return a.opEquals(b) && b.opEquals(a);
> }

Sure, but that defers to the a.opEquals / b.opEquals in many the interesting cases :)  Which comes back to the original point: that I feel the documentation I quoted is at least easily misunderstood, if not straight out wrong.
November 19, 2015
On Tuesday, November 17, 2015 20:25:30 user123ABCabc via Digitalmars-d-learn wrote:
> On Tuesday, 17 November 2015 at 19:44:36 UTC, Ali Çehreli wrote:
> >     if (typeid(a) == typeid(b)) return a.opEquals(b);
>
> Wow this is terrible to compare two objects in D. The line I quoted means that two TypeInfoClass are likely to be allocated, right ?

No. As Steven points out. No allocation takes place.

> But usually when comparing objects one rather cares about the reference itself, so a comparison of the two heap addresses is enough in this case. (meaning same or not same instance, regardless of the their members values).

Really? I would have expected caring about reference equality to be the _rare_ case rather than the common one. And if that's what you want, == isn't the right operator to use anyway. That's what the is operator is for. Regardless, as the code posted by Ali indicates, the free function opEquals that gets called by == for classes does check whether they're the same object first by using the is operator, so all of the other checking is only done if they're not the same object.

- Jonathan M Davis