Assume, we have an abstract class with an abstract type field:
abstract class A {type T}
Now let\'s assume, we have a method, which returns
As you guessed, abstract type members are a compile time information that will be erased during type erasure. Here is a work around that uses implicit
parameters. The dispatch is static.
scala> class A {
| type T
| }
defined class A
scala> implicit def distString(a: A { type T = String }) = "String"
distString: (a: A{type T = String})java.lang.String
scala> implicit def distInt(a: A { type T = Int }) = "Int"
distInt: (a: A{type T = Int})java.lang.String
scala> implicit def distOther[O](a: A { type T = O }) = "Other"
distOther: [O](a: A{type T = O})java.lang.String
scala> def distinguish(a: A)(implicit ev: A { type T = a.T } => String) = ev(a)
distinguish: (a: A)(implicit ev: A{type T = a.T} => String)String
scala> distinguish(new A { type T = String })
res2: String = String
scala> distinguish(new A { type T = Int })
res3: String = Int
scala> distinguish(new A { type T = Float })
res4: String = Other
Another way:
scala> def dist(a: A)(implicit s: a.T =:= String = null, i: a.T =:= Int = null) =
| if (s != null) "String" else if (i != null) "Int" else "Other"
dist: (a: A)(implicit s: =:=[a.T,String], implicit i: =:=[a.T,Int])String
scala> dist(new A { type T = String })
res5: String = String
scala> dist(new A { type T = Int })
res6: String = Int
scala> dist(new A { type T = Float })
res7: String = Other
Edit:
If the above solutions do not satisfy you, and you want to reify and introspect this type information at runtime after all, you can do that as well, using something called Manifest
s.
scala> :paste
// Entering paste mode (ctrl-D to finish)
abstract class A {
type T
def man: Manifest[T]
}
object A {
def apply[X](implicit m: Manifest[X]) = new A { type T = X; def man = m }
}
// Exiting paste mode, now interpreting.
defined class A
defined module A
scala> def disti(a: A): String = a match {
| case _ if a.man <:< manifest[String] => "String"
| case _ if a.man <:< manifest[Int] => "Int"
| case _ => "Other"
| }
disti: (a: A)String
scala> disti(A.apply[String])
res14: String = String
scala> disti(A.apply[Int])
res15: String = Int
scala> disti(A.apply[Float])
res16: String = Other