When we have an Array of arbitrary type X
in Scala and we try to do a double nest to each of its values using map
(that is, turning [1,2,3]
into [[[1]],[[2]],[[3]]]
), we get a java.lang.ArrayStoreException
. Code below is a minimal failing example:
import scala.reflect.ClassTag
def doubleNest[X: ClassTag](values: Array[X]): Array[Array[Array[X]]] = {
values map { value =>
Array(Array(value))
}
}
doubleNest(Array(1,2,3))
What is more, error seems to arise when turning [[1],[2],[3]]
into [[[1]],[[2]],[[3]]]
. Code below is a minimal failing example (error happens in the second map
):
import scala.reflect.ClassTag
def doubleNest[X: ClassTag](array: Array[X]): Array[Array[Array[X]]] = {
val nested = array map { value =>
Array(value)
}
nested map { arr =>
Array(arr)
}
}
doubleNest(Array(1,2,3))
Why does this happen?
It seems that Scala doesn't like making nested generic arrays directly. Even this fails:
def foo[T: ClassTag](t: T) = Array(Array(t))
foo(1) // java.lang.ClassCastException: java.base/[Ljava.lang.Object; cannot be cast to [[I
(In this case, it's probably because ClassTag
looks at the erased class, so Array.apply
does the same, and it creates an Array[Array[Object]]
instead of Array[Array[T]]
.)
It also appears that ClassTag
has the methods wrap
and newArray for this purpose. So, you can use some ugliness involving implicitly[ClassTag[X]].wrap.wrap.newArray(array.length)
to get the job done, or you can do this, which seems to work by never directly asking it to create a nested array:
import scala.reflect.ClassTag
def nest[C: ClassTag](arr: Array[C]) = arr.map(Array(_))
def doubleNest[X: ClassTag](array: Array[X]): Array[Array[Array[X]]] =
nest(nest(array))