jeudi 22 janvier 2015

How do I check if a Scala HigherKinded TypeTag is an Array?

I'm trying to convert a type tag into a java class that maintains/persists normally-erased type parameters. There are quite a few libraries that benefit from conversions like these (such as Jackson, and Guice). I'm currently trying to migrate Manifest based code to TypeTag since Manifests are insufficient for some corner cases.


The JVM treats Arrays special in comparison to other data types. The difference between a classOf[Int] and classOf[Array[Int]] is that the method Class.isArray() will return true for the latter.


The Manifest implementation was simple. Manifest.erasure was a Class instance where isArray() was already valid/true.


The TypeTag implementation is trickier. There is no quick and easy erasure method. In fact the 'similar' TypeTag variant, RuntimeMirror.runtimeClass, prefers not to handle creating any Array based classes on our behalf. Read the documentation:



Note: If the Scala symbol is ArrayClass, a ClassNotFound exception is thrown because there is no unique Java class corresponding to a Scala generic array



To work around this I try to detect if it is an Array. If it is an array, then I manually create the class object. However, I've come across an additional edge case when Array has an unknown type argument.


First let me show you an example that is not a HigherKinded type.



import scala.reflect.runtime.universe._
class A[T]

val innerType = typeOf[A[Array[_]]].asInstanceOf[TypeRefApi].args.head
innerType <:< typeOf[Array[_]] // Returns true.


So far so good.



class B[T[_]]

val innerType = typeOf[B[Array]].asInstanceOf[TypeRefApi].args.head
innerType <:< typeOf[Array[_]] // Returns false.


I can't create a typeOf[Array] since it complains about the missing parameter. How can I detect that B has an type parameter of Array?


Also, what would the class instance look like in this case? Is it an Array[Object]?






Aucun commentaire:

Enregistrer un commentaire