I think I am close to start understanding type erasure and the Scala reflection API. But I'm still in a world of pain...
How do I deal with this problem? I have a class that can take generic functions as arguments, and I need to do different things depending on the type from the function output. I also need to be able to "extract" the types. (This is all related to another question of mine, which helped me a lot, but still didn't solve my real problem.)
I know I can do the following:
import scala.reflect.runtime.universe._
object ReflectiveMysteryA extends App {
def stupidFunc[A: TypeTag](arg: List[A]) = typeOf[A] match {
case t if t =:= typeOf[List[String]] =>
println("its a list of list of string")
case t if t =:= typeOf[Set[Int]] =>
println("its a list of set of int")
case t if t =:= typeOf[Set[Long]] =>
println("its a list of set of Long")
case _ =>
println("WTF")
}
stupidFunc(List(List("a", "bc"), List("b", "def")))
stupidFunc(List(Set(1, 2), Set(2, 3, 4)))
stupidFunc(List(Set(0L, 432L), Set(321L)))
stupidFunc(List(Set("a", "bc", "def")))
// stupidFunc(Set(Set("a", "bc", "def"))) // Doesn't compile, "type mismatch"
}
// its a list of list of string
// its a list of set of int
// its a list of set of Long
// WTF
This is all good good, we test the type using TypeTag
and then we do the corresponding stuff. But it only works as long as you don't really need to be sure about that type you tested...
For instance, now I have a function like this, with type parameter bounds and an implicit argument that is used to "extract" type B from type LSB from the function argument:
object ReflectiveMysteryB extends App {
def specialFunc[LSB <: List[Set[_]], B: TypeTag](vv: LSB)(implicit ev: List[Set[B]] =:= LSB) = {
typeOf[B] match {
case t if t =:= typeOf[Int] =>
println("list of set of int")
case t if t =:= typeOf[Long] =>
println("list of set of long")
}
}
specialFunc(List(Set(1, 2), Set(2, 3, 4)))
specialFunc(List(Set(0L, 432L), Set(321L)))
// specialFunc(List(List("a", "bc"), List("b", "def"))) // Doesn't compile, "type parameter bounds"
}
// list of set of int
// list of set of long
This is working fine too. The problem happens when I try to compose the two things:
object ReflectiveMysteryC extends App {
def stupiderFunc[A: TypeTag](arg: List[A]) = typeOf[A] match {
case t if t =:= typeOf[List[String]] =>
println("its a list of list of string")
case t if t =:= typeOf[Set[Int]] =>
specialFunc(arg)
case t if t =:= typeOf[Set[Long]] =>
specialFunc(arg)
case _ =>
println("WTF")
}
def specialFunc[LSB <: List[Set[_]], B: TypeTag](vv: LSB)(implicit ev: List[Set[B]] =:= LSB) = {
typeOf[B] match {
case t if t =:= typeOf[Int] =>
println("list of set of int")
case t if t =:= typeOf[Long] =>
println("list of set of long")
}
}
stupiderFunc(List(List("a", "bc"), List("b", "def")))
stupiderFunc(List(Set(1, 2), Set(2, 3, 4)))
stupiderFunc(List(Set(0L, 432L), Set(321L)))
stupiderFunc(List(Set("a", "bc", "def")))
}
That won't compile
Error:(45, 7) inferred type arguments [List[A],Nothing] do not conform to method specialFunc's type parameter bounds [LSB <: List[Set[_]],B]
specialFunc(arg)
^
Error:(45, 19) type mismatch;
found : List[A]
required: LSB
specialFunc(arg)
^
Error:(45, 18) Cannot prove that List[Set[B]] =:= LSB.
specialFunc(arg)
^
Error:(47, 7) inferred type arguments [List[A],Nothing] do not conform to method specialFunc's type parameter bounds [LSB <: List[Set[_]],B]
specialFunc(arg)
^
Error:(47, 19) type mismatch;
found : List[A]
required: LSB
specialFunc(arg)
^
Error:(47, 18) Cannot prove that List[Set[B]] =:= LSB.
specialFunc(arg)
^
To make it work, we could do the following:
object ReflectiveMysteryD extends App {
def stupiderFunc[A: TypeTag](arg: List[A]) = typeOf[A] match {
case t if t =:= typeOf[List[String]] =>
println("its a list of list of string")
case t if t =:= typeOf[Set[Int]] =>
specialFunc(arg.asInstanceOf[List[Set[Int]]])
case t if t =:= typeOf[Set[Long]] =>
specialFunc(arg.asInstanceOf[List[Set[Long]]])
case _ =>
println("WTF")
}
def specialFunc[B: TypeTag](vv: List[Set[B]]) = {
typeOf[B] match {
case t if t =:= typeOf[Int] =>
println("list of set of int")
case t if t =:= typeOf[Long] =>
println("list of set of long")
}
}
stupiderFunc(List(List("a", "bc"), List("b", "def")))
stupiderFunc(List(Set(1, 2), Set(2, 3, 4)))
stupiderFunc(List(Set(0L, 432L), Set(321L)))
stupiderFunc(List(Set("a", "bc", "def")))
}
// its a list of list of string
// list of set of int
// list of set of long
// WTF
But now my problem is: How can I match the general case of List[Set[_]]
in stupiderFunc
in order to apply specialFunc
to arg
without having to list all the specific Int
or Long
types? Is there a way to use asInstanceOf
without fixing the inner type parameter? Or is there a way to fix the implicit
approach so it is able to figure out that args
actually conforms to the expected type by the time we are calling specialFunc
inside the match
?
Is this a problem I might be using macros to solve? How should I proceed in that case?
Aucun commentaire:
Enregistrer un commentaire