Ambiguous implicit values

14,955

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.

Share:
14,955

Related videos on Youtube

lambdas
Author by

lambdas

Updated on September 14, 2022

Comments

  • lambdas
    lambdas over 1 year

    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.

  • lambdas
    lambdas over 9 years
    You're right, it fixes the problem, but imagine convert being implicit and f defined as def f(s: String): Foo = s. Is it impossible to accomplish? In theory, scala could infer Foo type from f's return type, so why the error?