Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this call to implicitly ambiguous?

Tags:

scala

implicit

The signature of the sum method on TraversableOnce is as follows:

def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus)

I can use it thus:

scala> (1 to 10).sum
res0: Int = 55

In this case, the compiler is injecting the Numeric[B] itself, so there must be an unambiguous implicit value of this type in scope. If I use Predef.implicitly to inject it myself, this happens:

scala> (1 to 10).sum(implicitly)
<console>:6: error: ambiguous implicit values:
 both method conforms in object Predef of type [A]<:<[A,A]
 and method stringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String]
 match expected type T
   (1 to 10).sum(implicitly)
                 ^

Why is this ambiguous?

I can make the ambiguity disappear either by

scala> (1 to 10).sum(implicitly[Numeric[Int]])
res2: Int = 55

Or

scala> (1 to 10).sum[Int](implicitly)
res3: Int = 55

I presume that this has something to do with the fact that sum declares a new type parameter B >: A (it clearly is, see below edit), but I'm still confused about why something can be unambiguously found in the first example but not the second?

EDIT - to address subsub's inane comment (below)

scala> class As[A](as : A*) { 
 | def sum(implicit num : Numeric[A]) : A = as.foldLeft(num.zero)(num.plus) 
 | }
defined class As

scala> (new As(1, 2, 3, 4)).sum
res0: Int = 10

scala> (new As(1, 2, 3, 4)).sum(implicitly)
res1: Int = 10

So, you can see that it is not the case that any call to implicitly is ambiguous

like image 294
oxbow_lakes Avatar asked Apr 06 '11 09:04

oxbow_lakes


1 Answers

Short answer: Because of B >: A resulting type for implicitly call can not be inferred.

Longer answer. When argument defined as implicit is missing, compiler will search current scope for any implicit value of type Numeric[B >: Int] and will use the most specific - Numeric[Int].

But if you specify argument as implicitly (a call to the implicitly [T] (implicit e: T) : T) first the type argument T must be resolved. And scala runtime clearly fails to do so.

It is the same as calling this:

scala> var f = implicitly
 <console>:5: error: ambiguous implicit values:
 both method conforms in object Predef of type [A]<:<[A,A]
 and method stringCanBuildFrom in object Predef of type =>     scala.collection.generic.CanBuildFrom[String,Char,String]
 match expected type T
       var f = implicitly
               ^
like image 172
Nikita Skvortsov Avatar answered Nov 17 '22 20:11

Nikita Skvortsov