Reputation: 16143
class S
class A extends S
class B extends S
class ClassWithTypeParameter[+T]
val a: ClassWithTypeParameter[S] = new ClassWithTypeParameter[A]
How can one determine the type of the subclass used for the type parameter of value a ?
Upvotes: 2
Views: 290
Reputation: 139038
The following is a bad idea (like most uses of reflection) but it works:
class ClassWithTypeParameter[+T: Manifest] {
def paramIs[V: Manifest] = manifest[T] == manifest[V]
}
Which gives us:
scala> val a: ClassWithTypeParameter[S] = new ClassWithTypeParameter[A]
a: ClassWithTypeParameter[S] = ClassWithTypeParameter@6493c09c
scala> a.paramIs[A]
res0: Boolean = true
scala> a.paramIs[S]
res1: Boolean = false
scala> a.paramIs[B]
res2: Boolean = false
And:
scala> val i = new ClassWithTypeParameter[List[Int]]
i: ClassWithTypeParameter[List[Int]] = ClassWithTypeParameter@260702ee
scala> i.paramIs[List[Int]]
res3: Boolean = true
scala> i.paramIs[List[Double]]
res4: Boolean = false
You could write similar paramSubtypeOf
and paramSupertypeOf
methods using Manifest
's <:<
and >:>
.
In Scala 2.10 (Milestone 4 or later) there's a much more flexible way to get the type:
class ClassWithTypeParameter[+T: TypeTag] {
def paramType = reflect.runtime.universe.typeTag[T].tpe
}
Now you could write things like a.paramType.parents
to get the immediate supertypes, etc.
Upvotes: 2
Reputation: 134270
You cannot because of type erasure. However, I would argue that your attempt to do this is formed from a mis-understanding.
In your program, there is one reference, a
and the type of this reference is ClassWithTypeParameter[S]
. That. Is. All. The compiler can know what can be done with this reference. The types are there purely for the compiler. The fact that, at runtime, a
was assigned to a value which was a ClassWithTypeParameter[A]
is irrelevant.
One possible way of doing this to some approximation (limited by erasure) is to use manifests (called something else in 2.10):
class ClassWithTypeParameter[+T: Manifest] { def erasure = manifest[T].erasure }
Then you can call erasure
which will get you a java.lang.Class
back. As I said, this is limited. A class is not the same thing as a type and there is no way to distinguish, for example, ClassWithTypeParameter[List[Int]]
from ClassWithTypeParameter[List[Double]]
Upvotes: 3