Hello,
Say I have a wrapper:
sealed trait Val[V] {
val v: V
}
And I can create instances of these with:
implicit def pack[A](s:A) : Val[A] = new Val[A] {
override val v: A = s
}
Now assume I create these instances:
val r5: Val[String] = "100"
val r6: Val[Double] = 200.0
val r7: Val[Array[Double]] = Array(300.0, 301, 302)
Now here are two ways I can unpack the wrapped value v
. If I have all
of the type information, I can use this definition:
implicit def testFull[A,B](av: Val[A], f: A => B): Either[String,B] = {
try {
val v = av.v.asInstanceOf[A]
Right(f(v))
} catch {
// When used via implicits should never reach this
case e:Exception => Left(e.getMessage)
}
}
so:
val u0 = testFull(r5, (e:String) => e.toInt)
val u1 = testFull(r6, (e:Double) => e)
val u2 = testFull(r7, (e:Array[Double]) => e)
and be sure that no run-time error will occur. On the other hand I
may also extract the wrapped value when not all the type information
is available, using the following definition:
implicit def test[A,B,X](av: Val[X], f: A => B): Either[String,B] = {
try {
val v = av.v.asInstanceOf[A]
Right(f(v))
} catch {
// When used via implicits should never reach this
case e:Exception => Left(e.getMessage)
}
}
For example, if I have this data:
val rs = Map("x" -> r5, "y" -> r6, "z" -> r7)
val s5 = rs("x")
val s6 = rs("y")
val s7 = rs("z")
I can unpack the values so:
val v0 = test(s5, (e:String) => e.toInt)
val v1 = test(s6, (e:Double) => e)
val v2 = test(s7, (e:Array[Double]) => e)
Naturally, this can fail during run-time.
So my question is, is it possible in Scala to select test
or testFull
automatically so that the bound types are as specific as possible. For
example, if the compiler sees this:
val c2 = choose(r6, (e:String) => e.toInt)
it automatically selects testFull
. However, in the following case:
val c2 = choose(s6, (e:String) => e.toInt)
it falls back onto test
.
I have tried to use prioritized implicit conversion with these
definitions:
sealed trait LowPriority {
implicit def testFull[A,B](av: Val[A], f: A => B): Either[String,B] = {
try {
val v = av.v.asInstanceOf[A]
Right(f(v))
} catch {
// When used via implicits should never reach this
case e:Exception => Left(e.getMessage)
}
}
}
object HighPriority extends LowPriority {
implicit def test[A,B,X](av: Val[X], f: A => B): Either[String,B] = {
try {
val v = av.v.asInstanceOf[A]
Right(f(v))
} catch {
// When used via implicits should never reach this
case e:Exception => Left(e.getMessage)
}
}
}
def choose[A,B,X](av: Val[X], f: A => B)(implicit a: (Val[X], A=>B) => Either[String,B]): Either[String,B] = {
a(av, f)
}
but the following code always executes:
val c2 = choose(r6, (e:String) => e.toInt)
Seems like test
is always selected irrespective of the priority set.
TIA