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 ?
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]]
CWTP[List[Int]] and CWTP[List[Double]]—just not if you take the erasure.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.