No ambiguous implicit values errror

The following code compiles without warning.

case class A[T](val value: T)

object A {
  implicit def getA[T](implicit ev: Int =:= T): A[T] = A(ev(1))
  implicit val newA: A[Int] = A(2)               
  implicitly[A[Int]]
} 

The resolved implicit in implicitly[A[Int]] will be A(2) but removing the definition of newA the code still compiles but now implicitly[A[int]] resolves into A(1). So there would seem that there is two implicits available in the original code.

Is it a bug in the scala compiler that it does not produce a ambiguous implicit values error when compiling the original code?

I have tested this with scala 2.13.7, and scala 3.1.0 neither seem to produce a warning.

Overloading rules apply, and it prefers “no arg” over “takes an arg”.

Regular overloading, shown in Scala 3:

scala> class C { def f = 42 ; def f(i: Int) = i }
// defined class C

scala> C().f
val res1: Int = 42

scala> C().f(_)
val res2: Int => Int = Lambda$1335/0x000000080109d830@4f20b022

scala> class C { def f(i: Int) = i }
// defined class C

scala> C().f
val res3: Int => Int = Lambda$1345/0x00000008010c4410@5f3ddc86

The words in the spec are that f() is as specific as f if the second f takes the same params, which it doesn’t; and conversely, f is always as specific as another f that takes params. (Emphasis in original.)

If they haven’t yet, The Scala Store should make available a t-shirt that reads “as specific as” and then has an arrow pointing to the person next to you, like the old “I’m with so-and-so” t-shirts.

1 Like

It would be nice if -Xlint noticed that the val here is redundant.

Thanks for the explanation. But it seems like scala 2.13.7 handles a variation of this code incorrectly then. If the code is changed to

case class A[T](value: T)

object A {
  implicit def getA[T](implicit ev: Int =:= T): A[Int] = A(1)
  implicit val newA: A[Int] = A(2)               
  val i = implicitly[A[Int]]
}

This on Scala 2.13 fails the compilation with

error: ambiguous implicit values:
 both value newA in object A of type this.A[Int]
 and method getA in object A of type [T](implicit ev: Int =:= T): this.A[Int]
 match expected type this.A[Int]
  val i = implicitly[A[Int]]
                    ^

while scala 3.1.0 compiles the code without warnings.

IDK, but I’ve had a few guesses in the last several minutes.

Maybe it’s because Scala 3 looks at multiple parameter lists in overloading resolution, in order to support extension methods. The doc doesn’t say so, but maybe that includes implicit parameter lists.

Scala 2 only looks at the first parameter list, but that’s after an “applicability” test in which a second implicit parameter list would not disqualify a candidate.

My first thought was more clever: Probably the difference is in type inference described at the bottom here, about inferring the type of a function-valued parameter. Recall that Int =:= T is just Int => T. You changed the result type of getA from A[T] to A[Int], so I guess the presence of T helped Scala 2 because the expected type (from implicitly) is A[Int]. That hypothesis is wrong, so it should have a * in front of it.

Here is the difference in overloading, which shows the same result without type params.

  def f[T](implicit ev: Int =:= T): A[T] = A(1)
  val f: A[Int] = A(2)
  def g: A[Int] = f

  def f2[T](implicit ev: Int =:= T): A[Int] = A(1)
  val f2: A[Int] = A(2)
  def g2: A[Int] = f2       // scala 2 doesn't know what you mean

Without T, only Scala 2 takes this as ambiguous, and only if the param is implicit.

  def f3()(implicit s: String): A[Int] = A(1)
  def f3(): A[Int] = A(2)
  def g3: A[Int] = f3()

But isn’t that obviously ambiguous? in so far as f3() could mean either declaration. But in Scala 3, we only compare the signatures of the eligible members, which now includes all parameter lists.