tags:

views:

69

answers:

1

Given a simple generic class:

class EqualsQuestion[T]( val value :T )

it seems reasonable that the following code would resolve to "false":

val a = new EqualsQuestion[Int]( 5 )
val b = new EqualsQuestion[Long]( 5 )
a == b

(Yes, it's a contrived example. In my real code I wanted '==' to fail if the type parameters are different, regardless if the values are the same, though at this point I'm not sure that makes sense. Still, it struck me as an interesting Scala question to puzzle through.)

Anyway, I of course haven't been able to implement such an equals() method:

override def equals( obj :Any ) :Boolean = 
{
    obj match {
        case that :EqualsQuestion[T] => 
                ( this.getClass == that.getClass ) &&  // no help
                this.getClass().isInstance(that) && // no help
                //this.value.getClass == that.value.getClass && // doesn't even compile
                this.value == that.value

        case _ => false
    }
}

The issue is type erasure, I know: all the compiler knows at this point is that 'T' is a type, but it has no idea what that type is. So it can't make comparisons.

It seems 2.8 can address this with manifests, but... I'm not quite to point of grokking http://stackoverflow.com/questions/1094173/how-do-i-get-around-type-erasure-on-scala-or-why-cant-i-get-the-type-parameter.

Any other ways around this?

+2  A: 

The following function seems to be able to distinguish between a and b:

def same(x: EqualsQuestion[_], y: EqualsQuestion[_]) = {
  x.value.asInstanceOf[AnyRef].getClass == y.value.asInstanceOf[AnyRef].getClass && 
  x.value == y.value
}

Please note that this works only if T isn't a generic type itself, e.g. it wouldn't distinguish List[Int] and List[Long]. I hope that's good enough...

Landei
Ah! Cast to the lowest level to keep the compiler happy, then the runtime can do the getClass calls. Clever! :-)
Rodney Gitzel