Jump to page: 1 2
Thread overview
putting more smarts into a == b
Sep 27, 2009
Christopher Wright
Sep 27, 2009
bearophile
Sep 27, 2009
Ary Borenszweig
Sep 27, 2009
Robert Jacques
Sep 27, 2009
Robert Jacques
Sep 27, 2009
Frank Benoit
Sep 27, 2009
Frank Benoit
Sep 27, 2009
Frank Benoit
Sep 27, 2009
Frank Benoit
Sep 27, 2009
Ary Borenszweig
September 27, 2009
Consider two objects a and b with a of class type. Currently, the expression a == b is blindly rewritten as a.opEquals(b). I argue it should be rewritten into a call to an (imaginary/inlined) function equalObjects(a, b), with the following definition:

bool equalObjects(T, U)(T a, U b) if (is(T == class))
{
    static if (is(U == class))
    {
        if (b is null) return a is null;
        if (a is null) return b is null;
    }
    else
    {
        enforce(a !is null);
    }
    return a.opEquals(b);
}

This hoists the identity test outside the opEquals call and also deals with null references. What do you think?


Andrei
September 27, 2009
On Sat, Sep 26, 2009 at 9:32 PM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> Consider two objects a and b with a of class type. Currently, the expression
> a == b is blindly rewritten as a.opEquals(b). I argue it should be rewritten
> into a call to an (imaginary/inlined) function equalObjects(a, b), with the
> following definition:
>
> bool equalObjects(T, U)(T a, U b) if (is(T == class))
> {
>    static if (is(U == class))
>    {
>        if (b is null) return a is null;
>        if (a is null) return b is null;
>    }
>    else
>    {
>        enforce(a !is null);
>    }
>    return a.opEquals(b);
> }
>
> This hoists the identity test outside the opEquals call and also deals with null references. What do you think?

I'm almost sure that C# does this already, and it's a useful behavior.

Of course, with nonnull types, the check for null wouldn't even need to exiiiiiiiist.... ;)
September 27, 2009
Andrei Alexandrescu:

> This hoists the identity test outside the opEquals call and also deals with null references. What do you think?

I like it, is also saves some boring code.

Bye,
bearophile
September 27, 2009
Andrei Alexandrescu wrote:
> Consider two objects a and b with a of class type. Currently, the expression a == b is blindly rewritten as a.opEquals(b). I argue it should be rewritten into a call to an (imaginary/inlined) function equalObjects(a, b)

Definitely!
September 27, 2009
On Sat, 26 Sep 2009 21:32:13 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> Consider two objects a and b with a of class type. Currently, the expression a == b is blindly rewritten as a.opEquals(b). I argue it should be rewritten into a call to an (imaginary/inlined) function equalObjects(a, b), with the following definition:
>
> bool equalObjects(T, U)(T a, U b) if (is(T == class))
> {
>      static if (is(U == class))
>      {
>          if (b is null) return a is null;
>          if (a is null) return b is null;
>      }
>      else
>      {
>          enforce(a !is null);
>      }
>      return a.opEquals(b);
> }
>
> This hoists the identity test outside the opEquals call and also deals with null references. What do you think?
>
>
> Andrei

I like this. I think optimizing away opEquals for identical objects would also be a good idea:

static if (is(U == class))
	if(a is b || a is null || b  is null) return a is b;
else
	enforce(a !is null);
September 27, 2009
Andrei Alexandrescu schrieb:
> Consider two objects a and b with a of class type. Currently, the
> expression a == b is blindly rewritten as a.opEquals(b). I argue it
> should be rewritten into a call to an (imaginary/inlined) function
> equalObjects(a, b), with the following definition:
> 
> bool equalObjects(T, U)(T a, U b) if (is(T == class))
> {
>     static if (is(U == class))
>     {
>         if (b is null) return a is null;
>         if (a is null) return b is null;
>     }
>     else
>     {
>         enforce(a !is null);
>     }
>     return a.opEquals(b);
> }
> 
> This hoists the identity test outside the opEquals call and also deals with null references. What do you think?
> 
> 
> Andrei

What about interfaces?
September 27, 2009
Frank Benoit schrieb:
> What about interfaces?

