This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Propagating ambiguous implicit values and unhelpful scalac error messages

2 replies
Chris Marshall
Joined: 2009-06-17,
User offline. Last seen 44 weeks 3 days ago.
I had an issue recently where scalac was unable to provide a helpful error message in the case of ambiguous implicits. It's in the event that the ambiguity is 1-step-removed.
Here is a standard ambiguous implicit
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18).Type in expressions to have them evaluated.Type :help for more information.
scala> trait Foo[T] { def foo: T }defined trait Foo
scala> def bar[T : Foo]: T = implicitly[Foo[T]].foobar: [T](implicit evidence$1: Foo[T])T
scala> implicit val f1 = new Foo[Int] { def foo = 1 }f1: java.lang.Object with Foo[Int] = $anon$1@6f6068
scala> implicit val f2 = new Foo[Int] { def foo = 2 }f2: java.lang.Object with Foo[Int] = $anon$1@ec9441
scala> bar[Int]<console>:12: error: ambiguous implicit values: both value f1 in object $iw of type => java.lang.Object with Foo[Int] and value f2 in object $iw of type => java.lang.Object with Foo[Int] match expected type Foo[Int]              bar[Int]                 ^

So far so good. But what happens when we declare a second type, for which an implicit value only exists if there is an implicit value for the Foo?
scala> trait Baz { def baz[T : Foo] = implicitly[Foo[T]].foo }defined trait Baz
scala> implicit def z[T : Foo] = new Baz {}z: [T](implicit evidence$1: Foo[T])java.lang.Object with Baz

Now, if we have some reliance on finding an implicit Baz instance...
scala> def bat(implicit baz: Baz) = bazbat: (implicit baz: Baz)Baz
scala> bat.baz[Int]<console>:16: error: could not find implicit value for parameter baz: Baz              bat.baz[Int]              ^

There is no warning as to why the implicit baz method is not applicable. In practice this can be really hard to track down (especially with a library like scalaz). Is there any way in which you can generate an error which looks like 
could not find implicit value for parameter baz: Baz. "implicit def z" not applicable here due to ambiguous implicit values for Foo[Int]:
 both value f1 in object $iw of type => java.lang.Object with Foo[Int] and value f2 in object $iw of type => java.lang.Object with Foo[Int] match expected type Foo[Int]
Would such an error message be feasible?
Chris
Matthew Pocock 3
Joined: 2010-07-30,
User offline. Last seen 42 years 45 weeks ago.
Re: Propagating ambiguous implicit values and unhelpful scalac
Hi,
I'd love an error message like this. However, I'm not sure what the workable heuristic would be - when would it know that the first-level implicit that failed due to a 2nd level one was the intended implicit? There will be a whole load of level-1 implicits that it tries and fails with. So, on failure, would it go back to the most specific implicit that failed, and then if that was itself a level-1 lookup that failed due to a level-2 lookup, give the error? If that level-2 implicit failed due to a level-3, do you recurse the messages?
I've been having an entertaining time trying to write some DSL stuff that uses implicits, and debugging them is a PITA. The intellij plugin can sometimes pop-up an implicit that is used, but doesn't always get them, and doesn't give you any feedback when no implicit can be found. Consider:
def foo()(implicitly b: Bar)...foo // no implicit found for b: Bar
Once the compiler has complained here, what I need is a UI where I can get a drop-down of in-scope implicits, and click the one that I think should have been used, and then get out an explanation for why it was not applicable. If the implicit arg relies on something else, then this process needs to be continued recursively. A truly interactive implicit debugging environment would be a godsend.

Matthew

On 30 December 2011 10:02, Chris Marshall <oxbow_lakes@hotmail.com> wrote:
I had an issue recently where scalac was unable to provide a helpful error message in the case of ambiguous implicits. It's in the event that the ambiguity is 1-step-removed.
Here is a standard ambiguous implicit
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18).Type in expressions to have them evaluated. Type :help for more information.
scala> trait Foo[T] { def foo: T }defined trait Foo
scala> def bar[T : Foo]: T = implicitly[Foo[T]].foobar: [T](implicit evidence$1: Foo[T])T
scala> implicit val f1 = new Foo[Int] { def foo = 1 }f1: java.lang.Object with Foo[Int] = $anon$1@6f6068
scala> implicit val f2 = new Foo[Int] { def foo = 2 } f2: java.lang.Object with Foo[Int] = $anon$1@ec9441
scala> bar[Int]<console>:12: error: ambiguous implicit values: both value f1 in object $iw of type => java.lang.Object with Foo[Int]  and value f2 in object $iw of type => java.lang.Object with Foo[Int] match expected type Foo[Int]              bar[Int]                 ^

So far so good. But what happens when we declare a second type, for which an implicit value only exists if there is an implicit value for the Foo?
scala> trait Baz { def baz[T : Foo] = implicitly[Foo[T]].foo }defined trait Baz
scala> implicit def z[T : Foo] = new Baz {} z: [T](implicit evidence$1: Foo[T])java.lang.Object with Baz

Now, if we have some reliance on finding an implicit Baz instance...
scala> def bat(implicit baz: Baz) = bazbat: (implicit baz: Baz)Baz
scala> bat.baz[Int]<console>:16: error: could not find implicit value for parameter baz: Baz               bat.baz[Int]              ^

