Thread overview
opEquals footprint
Mar 22, 2006
Erik Rasmussen
Mar 22, 2006
xs0
Mar 22, 2006
Erik Rasmussen
Mar 22, 2006
xs0
Mar 22, 2006
Erik Rasmussen
Mar 22, 2006
Sean Kelly
Mar 22, 2006
Sean Kelly
March 22, 2006
I've looked all around in the documentation and forum discussions, and I can't find the answer to this simple, but all-important question:

***** What should the type of the parameter to opEquals be??? *****

I can see two possibilities:

A) Object.  This would force you to check the type of the object passed in as part of your equivalence check.  Could this perhaps be done at compile-time with an is() expression?

B) The same type as the class.  This is fine, but I don't think subclasses properly override the superclass's opEquals implementations when this is the case.

Can someone settle this?  What is the proper way to implement opEquals??

Thanks,
Erik
March 22, 2006
Erik Rasmussen wrote:
> I've looked all around in the documentation and forum discussions, and I can't find the answer to this simple, but all-important question:
> 
> ***** What should the type of the parameter to opEquals be??? *****
> 
> I can see two possibilities:
> 
> A) Object.  This would force you to check the type of the object passed in as part of your equivalence check.  Could this perhaps be done at compile-time with an is() expression?
> 
> B) The same type as the class.  This is fine, but I don't think subclasses properly override the superclass's opEquals implementations when this is the case.
> 
> Can someone settle this?  What is the proper way to implement opEquals??
> 
> Thanks,
> Erik

int opEquals(Object)

so it overrides the default implementation found in, you guessed it, Object :) Same goes for opCmp, I think..


xs0
March 22, 2006
xs0 wrote:
> int opEquals(Object)
> 
> so it overrides the default implementation found in, you guessed it, Object :) Same goes for opCmp, I think..
> 
> 
> xs0

So what's the best way to actually check the type in the opEquals/opCmp method?  Something like...

class A
{
  int opEquals(Object o)
  {
    // check for null
    if(o is null)
      return false;
    // check type
    if(typeid(typeof(o)) != typeid(A))
      return false;
    // cast
    A that = cast(A) o;
    // actually check fields
    return this.a == that.a && this.b == that.b && ...;
  }
}

Or is there a better way?  asserts?

How do you hard-core D programmers usually do it?

Cheers,
Erik
March 22, 2006
Erik Rasmussen wrote:
> xs0 wrote:
>> int opEquals(Object)
>>
>> so it overrides the default implementation found in, you guessed it, Object :) Same goes for opCmp, I think..
>>
>>
>> xs0
> 
> So what's the best way to actually check the type in the opEquals/opCmp method?  Something like...
> 
> class A
> {
>   int opEquals(Object o)
>   {
>     // check for null
>     if(o is null)
>       return false;
>     // check type
>     if(typeid(typeof(o)) != typeid(A))
>       return false;
>     // cast
>     A that = cast(A) o;
>     // actually check fields
>     return this.a == that.a && this.b == that.b && ...;
>   }
> }
> 
> Or is there a better way?  asserts?
> 
> How do you hard-core D programmers usually do it?
> 
> Cheers,
> Erik

Something like this should be ok:

// optional
if (this is o)
    return true;

if (A that = cast(A)o) { // checks for null, too
    return this.a==that.a && ...
} else {
    return false;
}

OTOH, if you want to return false for subclasses, your version seems fine to me.


xs0
March 22, 2006
class A
{
	int opEquals(Object o)
	{
		A a = cast(A) o;

		if (a is null)
			return false;
		else
			return this.member1 == a.member1;
	}
}

Casting will return null if it fails, so to speak (so you definitely need to check after it for null.)  Typeof will always give "Object" for o since that's its compile-time type.

-[Unknown]


> xs0 wrote:
>> int opEquals(Object)
>>
>> so it overrides the default implementation found in, you guessed it, Object :) Same goes for opCmp, I think..
>>
>>
>> xs0
> 
> So what's the best way to actually check the type in the opEquals/opCmp method?  Something like...
> 
> class A
> {
>   int opEquals(Object o)
>   {
>     // check for null
>     if(o is null)
>       return false;
>     // check type
>     if(typeid(typeof(o)) != typeid(A))
>       return false;
>     // cast
>     A that = cast(A) o;
>     // actually check fields
>     return this.a == that.a && this.b == that.b && ...;
>   }
> }
> 
> Or is there a better way?  asserts?
> 
> How do you hard-core D programmers usually do it?
> 
> Cheers,
> Erik
March 22, 2006
xs0 wrote:
> Erik Rasmussen wrote:
> 
>> xs0 wrote:
>>
>>> int opEquals(Object)
>>>
>>> so it overrides the default implementation found in, you guessed it, Object :) Same goes for opCmp, I think..
>>>
>>>
>>> xs0
>>
>>
>> So what's the best way to actually check the type in the opEquals/opCmp method?  Something like...
>>
>> class A
>> {
>>   int opEquals(Object o)
>>   {
>>     // check for null
>>     if(o is null)
>>       return false;
>>     // check type
>>     if(typeid(typeof(o)) != typeid(A))
>>       return false;
>>     // cast
>>     A that = cast(A) o;
>>     // actually check fields
>>     return this.a == that.a && this.b == that.b && ...;
>>   }
>> }
>>
>> Or is there a better way?  asserts?
>>
>> How do you hard-core D programmers usually do it?
>>
>> Cheers,
>> Erik
> 
> 
> Something like this should be ok:
> 
> // optional
> if (this is o)
>     return true;
> 
> if (A that = cast(A)o) { // checks for null, too
>     return this.a==that.a && ...
> } else {
>     return false;
> }
> 
> OTOH, if you want to return false for subclasses, your version seems fine to me.
> 
> 
> xs0

No, I definitely don't want it to return false for subclasses!

That "failed cast returns null" trick is handy.  That's waaay better than all that typeid(typeof()) crap.  Thanks guys.

Erik
March 22, 2006
xs0 wrote:
> 
> int opEquals(Object)
> 
> so it overrides the default implementation found in, you guessed it, Object :) Same goes for opCmp, I think..

It's probably worth also supplying overloads for the class in question, as you don't want to cast if you don't have to:

class A
{
    int opEquals(Object o)
    {
        A a = cast(A) o;

        if (a is null)
            return false;
        else
            return *this == a;
    }
}
March 22, 2006
Forgot the second overload.


Sean Kelly wrote:
> xs0 wrote:
>>
>> int opEquals(Object)
>>
>> so it overrides the default implementation found in, you guessed it, Object :) Same goes for opCmp, I think..
> 
> It's probably worth also supplying overloads for the class in question, as you don't want to cast if you don't have to:
> 
> class A
> {
>     int opEquals(Object o)
>     {
>         A a = cast(A) o;
> 
>         if (a is null)
>             return false;
>         else
>             return *this == a;
>     }

      int opEquals( A a )
      {
          return member1 == a.member1;
      }
> }