Reputation: 7357
I just looked at the List.flatMap
declaration and was kind of surprised by this.
final override def flatMap[B, That](f: A => GenTraversableOnce[B])
(implicit bf: CanBuildFrom[List[A], B, That]): That
Where object List
defines:
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] =
ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]
So, if we invoke flatMap
on a List
we will get the List
and I don't see any point in That
type if it will always be deduced to List[B]
(because of the implicit
).
Upvotes: 5
Views: 146
Reputation: 149518
So, if we invoke
flatMap
on aList[A]
we will get theList[A]
and I don't see any point inThat
type if it will always be deduced toList[B]
One thing you're missing is that flatMap
isn't actually defined on List[+A]
. It is inherited from TraversableLike
, which is a trait used by most of Scalas collections. Each of them can supply the implicit CanBuildFrom
which may be overridden to supply a different resulting collection.
If you want a little taste of what you can do with a custom CanBuildFrom
:
scala> :pa
// Entering paste mode (ctrl-D to finish)
import scala.collection.generic.CanBuildFrom
import scala.collection.immutable._
import scala.collection.mutable
import scala.{List, Vector}
implicit val listToVectorCBF = new CanBuildFrom[List[Int], Int, Vector[Int]] {
override def apply(from: List[Int]): mutable.Builder[Int, Vector[Int]] = this.apply()
override def apply(): mutable.Builder[Int, Vector[Int]] = Vector.newBuilder
}
// Exiting paste mode, now interpreting.
scala> List(1,2,3).flatMap(List(_))
res6: Vector[Int] = Vector(1, 2, 3)
Upvotes: 5
Reputation: 13985
Well... That implicit CanBuildFrom
can be used to directly build different type of structure instead of List
and thus saving one extra step. lets look at following example,
val list = List(List(1, 2, 3), List(4, 5, 6))
// now if we do a flatmap withtout overriding the implicit CanBuildFrom
val newList = list.flatMap(l => l.map(i => (i,i)))
// new list will be a List[(Int, Int)]
// but what if you wanted a map
val newMap = newList.toMap
// But you actually needed to traverse the list twice in this case
// But we can avoid the second traversal if we chose to override the implicit
val newMap2 = list.flatMap(l => l.map(i => (i,i)))(collection.breakout)
Upvotes: 2