There is no warning as to why the implicit baz method is not applicable. In practice this can be really hard to track down (especially with a library like scalaz). Is there any way in which you can generate an error which looks like 
could not find implicit value for parameter baz: Baz. "implicit def z" not applicable here due to ambiguous implicit values for Foo[Int]:
 both value f1 in object $iw of type => java.lang.Object with Foo[Int] and value f2 in object $iw of type => java.lang.Object with Foo[Int] match expected type Foo[Int]
Would such an error message be feasible?
Chris



--
Dr Matthew PocockIntegrative Bioinformatics Group, School of Computing Science, Newcastle Universitymailto: turingatemyhamster@gmail.com gchat: turingatemyhamster@gmail.commsn: matthew_pocock@yahoo.co.uk irc.freenode.net: drdozerskype: matthew.pococktel: (0191) 2566550mob: +447535664143
Chris Marshall
Joined: 2009-06-17,
User offline. Last seen 44 weeks 3 days ago.
RE: Propagating ambiguous implicit values and unhelpful scalac
I'm not familiar enough with the internals of implicit resolution to know whether this is possible. But if the compiler finds a type with a method with a matching name with an in-scope implicit conversion to that type, it could carry around a single slot saying why the implicit conversion was not applicable. If there are more than one such conversions; tough. You only get one error message. But one is better than none.
Chris

Date: Tue, 3 Jan 2012 11:45:00 +0000
Subject: Re: [scala-user] Propagating ambiguous implicit values and unhelpful scalac error messages
From: turingatemyhamster@gmail.com
To: oxbow_lakes@hotmail.com
CC: scala-user@googlegroups.com

Hi,
I'd love an error message like this. However, I'm not sure what the workable heuristic would be - when would it know that the first-level implicit that failed due to a 2nd level one was the intended implicit? There will be a whole load of level-1 implicits that it tries and fails with. So, on failure, would it go back to the most specific implicit that failed, and then if that was itself a level-1 lookup that failed due to a level-2 lookup, give the error? If that level-2 implicit failed due to a level-3, do you recurse the messages?
I've been having an entertaining time trying to write some DSL stuff that uses implicits, and debugging them is a PITA. The intellij plugin can sometimes pop-up an implicit that is used, but doesn't always get them, and doesn't give you any feedback when no implicit can be found. Consider:
def foo()(implicitly b: Bar)...foo // no implicit found for b: Bar
Once the compiler has complained here, what I need is a UI where I can get a drop-down of in-scope implicits, and click the one that I think should have been used, and then get out an explanation for why it was not applicable. If the implicit arg relies on something else, then this process needs to be continued recursively. A truly interactive implicit debugging environment would be a godsend.

Matthew

On 30 December 2011 10:02, Chris Marshall <oxbow_lakes@hotmail.com> wrote:
I had an issue recently where scalac was unable to provide a helpful error message in the case of ambiguous implicits. It's in the event that the ambiguity is 1-step-removed.
Here is a standard ambiguous implicit
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18).Type in expressions to have them evaluated. Type :help for more information.
scala> trait Foo[T] { def foo: T }defined trait Foo
scala> def bar[T : Foo]: T = implicitly[Foo[T]].foobar: [T](implicit evidence$1: Foo[T])T
scala> implicit val f1 = new Foo[Int] { def foo = 1 }f1: java.lang.Object with Foo[Int] = $anon$1@6f6068
scala> implicit val f2 = new Foo[Int] { def foo = 2 } f2: java.lang.Object with Foo[Int] = $anon$1@ec9441
scala> bar[Int]<console>:12: error: ambiguous implicit values: both value f1 in object $iw of type => java.lang.Object with Foo[Int]  and value f2 in object $iw of type => java.lang.Object with Foo[Int] match expected type Foo[Int]              bar[Int]                 ^

So far so good. But what happens when we declare a second type, for which an implicit value only exists if there is an implicit value for the Foo?
scala> trait Baz { def baz[T : Foo] = implicitly[Foo[T]].foo }defined trait Baz
scala> implicit def z[T : Foo] = new Baz {} z: [T](implicit evidence$1: Foo[T])java.lang.Object with Baz

Now, if we have some reliance on finding an implicit Baz instance...
scala> def bat(implicit baz: Baz) = bazbat: (implicit baz: Baz)Baz
scala> bat.baz[Int]<console>:16: error: could not find implicit value for parameter baz: Baz               bat.baz[Int]              ^

There is no warning as to why the implicit baz method is not applicable. In practice this can be really hard to track down (especially with a library like scalaz). Is there any way in which you can generate an error which looks like 
could not find implicit value for parameter baz: Baz. "implicit def z" not applicable here due to ambiguous implicit values for Foo[Int]:
 both value f1 in object $iw of type => java.lang.Object with Foo[Int] and value f2 in object $iw of type => java.lang.Object with Foo[Int] match expected type Foo[Int]
Would such an error message be feasible?
Chris



--
Dr Matthew PocockIntegrative Bioinformatics Group, School of Computing Science, Newcastle Universitymailto: turingatemyhamster@gmail.com gchat: turingatemyhamster@gmail.commsn: matthew_pocock@yahoo.co.uk irc.freenode.net: drdozerskype: matthew.pococktel: (0191) 2566550mob: +447535664143

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland