I can't figure out how the Scala compiler figures out how to use flatMap with a sequence of Options.
If I use a flatMap on a sequence of sequences:
println(Seq(Seq(1), Seq()).flatMap(a => a)) // List(1)
it will concatenate all nested sequences
The same happens if I use it with a sequence of Options:
println(Seq(Some(1), None).flatMap(a => a)) // List(1)
So the flatMap treats Option as a collection in this case. The question is why does this work? The flatMap has the following definition:
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That
Meaning that it expects a function that returns an instance of GenTraversableOnce, but Option does not inherit GenTraversableOnce. It only inherits Product and Serializable, and Product inherits Equals.
How does Scala compiler can use the flatMap on the sequence of Options in this case?
In Scala, flatMap() method is identical to the map() method, but the only difference is that in flatMap the inner grouping of an item is removed and a sequence is generated. It can be defined as a blend of map method and flatten method.
The flatMap() method is similar to the map() method, but the only difference is that in flatMap, the inner grouping of an item is removed and a sequence is generated. The flatMap method acts as a shorthand to map a collection and then immediately flatten it.
Using flatMap() is useful when you want to add and remove items during a map() , as it can map many to many items by handling each input item separately, versus map() itself that is always one-to-one. This means the resulting array can grow during the mapping, and it will be flattened afterward.
Scala Seq is a trait to represent immutable sequences. This structure provides index based access and various utility methods to find elements, their occurences and subsequences. A Seq maintains the insertion order.
Your observation is right. In this case, if the compiler can't match the type, it looks for an implicit conversion and finds one in Option's companion object:
import scala.language.implicitConversions
/**
An implicit conversion that converts an option to an iterable value
*/
implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList
This makes it possible to treat Options as Iterables.
Also, your code can be simplified using flatten:
Seq(Some(1), None).flatten
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