| Thread overview | |||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
September 27, 2009 putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Frank Benoit | 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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | 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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | 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 Re: putting more smarts into a == b | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Frank Benoit | 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
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply