11

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

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • 1
    It's as ambiguous as any call to implicitly. `scala> Predef.implicitly :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 Predef.implicitly`. So possibly the underlying meaning is something along the lines of "didn't find any suitable implicit thing here, please help!" – subsub Apr 06 '11 at 12:26
  • @subsub - see my edit. That's exactly what is going on; I'm asking why the call to implicitly is being inferred as resulting in an ambiguous implicit. If there are matching implicit values in cope, why is the no-param call having similar problems? – oxbow_lakes Apr 06 '11 at 13:27
  • if my comment was inane why did you edit your question? Well, here's another one: `class Bs[A](bs : TraversableOnce[A]) { def sum(implicit num : Numeric[A]) : A = bs.foldLeft(num.zero)(num.plus) }; (new Bs(1 to 10)).sum(implicitly) ` – subsub Apr 06 '11 at 14:00
  • To prove to you how inane it was. I asked why a call to `implicitly` was ambiguous in a **specific case**. You answered: "well, it's ambiguous over here" *for a completely different case*! – oxbow_lakes Apr 06 '11 at 14:31
  • interestingly the accepted answer includes that inane completely different case ;-) – subsub Apr 07 '11 at 15:13

1 Answers1

6

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
               ^
Nikita Skvortsov
  • 4,768
  • 24
  • 37