The problem with your example is that you only override the equals
method of the anonymous class you define your specific tuple to be part of. Let's take a closer look at what you are doing when running the code you have given here.
val p = new Pair(1, 2) {
override def equals(obj:Any) = {
obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1
}
}
What Scala does here is it creates a new anonymous class which extends Pair
and overrides its equals. So this is equivalent to running the following code:
class Foo extends Pair(1,2) {
override def equals(obj:Any) = {
obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1
}
}
val p = new Foo
And here is where you can see exactly where the problem lies! The definition of equals
is not symmetric. p == (1,1)
evaluates to true
and (1,1) == p
evaluates to false
! This is because the former is equivalent to p.equals((1,1))
while the latter is equivalent to (1,1).equals(p)
. In the example you have given, it doesn't work because the object in the case is compared with the object being matched, and not the other way around. Therefore, as you have indicated, Pair.unapply(p).get == (1, 1)
evaluates to true
, however (1,1) == Pair.unapply(p).get
evaluates to false
, and it seems that the latter is the one used when matching.
However, in any case creating an equals that is not symmetric is a really really bad idea as the execution of the code depends on the order you compare objects in. Furthermore, the equals you have defined has a further problem -- it fails with error when you try to compare your p
with any Pair
that is not of type (Int, Int)
. This is because, after type erasure (which is how the JVM implements generics), a Pair
is no longer parametrised by the types of its constituents. Therefore, (Int, Int)
has exactly the same type as (String, String)
and thus, the following code will fail with error:
p == ("foo", "bar")
as Scala will try to cast a (String, String)
to an (Int, Int)
.
If you want to implement this functionality, the easiest thing you could do is to use the pimp my library pattern, pimping a Pair
. However, you shouldn't call your method equals
. Call it something else, like ~=
. I have to be going now, however when I come back I could give you the code for it. It's pretty easy. You should look at the implementation of equals
in a pair and remove the part that compares the second argument :)