Permalink
Browse files

Refactor OnceCanBuildFrom to check the collection type.

The builder is now instantiated as an iterator builder only
if a generic builder cannot be found on the collection that
requested the builder.

Reason - we want this behaviour:

scala> scala.util.Random.shuffle(List(1, 2, 3): collection.TraversableOnce[Int])
res0: scala.collection.TraversableOnce[Int] = List(3, 1, 2)

instead of this one:

scala> scala.util.Random.shuffle(List(1, 2, 3): collection.TraversableOnce[Int])
res0: scala.collection.TraversableOnce[Int] = non-empty iterator

which may lead to nasty surprises.

Alternately, to avoid pattern-matching in OnceCanBuildFrom.apply, we
could mix in GenericTraversableTemplate-related functionaly into
TraversableOnce, but this may become too complicated.
  • Loading branch information...
Aleksandar Prokopec Aleksandar Prokopec
Aleksandar Prokopec authored and Aleksandar Prokopec committed May 1, 2012
1 parent 5f29da7 commit 187817b7969aecfcec68dfc910c5a01e57d8edc4
Showing with 16 additions and 6 deletions.
  1. +2 −1 src/library/scala/collection/Iterator.scala
  2. +14 −5 src/library/scala/collection/TraversableOnce.scala
@@ -26,7 +26,8 @@ object Iterator {
* See `scala.util.Random.shuffle` for an example.
*/
implicit def IteratorCanBuildFrom[A] = new TraversableOnce.BufferedCanBuildFrom[A, Iterator] {
def toColl[B](coll: ArrayBuffer[B]) = coll.iterator
def bufferToColl[B](coll: ArrayBuffer[B]) = coll.iterator
def traversableToColl[B](t: GenTraversable[B]) = t.toIterator
}
/** The iterator which produces no values. */
@@ -367,16 +367,23 @@ object TraversableOnce {
implicit def flattenTraversableOnce[A, CC[_]](travs: TraversableOnce[CC[A]])(implicit ev: CC[A] => TraversableOnce[A]) =
new FlattenOps[A](travs map ev)
abstract class BufferedCanBuildFrom[A, Coll[X] <: TraversableOnce[X]] extends generic.CanBuildFrom[Coll[_], A, Coll[A]] {
def toColl[B](buff: ArrayBuffer[B]): Coll[B]
/* Functionality reused in Iterator.CanBuildFrom */
private[collection] abstract class BufferedCanBuildFrom[A, Coll[X] <: TraversableOnce[X]] extends generic.CanBuildFrom[Coll[_], A, Coll[A]] {
def bufferToColl[B](buff: ArrayBuffer[B]): Coll[B]
def traversableToColl[B](t: GenTraversable[B]): Coll[B]
def newIterator: Builder[A, Coll[A]] = new ArrayBuffer[A] mapResult toColl
def newIterator: Builder[A, Coll[A]] = new ArrayBuffer[A] mapResult bufferToColl
/** Creates a new builder on request of a collection.
* @param from the collection requesting the builder to be created.
* @return the result of invoking the `genericBuilder` method on `from`.
*/
def apply(from: Coll[_]): Builder[A, Coll[A]] = newIterator
def apply(from: Coll[_]): Builder[A, Coll[A]] = from match {
case xs: generic.GenericTraversableTemplate[_, _] => xs.genericBuilder mapResult {
case res => traversableToColl(res.asInstanceOf[GenTraversable[A]])
}
case _ => newIterator
}
/** Creates a new builder from scratch
* @return the result of invoking the `newBuilder` method of this factory.
@@ -389,9 +396,11 @@ object TraversableOnce {
* See `scala.util.Random.shuffle` or `scala.concurrent.Future.sequence` for an example.
*/
class OnceCanBuildFrom[A] extends BufferedCanBuildFrom[A, TraversableOnce] {
def toColl[B](buff: ArrayBuffer[B]) = buff.iterator
def bufferToColl[B](buff: ArrayBuffer[B]) = buff.iterator
def traversableToColl[B](t: GenTraversable[B]) = t.seq
}
/** Evidence for building collections from `TraversableOnce` collections */
implicit def OnceCanBuildFrom[A] = new OnceCanBuildFrom[A]
class FlattenOps[A](travs: TraversableOnce[TraversableOnce[A]]) {

0 comments on commit 187817b

Please sign in to comment.