putting more smarts into a == b

Ary Borenszweig ary at esperanto.org.ar
Sun Sep 27 09:09:43 PDT 2009


Andrei Alexandrescu wrote:
> Frank Benoit wrote:
>> Andrei Alexandrescu schrieb:
>>> 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
>>
>> Hm, i would have expected it not to compile, because A does not have
>> opEquals.
>>
>> In DWT, I cast always first to Object.
>> Java> if( intf1.equals(intf2) ){
>> D1.0> if( ((cast(Object)intf1).opEquals( cast(Object)intf2 )){
> 
> I think in D the cast is inserted automatically. Walter?
> 
> Andrei

Using the compile-time view of Descent, if I have this code:

---
interface I {
	
}

class C {
	
}

int main(char[][] args) {
	C c = new C();
	I i = null;
	
	auto x = i == c;
	auto y = c == i;
	
	return 0;
}
---

the compiler turns it into:

---
interface I {
}

class C: Object {
}

int main(char[][] args) {
	C c = new C;
	I i = null;
	int x = c.opEquals(cast(Object) i);
	int y = c.opEquals(cast(Object) i);
	return 0;
}
---

That's why it doesn't segfault.

Debugging the code it turns out the logic is very simple, it's just 
applying operator overloading: (for the first comparison) "opEquals" is 
searched in "I". Since "opEquals" is not found in it, the compiler 
checks if "opEquals" is commutative. It is, so it searches "opEquals" in 
"C", finds it and does the rewrite. (more or less)



More information about the Digitalmars-d mailing list