Trying to disambiguate which method is called based upon the type of the second parameter, Any vs. Throwable, but without success. Compiling the code below generates the following error message:
Main.scala:85: error: ambiguous reference to overloaded definition,
both method apply in class Call of type (body: =>(String, Throwable, Array[Any]))(implicit m: Main.Call.Dummy3)Unit
and method apply in class Call of type (body: => (String, Array[Any]))(implicit m: Main.Call.Dummy1)Unit
match argument types ((String, Throwable, String))
agent.call {
^
one error found
Here's the code:
object Main {
object Call {
implicit def t1(t: Tuple2[String, Any]): Tuple2[String, Array[Any]] = {
(t._1, Array(t._2))
}
implicit def t1t(t: Tuple2[String, Throwable]): Tuple2[String, Throwable] = {
(t._1, t._2)
}
implicit def t2(t: Tuple3[String, Any, Any]): Tuple2[String, Array[Any]] = {
(t._1, Array(t._2, t._3))
}
implicit def t2t(t: Tuple3[String, Throwable, Any]): Tuple3[String, Throwable, Array[Any]] = {
(t._1, t._2, Array(t._3))
}
class Dummy1
object Dummy1 {
implicit def dummyImplicit: Dummy1 = {
println("Dummy1.dummyImplicit")
new Dummy1
}
}
class Dummy2
object Dummy2 {
implicit def dummyImplicit: Dummy2 = {
println("Dummy2.dummyImplicit")
new Dummy2
}
}
class Dummy3
object Dummy3 {
implicit def dummyImplicit: Dummy3 = {
println("Dummy3.dummyImplicit")
new Dummy3
}
}
}
import Call._
class Call {
def apply(body: => Tuple2[String, Array[Any]])
(implicit m: Dummy1): Unit = {
println("message and array of parameters")
}
def apply(body: => Tuple2[String, Throwable])
(implicit m: Dummy2): Unit = {
println("message and throwable")
}
def apply(body: => Tuple3[String, Throwable, Array[Any]])
(implicit m: Dummy3): Unit = {
println("message, throwable and array of parameters")
}
}
class Agent {
val _call = new Call
def call: Call = _call
}
def main(args: Array[String]): Unit = {
val msg = "XXX"
val agent = new Agent
agent.call {
(msg, "one")
}
agent.call {
(msg, new Exception)
}
agent.call {
(msg, "one", "two")
}
agent.call {
(msg, new Exception, "one")
}
}
}
I tried making the "t2" lower priority as follows:
trait LowPriority {
implicit def t2(t: Tuple3[String, Any, Any]): Tuple2[String, Array[Any]] = {
(t._1, Array(t._2, t._3))
}
}
object Call extends LowPriority {
....
}
and removing "t2" from the "Call" object, but got the same error message.
I would like the disambiguation to take place at compile-time and not at run-time. Thanks.
Miles Sabin provided me with the following solution:
object Main {
object Call {
trait LowPriorityDistinguishThrowable {
trait Wrap1[A, B] {
val body : (A, B)
def apply(call: Call) : Unit
}
trait Wrap2[A, B, Any] {
val body : (A, B, Any)
def apply(call: Call) : Unit
}
implicit def wrap11[T](body0 : => (String, T)) =
new Wrap1[String, T] {
lazy val body = body0
def apply(call: Call) {
println("(message and not throwable): " +body)
}
}
implicit def wrap21[T](body0 : => (String, T, Any)) =
new Wrap2[String, T, Any] {
lazy val body = body0
def apply(call: Call) {
println("(message and not throwable): " +body)
}
}
}
object DistinguishThrowable extends LowPriorityDistinguishThrowable {
implicit def wrap12(body0 : => (String, Throwable)) =
new Wrap1[String, Throwable] {
lazy val body = body0
def apply(call: Call) {
println("(message and throwable): " +body)
}
}
implicit def wrap22(body0 : => (String, Throwable, Any)) =
new Wrap2[String, Throwable, Any] {
lazy val body = body0
def apply(call: Call) {
println("(message and throwable): " +body)
}
}
}
}
class Call(val enabled: Boolean) {
import Call._
import DistinguishThrowable._
def apply[T](body: Wrap1[String, T]): Unit = {
if (enabled) body(this)
}
def apply[T](body: Wrap2[String, T, Any]): Unit = {
if (enabled) body(this)
}
}
def main(args : Array[String]): Unit = {
val call = new Call(true)
call {
("foo", new Exception)
}
call {
("foo", "bar")
}
call {
("foo", new Exception, "one")
}
call {
("foo", "bar", "one")
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With