0
votes

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.

2
Will you always have only two possible return types, A and B, or is it possible for there to be many?mattinbits
Looks like an XY problemdcastro
@mattinbits there will be more than two. Sorry for not being clear about that in the question. If it was limited to 2, I could've used Either[A, B]Paulo
@dcastro You're right in that my actual problem led me to this issue and right now I'm more interested in this issue than the actual issue :)Paulo

2 Answers

1
votes

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.

1
votes

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"))