Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't Scala primitives show up as type parameters in Java reflection?

Given the following case class:

case class Foo(
    bar: Int,
    baz: Boolean,
    qux: Option[Int],
    quux: Option[Boolean],
    quuux: Option[Integer]
)

I would expect the following:

for (f <- classOf[Foo].getDeclaredFields) {
    println(f.getGenericType)
}

to produce something like:

int
boolean
scala.Option<int>
scala.Option<boolean>
scala.Option<java.lang.Integer>

But instead, it produces:

int
boolean
scala.Option<java.lang.Object>
scala.Option<java.lang.Object>
scala.Option<java.lang.Integer>

Why do the primitives get erased from the generics, instead of getting treated as java.lang.Integer.TYPE and java.lang.Boolean.TYPE, as appears to happen with the plain fields?

And is there any way to retrieve the primitive type parameters from classOf[Foo]?

like image 769
David Moles Avatar asked Dec 23 '13 18:12

David Moles


People also ask

Why are primitives not possible as generic types?

So, anything that is used as generics has to be convertable to Object (in this example get(0) returns an Object ), and the primitive types aren't. So they can't be used in generics.

How do you check if an object is a primitive type in Java?

The java. lang. Class. isPrimitive() method can determine if the specified object represents a primitive type.

What is type parameter in Scala?

Language. Methods in Scala can be parameterized by type as well as by value. The syntax is similar to that of generic classes. Type parameters are enclosed in square brackets, while value parameters are enclosed in parentheses.


1 Answers

Scala thinks that the generic parameter for primitives is scala.<Primitive> e.g. scala.Int. It doesn't store the type in the Java class file, though arguably it could. (Or not; depends on whether there needs to be a distinction between Int and java.lang.Integer; under the hood the boxed form is java.lang.Integer, even if the compiler does a good job making you believe it is Int.)

Anyway, Scala has its own reflection capabilities which are in flux, but with 2.10 you can find the arguments of the Option types like so:

import scala.reflect.runtime.universe._
typeTag[Foo].tpe.members.collect{
  case m: MethodSymbol if m.isCaseAccessor => m 
}.foreach(m => println(m.name + " " + m.typeSignature))

and you'll get something like

quuux => scala.Option[java.lang.Integer]
quux => scala.Option[scala.Boolean]
qux => scala.Option[scala.Int]
baz => scala.Boolean
bar => scala.Int
like image 140
Rex Kerr Avatar answered Oct 22 '22 05:10

Rex Kerr