2011-10-15 20 views
5

Tratando de eliminar la ambigüedad del método que se invoca en función del tipo del segundo parámetro, cualquiera contra tirantez, pero sin éxito. Compilar debajo del código genera el siguiente mensaje de error:Tipos, tuplas, prioridad implícita y métodos sobrecargados

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 

Aquí está el código:

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

intenté hacer el "t2" prioridad más baja de la siguiente manera:

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 { 
    .... 
} 

y eliminar " t2 "del objeto" Llamar ", pero recibió el mismo mensaje de error.

Me gustaría que la desambiguación tenga lugar en tiempo de compilación y no en tiempo de ejecución. Gracias.

Respuesta

2

Miles Sabin me proporcionó la siguiente solución:

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") 
     } 
     } 
    } 
Cuestiones relacionadas