2
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 ?

2 Answers 2

3

You cannot because of type erasure. However, I would argue that your attempt to do this is formed from a mis-understanding.

  • The point of a type system is so that the compiler can reason more powerfully about the correctness of your program.
  • In a static type system, each reference has a type which cannot be changed

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]]

Sign up to request clarification or add additional context in comments.

1 Comment

But it is possible to use the manifests to distinguish between CWTP[List[Int]] and CWTP[List[Double]]—just not if you take the erasure.
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.