Should Scala map () behave differently when matching with the same type?

In the Scala Collections framework, I believe that map()there are several types of behavior that are incompatible when used .

We can distinguish between two types of transformations on (immutable) collections. Those whose implementation calls newBuilderto recreate the result set, and those who go implicitly CanBuildFromto get the builder.

The first category contains all transformations in which the type of contained elements does not change. This, for example, filter, partition, drop, take, span, etc. These transformations can be called up newBuilderand recreated the same type of collection as the one they cause, no matter how specific: filtering List[Int]can always return List[Int]; filtering a BitSet(or the exemplary structure RNAdescribed in this article about the architecture of the collection framework ) can always return another BitSet(or RNA). We call them filtrational transformations.

The second category of transformations needs CanBuildFromto be more flexible, because the type of elements contained can change, and as a result, the type of the collection itself may not be reused: a BitSetcannot contain Strings; a RNAcontains only Bases. Examples of such transformations are map, flatMap, collect, scanLeft, ++etc. We call them mapping transformations.

Now here is the main issue for discussion. Regardless of the type of static collection type, all filtering transformations return the same collection type, while the collection type returned by the matching operation may vary depending on the static type.

scala> import collection.immutable.TreeSet
import collection.immutable.TreeSet

scala> val treeset = TreeSet(1,2,3,4,5) // static type == dynamic type
treeset: scala.collection.immutable.TreeSet[Int] = TreeSet(1, 2, 3, 4, 5)

scala> val set: Set[Int] = TreeSet(1,2,3,4,5) // static type != dynamic type
set: Set[Int] = TreeSet(1, 2, 3, 4, 5)

scala> treeset.filter(_ % 2 == 0)
res0: scala.collection.immutable.TreeSet[Int] = TreeSet(2, 4) // fine, a TreeSet again

scala> set.filter(_ % 2 == 0)    
res1: scala.collection.immutable.Set[Int] = TreeSet(2, 4) // fine

scala> treeset.map(_ + 1)        
res2: scala.collection.immutable.SortedSet[Int] = TreeSet(2, 3, 4, 5, 6) // still fine

scala> set.map(_ + 1)    
res3: scala.collection.immutable.Set[Int] = Set(4, 5, 6, 2, 3) // uh?!

, . . , CanBuildFrom , def apply(from: Coll), .

, , , , ( ), . BitSet Int s, TreeSet ..

,

for (i <- set) {
  val x = i + 1
  println(x)
}

TreeSet ,

for (i <- set; x = i + 1)
  println(x)

:

  • , , ?
  • , ?
  • ?

- implicit sameTypeEvidence: A =:= B, , null (, , implicit canReuseCalleeBuilderEvidence: B <:< A = null), , CanBuildFrom, , .

+5
1

, , - Scala, TreeSet. :

val list = List(1,2,3,4,5)
val seq1: Seq[Int] = list
seq1.map( _ + 1 ) // yields List

val vector = Vector(1,2,3,4,5)
val seq2: Seq[Int] = vector
seq2.map( _ + 1 ) // yields Vector

, , TreeSet -/:

seq1.companion.newBuilder[Int]    // ListBuffer
seq2.companion.newBuilder[Int]    // VectorBuilder
treeset.companion.newBuilder[Int] // Set (oops!)

, , RNA, , map filter , ...?

+1

All Articles