Reputation: 41909
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?
Upvotes: 0
Views: 260
Reputation: 55569
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
.
Upvotes: 5