Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Predef.StringCanBuildFrom's behaviour

Tags:

scala

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 !

like image 831
Dici Avatar asked Oct 17 '22 18:10

Dici


1 Answers

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 type To with element type Elem. The collections framework usually arranges things so that the created builder will build the same kind of collection as from.

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 
like image 57
Kolmar Avatar answered Oct 20 '22 22:10

Kolmar