I mean, this is a point that annoyes me a lot in D, that interfaces (instances) cannot be treated like objects. I cannot do

if( someiface == someobj ){ ... }

With that technique, the compiler could do a dynamic cast to Object in place, do the null checks and then call opEquals.

Certainly, this should also work for the other methods of Objects like toHash, toString, ...
September 27, 2009
Jarrett Billingsley wrote:
> On Sat, Sep 26, 2009 at 9:32 PM, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>> Consider two objects a and b with a of class type. Currently, the expression
>> a == b is blindly rewritten as a.opEquals(b). I argue it should be rewritten
>> into a call to an (imaginary/inlined) function equalObjects(a, b), with the
>> following definition:
>>
>> bool equalObjects(T, U)(T a, U b) if (is(T == class))
>> {
>>    static if (is(U == class))
>>    {
>>        if (b is null) return a is null;
>>        if (a is null) return b is null;
>>    }
>>    else
>>    {
>>        enforce(a !is null);
>>    }
>>    return a.opEquals(b);
>> }
>>
>> This hoists the identity test outside the opEquals call and also deals with
>> null references. What do you think?
> 
> I'm almost sure that C# does this already, and it's a useful behavior.

C# operator overloads are of the form:
public static ReturnType operator+(Arg1 arg1, Arg2 arg2) {}

Object.operator== is defined to call arg1.Equals(arg2) if arg1 isn't null. But this isn't a feature of operator overloads.

> Of course, with nonnull types, the check for null wouldn't even need
> to exiiiiiiiist.... ;)

How clever and insightful of you!
September 27, 2009
Robert Jacques wrote:
> On Sat, 26 Sep 2009 21:32:13 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> 
>> Consider two objects a and b with a of class type. Currently, the expression a == b is blindly rewritten as a.opEquals(b). I argue it should be rewritten into a call to an (imaginary/inlined) function equalObjects(a, b), with the following definition:
>>
>> bool equalObjects(T, U)(T a, U b) if (is(T == class))
>> {
>>      static if (is(U == class))
>>      {
>>          if (b is null) return a is null;
>>          if (a is null) return b is null;
>>      }
>>      else
>>      {
>>          enforce(a !is null);
>>      }
>>      return a.opEquals(b);
>> }
>>
>> This hoists the identity test outside the opEquals call and also deals with null references. What do you think?
>>
>>
>> Andrei
> 
> I like this. I think optimizing away opEquals for identical objects would also be a good idea:
> 
> static if (is(U == class))
>     if(a is b || a is null || b  is null) return a is b;
> else
>     enforce(a !is null);

This code has an inefficiency, it seems, because it makes a bit more checks than necessary (e.g. checks a is b twice). Let's simplify:

bool equalObjects(T, U)(T a, U b) if (is(T == class))
{
     static if (is(U == class))
     {
         if (a is b) return true;
         if (b is null || a is null) return false;
     }
     else
     {
         enforce(a !is null);
     }
     return a.opEquals(b);
}


Andrei
September 27, 2009
Frank Benoit wrote:
> Andrei Alexandrescu schrieb:
>> Consider two objects a and b with a of class type. Currently, the
>> expression a == b is blindly rewritten as a.opEquals(b). I argue it
>> should be rewritten into a call to an (imaginary/inlined) function
>> equalObjects(a, b), with the following definition:
>>
>> bool equalObjects(T, U)(T a, U b) if (is(T == class))
>> {
>>     static if (is(U == class))
>>     {
>>         if (b is null) return a is null;
>>         if (a is null) return b is null;
>>     }
>>     else
>>     {
>>         enforce(a !is null);
>>     }
>>     return a.opEquals(b);
>> }
>>
>> This hoists the identity test outside the opEquals call and also deals
>> with null references. What do you think?
>>
>>
>> Andrei
> 
> What about interfaces?

Good question! What do they do now? I ran this:

interface A {}
class Widget : A {}

void main() {
    auto a = cast(A) new Widget;
    A b = null;
    writeln(a == b);
    writeln(b == a);
}

To my surprise, the program printed false twice. If I replace A with Widget inside main, the program prints false then crashes with the mythical segfault :o).

So how are interfaces compared?


Andrei
« First   ‹ Prev
1 2