Reputation:
Is it possible to generalize the return types of a Map of functions with variable return types to a common signature and then use the actual return type of each function in the Map at runtime?
Explanation:
I'm having a scala Map of string -> functions defined as:
Map[String, (String) => Seq[Any]] = Map("1" -> foo, 2 -> bar, 3 -> baz)
where foo, bar and baz are defined as:
foo(string: String): Seq[A]
bar(string: String): Seq[B]
baz(string: String): Seq[C]
The compilation works fine but at runtime Seq[A or B or C] types returned by the functions are being treated as Seq[Any] thereby giving me a reflection exception.
Upvotes: 0
Views: 1042
Reputation: 16308
Lets imagine some Map-alike workaround
Suppose we define type like that
import scala.reflect.runtime.universe._
class PolyMap[K, V[+_]] {
var backing = Map[(K, TypeTag[_]), V[Any]]()
def apply[T: TypeTag](key: K) =
backing.get(key, typeTag[T]).asInstanceOf[Option[V[T]]]
def update[T: TypeTag](key: K, f: V[T]): this.type = {
backing += (key, typeTag[T]) → f
this
}
}
now having
type String2Seq[+X] = String ⇒ Seq[X]
val polyMap = new PolyMap[String, String2Seq]
polyMap("foo") = foo
polyMap("bar") = bar
you could ensure that
polyMap[String]("foo").map(_("x")) == Some(foo("x"))
polyMap[Int]("foo").map(_("x")) == None
polyMap[Int]("bar").map(_("x")) == Some(bar("x"))
Upvotes: 1
Reputation: 19
I think you can try this variant
def foo(string: String): Seq[String] = {
Seq(string)
}
def bar(string: String): Seq[Int] = {
Seq(1)
}
val map = Map(1 -> foo _, 2 -> bar _)
val res = map(1) match {
case f: (String => Seq[String]) => f
case f: (String => Seq[Int]) => f
case _ => throw new NotImplementedError()
}
println(res("Hello"))
it work's for me.
Upvotes: 0