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 typeTowith 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