Here is some insight to what happens behind the scene. Consider this code:
class Test {
new Object match { case x: Seq[Int] => true }
new Object match { case Seq(1) => true }
}
If you compile with scalac -Xprint:12 -unchecked
, you'll see the code just before the erasure phase (id 13). For the first type pattern, you will see something like:
<synthetic> val temp1: java.lang.Object = new java.lang.Object();
if (temp1.isInstanceOf[Seq[Int]]())
For the Seq
extractor pattern, you will see something like:
<synthetic> val temp3: java.lang.Object = new java.lang.Object();
if (temp3.isInstanceOf[Seq[A]]()) {
<synthetic> val temp4: Seq[A] = temp3.asInstanceOf[Seq[A]]();
<synthetic> val temp5: Some[Seq[A]] = collection.this.Seq.unapplySeq[A](temp4);
// ...
}
In both cases, there is a type test to see if the object is of type Seq
(Seq[Int]
and Seq[A]
). Type parameters will be eliminated during the erasure phase. Thus the warning. Even though the second may be unexpected, it does make sense to check the type since if object is not of type Seq
that clause won't match and the JVM can proceed to the next clause. If the type does match, then the object can be casted to Seq
and unapplySeq
can be called.
RE: thoredge comment on the type check. May be we are talking about different things. I was merely saying that:
(o: Object) match {
case Seq(i) => println("seq " + i)
case Array(i) => println("array " + i)
}
translates to something like:
if (o.isInstanceOf[Seq[_]]) { // type check
val temp1 = o.asInstanceOf[Seq[_]] // cast
// verify that temp1 is of length 1 and println("seq " + temp1(0))
} else if (o.isInstanceOf[Array[_]]) { // type check
val temp1 = o.asInstanceOf[Array[_]] // cast
// verify that temp1 is of length 1 and println("array " + temp1(0))
}
The type check is used so that when the cast is done there is no class cast exception.
Whether the warning non variable type-argument A in type pattern Seq[A] is unchecked since it is eliminated by erasure is justified and whether there would be cases where there could be class cast exception even with the type check, I don't know.
Edit: here is an example:
object SeqSumIs10 {
def unapply(seq: Seq[Int]) = if (seq.sum == 10) Some(seq) else None
}
(Seq("a"): Object) match {
case SeqSumIs10(seq) => println("seq.sum is 10 " + seq)
}
// ClassCastException: java.lang.String cannot be cast to java.lang.Integer