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
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
^
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With