Seem to have painted myself in to a corner. I am trying to use a container
class that generically allows me to wrap and unwrap values of
different types used in a Scala collection.
I have the this class:
sealed trait Val[V] {
val v: V
override def toString: String = s"Val($v)"
override def equals(obj: scala.Any): Boolean = {
if (obj.isInstanceOf[Val[V]]){
val other = obj.asInstanceOf[Val[V]]
v.equals(other.v)
}
else
false
}
def arr(n: Int)(implicit tag: ClassTag[V]): Array[V] = Array.ofDim[V](n)
def vec(n: Int)(implicit tag: ClassTag[V]): Vector[V] = arr(n).toVector
def arrX(n: Int)(implicit tag1: ClassTag[V], tag2: TypeTag[V]): Array[V] = {
Array.ofDim[V](n)
}
}
I use the following functions to pack and unpack the values:
implicit def pack[A:TypeTag](s:A) : Val[A] = new Val[A] {
override val v: A = s
}
implicit def unpack[T:TypeTag](t:Val[_]): Either[String,T] = {
try {
val v = t.v.asInstanceOf[T]
Right(v)
} catch {
// When used via implicits should never reach this
case e: Exception => Left(e.getMessage)
}
}
Now I use the following function to see what type information is available:
def paramInfo[T: TypeTag](x: T): Unit = {
val targs = typeOf[T] match { case TypeRef(_, _, args) => args }
println(s"type of $x (${x.getClass}) has type arguments $targs")
}
So now I wrap and unwrap a String
value so:
val avt:Val[_] = "100"
print("pack Val[_]: "); paramInfo(avt.v)
val tavt: Either[String, Val[_]] = unpack(avt)
print("unpack Val[_]: "); paramInfo(tavt.right.get)
And I get this output:
pack Val[_]: type of 100 (class java.lang.String) has type arguments List()
unpack Val[_]: type of 100 (class java.lang.String) has type arguments List(_$8)
So far so good. Now I try to create an Array[String] from the Val[String] so:
//val at: Val[Array[_]] = avt.arr(5)
val at: Val[Array[_]] = avt.arrX(5)
paramInfo(at)
which results in:
type of Val([Ljava.lang.Object;@2219f3b5) (class pt.inescn.etl.stream.LoadX$$anon$5) has type arguments List(Array[_])
I can see that we have an Array
, but not an array of String
. So this won’t compile:
val arr:Array[String] = aut.right.get
and this won’t execute:
val arr = aut.right.get
Strangely enough the error is:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
So 2 questions:
- how did the compiler know it was a String?
- how can I get this to run?
Any other comments are welcome.
TIA