Consider the following REPL session:
@ def test[C[X] <: TraversableOnce[X]](implicit cbf: CanBuildFrom[C[Int], Int, C[Int]]) = cbf()
defined function test
@ test[List]
res32: collection.mutable.Builder[Int, List[Int]] = ListBuffer()
@ def test[C[X] <: TraversableOnce[X]] = implicitly[CanBuildFrom[C[Int], Int, C[Int]]]
cmd33.sc:1: Cannot construct a collection of type C[Int] with elements of type Int based on a collection of type C[Int].
def test[C[X] <: TraversableOnce[X]] = implicitly[CanBuildFrom[C[Int], Int, C[Int]]]
^
Compilation Failed
The first definition of test
function compiles and works, while the second one doesn't compile. The only difference between them is the way how the instance of CanBuildFrom
is obtained. In first case it's declared as implicit parameter, requiring the compiler to find one. In second case it's invoked via implicitly
function, which, in theory, should behave the same in terms of implicit search scope. What causes this behavior?
The definition of
implicitly
(inPredef
) is:It simply makes explicit to you an implicit already in scope (at the use site).
Now when you write this:
You are asking the caller to provide an implicit (at the call site).
When you write
You are asking the compiler with the call
implicitly
to look-up an implicit already in scope. But you are not having any implicit of the given type in scope! So the two definitions oftest
are doing something entirely different.You use
implicitly
normally to get hold of an implicit to which you don't have the name, because it was specified using the context-bounds or type-class notation, likedef test[A: TypeClass]
. You cannot use that notation here becauseCanBuildFrom
has three type parameters and not one. So you cannot do much withimplicitly
here.You could use
implicitly
with your first case:But then you already know that you have that implicit with name
cbf
...Note that you can get hold of an implicit
CanBuildFrom
for a known collection type:But this doesn't work if your collection type (
C[X]
) is abstract.