Akka Futures: Using For Comprehensions


In my previous post I discussed about composing Futures. I also discussed that Futures are monadic and they can be composed using map or flatmap. Since, for comprehension is just a sugar on top we can use it as well. Lets understand their usage in a bit more detail than my previous post.

Using the same example of direct use of Futures and using a timeTakingIdentity function. Code snippet below has two future creation and a function definition.

def timeTakingIdentityFunction(number: Int): Int = {
   // sleeping three seconds
   Thread.sleep(3000)
   number
}

val future1 = Future(timeTakingIdentityFunction(1))
val future2 = Future(timeTakingIdentityFunction(2))

Now we need to run them in parallel. The way to do this is to construct a single Future out of future1 and future2 and collect the result from them.

Since Future is a Monad we have useful methods like map and flatMap to compose a new Future. The resulting Future can then be used for assembling result. Lets use just a map method and see what happens.

Using future1 first we can call map method on it. We can then use nested map method on future2. On the inner map method we can then sum result1 and result2. We expect this Future to help us getting sum of two results from timeTakingIdentityFunction.

  val future1 = Future(timeTakingIdentityFunction(1))
  val future2 = Future(timeTakingIdentityFunction(2))

  // This will give us Future[Future[Int]]. This is not we want
  val finalFutureFuture = future1 map {
    result1 =>
      future2 map {
        result2 => result1 + result2
      }
  }

  def timeTakingIdentityFunction(number: Int): Int = {
    Thread.sleep(3000)
    number
  }


Not surprisingly, what we get is a Future[Future[Int]]. Not entirely useful conciseness wise. We need a final future that is a Future of Int. This is why we use a flatMap. We can make it work using a flatMap on future1 and then a map on future2. Here is the code.

  // we use flatMap instead for composition
  val finalFuture = future1 flatMap {
    result1 =>
      future2 map {
        result2 => result1 + result2
      }
  }

If we want, we can use this to get sum of two results from timeTakingIdentityFunction. Here is the complete code listing of an Application.

import akka.actor._
import akka.dispatch._

object FutureApp extends App {
  implicit val system = ActorSystem("future")
  val startTime = System.currentTimeMillis

  val future1 = Future(timeTakingIdentityFunction(1))
  val future2 = Future(timeTakingIdentityFunction(2))

  val finalFuture = future1 flatMap {
    result1 =>
      future2 map {
        result2 => result1 + result2
      }
  }

  finalFuture onSuccess {
    case sum => println("Sum of results from timeTakingIdentityFunction is " + sum + " calculated in " + (System.currentTimeMillis - startTime) / 1000 + " seconds")
  }

  def timeTakingIdentityFunction(number: Int): Int = {
    Thread.sleep(3000)
    number
  }

}

We made two calls to timeTakingIdentityFunction and got result in three seconds!!

But this is not a concise way to do things. Imagine there is a third future then our code will start looking a bit messy.

  val anotherFinalFuture = future1 flatMap {
    result1 =>
      future2 flatMap {
        result2 =>
          future3 map {
            result3 => result1 + result2 + result3
          }

      }
  }

For this we use for expressions. It is a sugar on top and here is a concise code we can use.

  val finalFutureUsingForExpression = for {
    result1 <- future1
    result2 <- future2
    result3 <- future3
  } yield result1 + result2 + result3

You can compare how better it is!!

Now there is a common pitfall we can get into when composing futures. I did it too. Rule of the thumb is to create Futures before you get into composing them. For example the code below will run in nine seconds.

  val finalFutureUsingFaultyForExpression = for {
    result1 <- Future(timeTakingIdentityFunction(1))
    result2 <- Future(timeTakingIdentityFunction(2))
    result3 <- Future(timeTakingIdentityFunction(3))
  } yield result1 + result2 + result3

It is so because creation of future2 and future3 happens after first future completes. Not so hard figuring it out but a common error nonetheless :)

We did composing futures using map and flatMap. We also used for expressions and noticed they are so better. And we know now the rule of the thumb is to create them before we go about composing them.

This entry was posted in Scala and tagged , , . Bookmark the permalink.

One Response to Akka Futures: Using For Comprehensions

  1. Pingback: Knolx Session: Using Akka Futures | Knoldus

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s