Some people will find that using a function called map
to convert a Future[Response]
into a Future[Result]
may seem a little strange. Let’s try to build some intuition around it.
map
is actually a functional programming concept that's easiest to understand when thinking about Lists. If you call map
on a List
, you get back a new List
where each element of the new List
is the result of applying a function to each element of the originalList
. For example, consider this lower
function:
What happens if we map
this function over a List
of Strings?
We get back a new List
of Strings that are all lower case. In other words, we transformed a List[String]
into a new List[String]
.
It’s also possible to use map
to convert a List[X]
into a List of some other type, such as a List[Y]
. For example, consider this strlen
function:
What happens if we map
this function over the same List
of Strings?
We now get back a new List
, where each element represents the length of a String in the original List
. That is, we’ve now transformed a List[String]
into a new List[Int]
.
Let’s look at one more case: a function called explode
that returns a List
of all the characters in the given String:
Look at what happens if we map
our List
of Strings over explode
:
We’ve now transformed a List[String]
into a new List[List[Char]]
. What if we didn’t want to have the nested List-in-a-List? To do that, we can use flatMap
instead of map
:
As the name implies, flatMap
behaves just like map
, except it combines (flattens) the nested Lists
into a single, flat List
.
The map
and flatMap
functions aren’t unique to Lists
. They are just as useful for other types of "containers", such as Array
, Set
, Map
, and so on:
As it turns out, a Future[T]
is also a "container": it’s a bit of a strange one, in that it contains just one element, but the same map
and flatMap
functions can be used to transform a Future[X]
into a Future[Y]
:
One detail that we’ve glossed over is that the "container" class controls when it actually calls the functions passed into map
and flatMap
. A List
may call the function immediately. However, a Future
will only do it when the I/O has completed and data is available.
This is ok, because the return value for Future.map
and Future.flatMap
is anotherFuture
. You can immediately transform, compose, and reason about this returned value because it also will control when it calls any functions passed to its map
, flatMap
, and other methods.