Trait runtime type of type parameter through TypeTag when used with Existential type in Scala -
i have trait type parameter. runtime type use typetag. however, when trait (and classes) used existential type in collection, e.g. list or map, typetag "lost".
here example of standard way use type tag:
scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> trait animal[t] { | def typet()(implicit t: typetag[t]) = t.tpe | } defined trait animal scala> scala> class dog extends animal[int] defined class dog scala> class cat extends animal[string] defined class cat scala> scala> val dog = new dog dog: dog = dog@4aa88c93 scala> val cat = new cat cat: cat = cat@2281e252 scala> dog.typet res46: reflect.runtime.universe.type = int scala> cat.typet res47: reflect.runtime.universe.type = string as can see, far good, method typet defined , implemented in trait animal works. however, when used list , existential types, failed working:
scala> val aa: list[animal[_]] = list(dog, cat, dog) aa: list[animal[_]] = list(dog@4aa88c93, cat@2281e252, dog@4aa88c93) scala> aa(0).typet res52: reflect.runtime.universe.type = _$1 scala> aa(1).typet res53: reflect.runtime.universe.type = _$1 explicit casting (like following) sure worked. of time given list[anima[_]]. if level of typecast necessary, , how?
scala> aa(0) res55: animal[_] = dog@4aa88c93 scala> aa(0).asinstanceof[dog] res56: dog = dog@4aa88c93 scala> aa(0).asinstanceof[dog].typet res57: reflect.runtime.universe.type = int i understand aa(0) animal[_] reason. still, aa(0) not animal[_], dog. why typet (or typetag) not used if normal method?
the problem here typet() method, return different value depending on knowledge of animal. if compiler can prove have animal[int], can typetag[int]. existential type in list[animal[_]], lose type information contained in animal. when select arbitrary element list, know it's animal[_] when typet called, , nothing else. typet not know type parameter t each instance. has no way of proving in context.
the type cast of course works, because asinstanceof[animal[cat]] tells compiler forget knows. if course can throw classcastexception when wrong.
one way can work requiring implicit typetag[t] on instantiation of animal[t], , storing value, rather resolving within method. unfortunately, means cannot use trait.
abstract class animal[t](implicit tt: typetag[t]) { val tpe = tt.tpe } class dog extends animal[int] class cat extends animal[string] val dog = new dog val cat = new cat scala> val aa: list[animal[_]] = list(cat, dog, cat) aa: list[animal[_]] = list(cat@5a9faacf, dog@675c379d, cat@5a9faacf) scala> aa(0).tpe res6: reflect.runtime.universe.type = string scala> aa(1).tpe res7: reflect.runtime.universe.type = int alternatively, express using little syntactic sugar on implicit parameters:
abstract class animal[t: typetag] { val tpe = implicitly[typetag[t]].tpe }
Comments
Post a Comment