Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguous implicit values

Tags:

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.

like image 385
lambdas Avatar asked Aug 21 '14 16:08

lambdas


Video Answer


1 Answers

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.

like image 131
wheaties Avatar answered Oct 11 '22 23:10

wheaties