Why do arrays require ClassTags, but collections like List don't work?

This works great:

def x[A](a: A) = List(a)

      

Missing ClassTag for A:

def y[A](a: A) = Array(a)

      

But of course it's kosher:

def y[A : ClassTag](a: A) = Array(a)

      

What gives?

+3


source to share


1 answer


Arrays retain their type at runtime, but generic methods lose their versatility at runtime due to type erasure. Thus, if you dynamically create an array at runtime from a generic method, the generic type information must be preserved. The JVM does not know the type due to erasure, but Scala stores the information in the form of a ClassTag to avoid the erasure problem.

You can cheat using Java reflection

def y[A](a: A, length: Int) = java.lang.reflect.Array.newInstance(a.getClass, length)

      

but that would be awful - note that the return type is Object, not Array [A], due to erasure

scala> y("foo", 1)
res2: Object = Array(null)

      

Also note that java.lang.reflect.Array.newInstance () returns Object in the API documentation .



This makes sense because Java erases and doesn't have ClassTags.

Scala has ClassTags, so an array created at runtime can be created with the appropriate type:

scala> def y[A : ClassTag](a: A) = Array(a)
y: [A](a: A)(implicit evidence$1: scala.reflect.ClassTag[A])Array[A]

scala> y("foo")
res4: Array[String] = Array(foo)

scala> y(1)
res5: Array[Int] = Array(1)

      

More on erasing styles on the JVM here (Java examples):

Of course, due to erasure, the List of A becomes a List AnyRef at runtime, so while the type checking is checked at compile time (via generics), the JVM doesn't care about runtime what the types are when the generic object is generated.

+1


source







All Articles