A Fresh Look at Comparisons, Take 2

Steven Schveighoffer schveiguy at yahoo.com
Fri Apr 18 09:11:14 PDT 2008


"Janice Caron" wrote
> On 18/04/2008, Steven Schveighoffer wrote:
>>  I don't really agree that opEquals or opCmp should not be inherited.  I
>>  think normal inheritance the way it is now is just fine.
>
> You do? Why?
>
> You obviously understand that if Z is a
> great-great-great-great-...-grandchild of A, then it will still use
> A's opCmp() function if not overridden? And you're OK with that?

Yes.  That is a choice of the great-great-great-...-grandchild of A's author 
:)  By not overriding opEquals or opCmp, he is saying that if you compare it 
with something else, A's implementation is the one to use.  If he wanted to 
specify that opCmp should be different he would have rewritten opCmp.

>>  You need to have opEquals in Object in order to support hashing.
>
> Please could you elaborate, as I don't understand why this is so?

A hashtable works by putting objects into buckets based on a hash-code. 
Usually you mod the hash-code so it fits in an array.

At that point, you have to deal with collisions.  So a simple method is to 
use a linked list for each bucket.

To look-up that object, you need to traverse the list, finding the object 
that equals the input.

So for example, an int[int], to lookup the int, it first converts to a 
hash-code, finds the right bucket, then traverses the linked list looking 
for the int equal to the key.  Then it returns the value.  So for anything 
to be a key, it must be able to provide a hash, and you must be able to 
check for equality.

>>  The default opCmp should be redefined to throw an exception.
>
> Again, I ask, why? Why detect something at run-time that could be
> detected at compile time?

I think the better solution is to use the interface.  But if that is not 
acceptable, at the very least, the default implementation should throw an 
exception.

>
> Moreover, if Z is a great-great-great-great-...-grandchild of A, then
> it will use A's opCmp() function - not Object's. Overriding opCmp even
> /once/ changes the defaut for the entire heirarchy from that point
> down, and at that point, Object's implementation becomes irrelevant.

The only benefit I see is that you would not have to declare that an object 
implements the interface.  Personally I don't think it's worth it, but I 
could live with it.  The way it is now is completely wrong.

>>  An alternative
>>  is that opCmp is defined in an interface.
>
> Yes, that is an alternative. I had thought of that. But then I
> realised that orderedness can be detected at compile-time without need
> for an interface, so it seemed unnecessary.

It cannot be detected at compile time:

class A
{
   int opCmp(Object o){...}
}

class B: A
{
   int opCmp(Object o)
   { throw new UnOrderedException("cannot order B");}
}

void f(A a, Object o)
{
   a < o; // can you tell at compile time whether a is a B or an A?
}

-Steve 





More information about the Digitalmars-d mailing list