I've been thinking I understand scala implicits until recently faced strange problem.
In my application I have several domain classes
case class Foo(baz: String)
case class Bar(baz: String)
And a class that is able to construct domain object from a string. It could be subclassed to do real deserialization it doesn't matter.
class Reads[A] {
def read(s: String): A = throw new Exception("not implemented")
}
Next, there are implicit deserializers
implicit val fooReads = new Reads[Foo]
implicit val barReads = new Reads[Bar]
And a helper to convert strings to one of domain classes
def convert[A](s: String)(implicit reads: Reads[A]): A = reads.read(s)
Unfortunatelly, when trying to use it
def f(s: String): Foo = convert(s)
I get compiler errors like
error: ambiguous implicit values:
both value fooReads of type => Reads[Foo]
and value barReads of type => Reads[Bar]
match expected type Reads[A]
def f(s: String): Foo = convert(s)
^
To me code seems simple and right. Reads[Foo]
and Reads[Bar]
is a completely different types, what is ambiguous about it?
The real code is much more complicated and uses play.api.libs.json
but this simplified version is sufficient to reproduce the error.
The ambiguity you're encountering in your example is that you didn't tell Scalac which one you wanted to use. You need to replace your code with
def f(s: String): Foo = convert[Foo](s)
in order for it to figure out which one to use. It can't infer from the return type of f
. It needs to be explicit here.
Response to comment
Let me play devil's advocate here.
trait Foo
case class Bar(s: String) extends Foo
case class Baz(s: String) extends Foo
def f(s: String): Foo = convert(s)
which implicit does it use assuming there is one defined for both Bar
and Baz
? I'm sure there's more devilish corner cases out there but this one jumps out to me.