Playing around with a reflection-base code I've come a cross a situation where I want to convert a sequence into array. The catch is that the only type information available is in the form of a runtime.universe.Type
, and the sequence itself is of type Seq[Any]
.
I attempted to call the toArray
method on the Seq, which requires a ClassTag
that I don't have. Naively I just created a ClassTag[Any]
out of the runtime Type, like this:
import scala.reflect.runtime.{universe => ru}
import scala.reflect.ClassTag
val mirror = ru.runtimeMirror(getClass.getClassLoader)
def anyClassTag(tpe: ru.Type) = ClassTag[Any](mirror.runtimeClass(tpe))
def toArray1(items: Seq[Any]) = (tpe: ru.Type) => {
items.toArray(anyClassTag(tpe))
}
Unsurpisingly this fails with a CastClassException
when called with a primitive type.
toArray1(Seq(1,2,3))(ru.typeOf[Int]) foreach print // java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
However, if the function is rewritten as a PartialFunction
instead, then it somehow works!
def toArray2(items: Seq[Any]) : PartialFunction[ru.Type, Array[Any]] = { case tpe =>
items.toArray(anyClassTag(tpe))
}
toArray2(Seq(1,2,3))(ru.typeOf[Int]) foreach print // Successfully prints 123 !
This seems to be very fragile though. A slight modification could easily break it again. Example:
def toArray3(items: Seq[Any]) : PartialFunction[ru.Type, Array[Any]] = { case tpe =>
val results = items.toArray(anyClassTag(tpe))
results
}
toArray3(Seq(1,2,3))(ru.typeOf[Int]) foreach print // ClassCastException again!
So the question is, what magic is going on here? Why is toArray2
the only one that work, and should it?