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
side question: Because type fields are translated to parameter types in Java ?
There are no type parameters in bytecode, so type fields could not possibly be translated into them. Type fields only exist during compilation.
Alternative : We can alternativley create an enumeration and put an additional field in the class A in order to distinguish the objects. But this smells, because it would mean, that we re-implement the type system.
There's only one kind of type question you can make at run time: what class is this? Scala 2.10 gives a bit more information, but it still boils down to that question.
If you actually subclass A
, you can get that information through reflection (on 2.10). Otherwise, I don't think so -- I've tested on REPL, and there it doesn't work, but things compiled to class files have more information on them.
Any other question has to be made about values.
Question : Is there a way to differ between the types of the objects with the help of the type field ? And if not, what will be a good workaround ?
No, unless Scala 2.10, reflection, and subclasses. Good workaround? Use values. The usual way to handle it is not enumeration, though, but Manifest
, which can be generated implicitly.
Look up questions about how to get around type erasure in Scala.
You can use the <%<
which tells you in compile-time if two types are compatible.
scala> class A { type T }
defined class A
scala> implicitly[A { type T=String } <%< A { type T=Int } ]
<console>:9: error: could not find implicit value for parameter e: <%<[A{type T = String},A{type T = Int}]
implicitly[A { type T=String } <%< A { type T=Int } ]
^
scala> implicitly[A { type T=String } <%< A { type T=String } ]
res1: <%<[A{type T = String},A{type T = String}] = <function1>
scala> implicitly[A { type T=String } <%< A ]
res3: <%<[A{type T = String},A] = <function1>
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