🎓 A1Learner
🔍
0 of 45 lessons completed

Future Composition Patterns

Future composition is the joining of futures into one pipeline. Each step in the pipeline uses the result of the step before it.

flatMap chains a dependent future

The second future needs the first result. flatMap feeds that result into the second future.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def main(): Unit =
  val step1 = Future(10)
  val combined = step1.flatMap(x => Future(x + 5))
  println(Await.result(combined, 5.seconds))

map changes the value inside a future

The value inside the future is tripled. No second future is started for this change.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def main(): Unit =
  val doubled = Future(6).map(x => x * 3)
  println(Await.result(doubled, 5.seconds))

A for-comprehension writes the chain plainly

The price is fetched first. The total then adds five to that price.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def main(): Unit =
  val total = for
    price <- Future(20)
    withFee <- Future(price + 5)
  yield withFee
  println(Await.result(total, 5.seconds))

Example

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def main(): Unit =
  val result = for
    a <- Future(8)
    b <- Future(a * 2)
    c <- Future(b + 4)
  yield c
  println(Await.result(result, 5.seconds))

Key points

  • Pipeline: A pipeline is a chain of steps where each step feeds the next step.
  • Use flatMap to run a second future that depends on the first future result.
  • Use map to change the value inside a future without starting a new future.
  • For-comprehension: A for-comprehension is a shorter way to write a chain of flatMap and map steps.
  • Order: Steps in a pipeline run in written order when each step depends on the previous result.

In this example, a starts as 8. Then b doubles a to 16. Then c adds 4 to b to give 20, and the program prints that final value.

Note

A future starts running as soon as it is created, so building a pipeline does not delay the first step.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Scastie

Exercise

What does Future(5).flatMap(x => Future(x * 2)) give when awaited?