Reputation: 4992
I have the following class hierarchy:
class A
class B extends A
class C extends A
then, there is another class which takes instances of these classes and there is a method, in which two cases of pattern-matching are possible like this:
class D (one: A, two: A) {
def work {
(one, two) match {
case (o, t): (B, B) => ... blablabla
case (o, t): (B, C) => ... blablabla
case _ =>
}
}
}
However, when it should resolve the matching in favor of the second case (B, C)
, it tries resolving it as (B, B)
and comes up with the class cast exception that C cannot be cast to B
. Why? What to do? How can I come around this?
Upvotes: 24
Views: 33795
Reputation: 2829
The problem, as always, is erased types. (B,C)
is syntactic sugar for Tuple2[B,C]
, which is erased to Tuple2
at runtime. The case statement verifies that (B,C)
matches Tuple2
, but then fails to cast it.
In your case, the easiest solution would be to match against 'one' and 'two' individually, rather than wrapping them in a tuple:
one match {
case o : B => two match {
case p : C => ...
case p : B => ...
}
...
}
It's not so pretty, but it won't suffer from the same problems.
Edit: Actually, I'd go with Brian Smith's solution - matching inside the tuple rather than outside. It avoids the problem in a similar way, but looks nicer.
Upvotes: 9
Reputation: 3381
Your syntax isn't quite right (doesn't compile).
This works though:
object Matcher extends App {
class A
class B extends A
class C extends A
class D(one: A, two: A) {
def work {
(one, two) match {
case (o: B, t: B) => println("B")
case (o: B, t: C) => println("C")
case _ =>
}
}
}
val d1 = new D(new B, new B)
val d2 = new D(new B, new C)
d1.work
//B
d2.work
//C
}
Upvotes: 33
Reputation: 3608
I made this code work.
Firstly I added a case to your class definition.
case class A
case class B extends A
case class C extends A
Secondly I changed the work
.
class D(one: A, two: A) {
def work {
(one, two) match {
case (o: B, t: B) => println("BB")
case (o: B, t: C) => println("BC")
case (o: C, t: C) => println("CC")
case _ => println("AA")
}
}
}
Now what I got:
new D(B(),B()).work => BB
new D(B(),C()).work => BC
new D(C(),C()).work => CC
new D(A(),B()).work => AA
The case
adds an apply and an unapply method.
Upvotes: 3