Klang Heavy Industries

We manufacture the most promising of futures.

Viktor Klang bio photo

This is the second of several posts describing protips for scala.concurrent.Future. For the previous post, click here.

Futures in for-comprehensions

A common choice when working with scala.concurrent.Future’s is to use them inside for-comprehensions. What I am about to show you is a common mistake to make, and how to avoid it.

The Problem

So let’s say you’ve written something similar to the following:

def doSomething(someParameter: SomeType)
               (implicit ec: ExecutionContext): Future[Something] =
  for {
    v1 <- Future(someCalculation())
    v2 <- Future(someOtherCalculation())
    v3 <- Future(someDifferentCalculation())
  } yield doSomethingWith(v1, v2, v3)

Well, it turns out that since the three calculations are independent, that the desire—and intent—of the method is to execute all the calculations in parallel and then combine their results in the doSomethingWith-method, and return everything inside a Future.

However, since for-comprehensions are simply syntactic bacon for flatMap, map, filter/withFilter, and foreachv2 will only be created once v1 has completed, and v3 will once be created once both v1 and v2 are completed.

What to do?

The Solution

What if we instead leverage the fact that for-comprehensions support value definitions once the “generator”—the first x <- y expression—has been given, and that consecutive value definitions are evaluated as regular value definitions—immediately after eachother?

def doSomething(someParameter: SomeType)
               (implicit ec: ExecutionContext): Future[Something] =
  for {
    _ <- Future.unit // Or Future.successful(())
    f1 = Future(someCalculation())
    f2 = Future(someOtherCalculation())
    f3 = Future(someDifferentCalculation())
    v1 <- f1
    v2 <- f2
    v3 <- f3
  } yield doSomethingWith(v1, v2, v3)

The solution above will execute f1, f2, and f3—if possible—in parallel, and then extract their values and combine them with the doSomethingWith method. Just like we intended when we wrote the for-comprehension the first time.

Click here for the next part in this blog series.