I stumbled accross Predef.StringCanBuildFrom
surprising implementation that breaks assumptions I was making on CanBuildFrom
in my code. Here's the implementation:
implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] =
new CanBuildFrom[String, Char, String] {
def apply(from: String) = apply()
def apply() = mutable.StringBuilder.newBuilder
}
It seems totally unnatural that apply(String)
simply ignores the parameter. To me, the correct implementation should be
implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] =
new CanBuildFrom[String, Char, String] {
def apply(from: String) = apply() ++= from
def apply() = mutable.StringBuilder.newBuilder
}
but it seems so trivial that I can't believe I'm the ony one to have spotted that since the language exists. I was tempted to open an issue for this, but if I'm missing any good reason to not do what I proposed, please tell me !
I think you are misunderstanding the purpose of apply(from)
.
It's documentation says:
Creates a new builder on request of a collection.
@param from the collection requesting the builder to be created.
@return a builder for collections of typeTo
with element typeElem
. The collections framework usually arranges things so that the created builder will build the same kind of collection asfrom
.
So it's used to resolve the builder using the runtime type of the collection, and maybe to copy some auxiliary data from the original collection. For example, the implementation in scala.collection.generic.GenTraversableFactory#GenericCanBuildFrom
is simply def apply(from: Coll) = from.genericBuilder[A]
. As you see no actual data is copied from the argument collection.
Actually, your implementation of CanBuildFrom
would produce wrong results for the standard implementations of map
, flatMap
and other generic functions:
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable
implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] =
new CanBuildFrom[String, Char, String] {
def apply(from: String) = apply() ++= from
def apply() = mutable.StringBuilder.newBuilder
}
scala> "foo".map(identity)(stringCanBuildFrom)
res1: String = foofoo
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