Kevin Meredith Kevin Meredith - 2 months ago 13
Scala Question

A => Class[A] using ClassTag?

Looking at ClassTag#runtimeClass, it has a return type of

Class[_]
, i.e. a
Class
with, as I understand, a wildcard parameter.

I tried to implement a method:
A => ClassTag[A]
:

import scala.reflect._

scala> def f[A](x: A)(implicit ev: ClassTag[A]) = ev.runtimeClass
f: [A](x: A)(implicit ev: scala.reflect.ClassTag[A])Class[_]


But, the output of the
def
's definition is, as the docs show,
Class[_]
.

Is it possible to change
f
such that its return type is
Class[A]
? If not, then why is it not possible?

m-z m-z
Answer

Unless you change the signature of f, your only option is to cast the Class[_] to a Class[A].

There is literally only one method in the entire Scala standard library that returns a Class[A], and that is classOf. f[A] cannot be re-written to use classOf[A] since it is a special compiler method and is incompatible with generic type parameters that may not be classes. You would simply get an error:

scala> def f[A: ClassTag](x: A) = classOf[A]
<console>:10: error: class type required but A found
       def f[A: ClassTag](x: A) = classOf[A]
                                          ^

The best you can get without casting is using x.getClass, but that will return a Class[_ <: A] (no ClassTag needed).

scala> def f[A](x: A): Class[_ <: A] = x.getClass
f: [A](x: A)Class[_ <: A]

scala> f(1)
res8: Class[_ <: Int] = class java.lang.Integer

scala> f(List(1, 2, 3))
res9: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon

You might ask, why _ <: A?

The answer to that question is also the reason why your definition of f doesn't really make sense. If A is an Int, it makes sense to be able to return a Class[A] because Int is a class. But what if A is a List[Int]? List[Int] is not a class, it's a type. The class is List, but A != List, therefore we cannot return a Class[A] consistently. We can, however, have an upper-bound of A on the type parameter of Class.