This is the second of several posts describing the evolution of scala.concurrent.Future
in Scala 2.12.x
.
For the previous post, click here.
Missing canonical combinators: zipWith
Being able to join two Future
s together to produce a new Future
which contains a Tuple
of the results of both has been available for a while with the zip
operation, and this looks something like this:
val future1: Future[String] = …
val future2: Future[Int] = …
val zippedFuture: Future[(String, Int)] = future1 zip future2
But what if we don’t want a Tuple
? What if we want to combine the results
of the two Future
s to create something else?
This typically means having to combine zip
and map
:
/* The reason why we use a «PartialFunction literal» (yes, I made that up)
* here is because otherwise the code has to use the arguably uglier _._1 and
* _._2 syntax for `Tuple` value extraction.
*/
val combinedFuture: Future[String] =
future1 zip future2 map { case (string, int) => s"$string & $int" }
Now, if you’re like me and you dislike allocations, tuples and lack of genericity, you’ll see that zip
is a specialization of x.zipWith(y)(Tuple2.apply)
! Well, perhaps it helps if we share the signature of said zipWith
:
def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R]
This allows us to express the example above as:
val combinedFuture: Future[String] =
future1.zipWith(future2)((string, int) => s"$string & $int")
Benefits:
- Less to type
- Less to read
- Fewer allocations
- Fewer asynchronous steps
- More general than
zip
Click here for the next part in this blog series.
Cheers,
√