Question

The setup for this example (Scala 2.10.3):

trait S[A]
trait T[A]
implicit class X[A : S](a: A) { def foo() { } }
implicit class Y[A : T](a: A) { def foo() { } }
implicit object I extends S[String]

This compiles:

new X("").foo()

This doesn't:

new Y("").foo()

because there is no implicit T[String].

could not find implicit value for evidence parameter of type T[String]
              new Y("").foo()
              ^

Therefore, I would assume that scalac could unambiguously apply the implicit conversion from String to X:

"".foo()

But instead we get:

type mismatch;
 found   : String("")
 required: ?{def foo: ?}
Note that implicit conversions are not applicable because they are ambiguous:
 both method X of type [A](a: A)(implicit evidence$1: S[A])X[A]
 and method Y of type [A](a: A)(implicit evidence$1: T[A])Y[A]
 are possible conversion functions from String("") to ?{def foo: ?}
              "".foo()
              ^

Is this intentional? Is scalac not supposed to consider whether each conversion would actually work when it enumerates the candidates?

Was it helpful?

Solution

My nonacademic view is that implicit is by design not meant to work everytime it seems that it should work. I think it's a good idea otherwise you could easily get into an implicit hell. You could extend your example by adding more layers of implicit conversions. It would be hard to tell which function is actually called just by looking at the code. There are well-defined rules, but I remember simply that if it's not obvious from the code what's going on, it doesn't work.

I would say that your code breaks One-at-a-time Rule which leads to breaking the Non-Ambiguity Rule. A : S is just a syntactic sugar, and can be rewritten to:

implicit class X[A](a: A)(implicit e: S[A]) { def foo() { } }
implicit class Y[A](a: A)(implicit e: T[A]) { def foo() { } }

Without resolution of the "second" implicit level (method argument e) both classes X and Y look the same to the compiler and therefore are ambiguous. As the linked document says: "For sanity's sake, the compiler does not insert further implicit conversions when it is already in the middle of trying another implicit."

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top