Lgd. Viktor Klang

Systems all the way down

Viktor Klang bio photo


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

Transforming when and where

Most readers will be familiar with Future-based code which looks something like this:

import scala.concurrent._
import ExecutionContext.Implicits._
def someCalculation(i: Int): Future[Int] = Future.successful(i) // placeholder

val f = someCalculation(42).map(_ * 10).filter(_ > 0).map(_ / 2))

f foreach println // prints 210

Let’s deconstruct what’s going on here:

First we perform someCalculation and then we multiply the result by 10, then we filter the result for positive integers and then we divide by 2.

But, for each of these steps we create an additional Future and schedule it to run on our designated ExecutionContext—in this case introducing significant overhead for these very simple operations.

A cheaper way (sometimes)

If we know that we’re going to use the same ExecutionContext, and we’re willing to make more calculations in one go, we can since Scala 2.12 use transform and run the transformations on Try directly, as transform takes a function from Try[T] to Try[U], which looks something like this:

import scala.concurrent._
import ExecutionContext.Implicits._
def someCalculation(i: Int): Future[Int] = Future.successful(i) // placeholder

val f = someCalculation(42).transform(_.map(_ * 10).filter(_ > 0).map(_ / 2))

f foreach println // prints 210

andThen more fun

Knowing this, we can compose many of the simple transformations we want to apply as functions from Try -> Try, as shown here:

import scala.concurrent._
import scala.util.Try
import ExecutionContext.Implicits._
def someCalculation(i: Int): Future[Int] = Future.successful(i) // placeholder

val times10 = (t: Try[Int]) => t.map(_ * 10)
val filterPos = (t: Try[Int]) => t.filter(_ > 0)
val divBy2 = (t: Try[Int]) => t.map(_ / 2)

val f = someCalculation(42).transform(times10 andThen filterPos andThen divBy2)

f foreach println // prints 210

Click here for the next part in this blog series.

Cheers,