Amol Pol
Amol Pol

Reputation: 1682

Why do we use flatten? How is it different from flatMap?

In scala, why do we use flatten? How is it different from flatMap? Examples which involve Futures would be very useful.

Upvotes: 0

Views: 579

Answers (1)

lex82
lex82

Reputation: 11307

flatten does not involve the "map" part of flatMap. Think of it as just flattening nested structures. An Option[Option[Int]] becomes just an Option[Int] or a List[List[Int]] becomes a List[Int] (by concatenating the elements of the individual lists).

On the contrary, mapping changes the elements contained in the structures. So

Some(4).map(_ + 1) // evaluates to Some(5)

Sometimes the function passed to map returns an instance of the underlying structure itself. Say you have an optional id and if it is set you want to look it up in a database not knowing if a record is present, thus your function also returns an Option:

val optionalId: Option[String] = ???
def getRecord(id: String): Option[Record] = ???

val naiveResult: Option[Option[Record]] = optionalId.map(getRecord)

This is usually not what you want. In essence you have an Option[Record] and the extra nesting is not needed. So you would call flatten right after the map:

optionalId.map(getRecord).flatten // evaluates to an Option[Record]

Now flatMap is essentially the combination of both in one method:

optionalId.flatMap(getRecord) // also yields an Option[Record]

The application of flatMap is not limited to collections but much more general. Another example where it comes in handy is futures. Let's say we don't have an optional id but a Future[String] that represents a computation that will eventually yield the id. We also have a method that gives us a Future[Record] for an id. We can now obtain a Future[Record] from the Future[String] like this:

val idFuture: Future[String] = ???
def getRecord(id: String): Future[Record] = ???

val recordFuture: Future[Record] = idFuture.flatMap(getRecord)

Upvotes: 3

Related Questions