Published on

Futures in Concurrent Programming (with examples in Scala)

Authors
  • avatar
    Name
    Benton Li
    Twitter

I will finish it in the future, but it’s no promise.

— Benton Li

Overview

In the previous blog, we see some usage of Promise in JavaScript. However, the formal definition of a promise is different from JS’s Promise but is more similar to JS’s Deferred, which is less commonly used. My bold claim is that a promise is an extension or wrapper of a future. That is, you can actually implement a promise using a future. In Java, promise is known as CompletableFuture. In Scala, a Future is embedded in a Promise.

Future

According to the Future trait in Scala (source code),

a future represents a value which may or may not currently be available, but will be available at some point, or an exception if that value could not be made available.

Sounds pretty similar to the Promise in JavaScript, right? Let’s revisit our previous example. Say, your girlfriend wants you to make an omelet for her. This is a future (technically this is a request). At some point in the future, either an omelet is available, or something goes wrong (exception). Here, the egg being cooked is the value and your omelet pan is the future. Let’s turn this into codes (try them in Scala REPL!)

import scala.util.Random
import scala.concurrent.Future
import concurrent.ExecutionContext.Implicits.global

val pan = Future[String] {
	val rand = new Random()
	val eggOk = Random.nextBoolean()
	Thread.sleep(1000)
	eggOk match {
		case true => "omelet"
		case false => throw new Exception("charcoal")
	}
}
// val pan: scala.concurrent.Future[String] = Future(<not completed>)

Wait for a second and see what’s in the omelet pan

pan
/**
	* val res: scala.concurrent.Future[String] = Future(Success(omelet))
	* or
	* val res: scala.concurrent.Future[String] = Future(Failure(java.lang.Exception: charcoal))
	*/

Of course you can add handlers to this future

pan.onComplete {
  case Success(egg) => println(s"Yummy ${egg}")
  case Failure(e) => println(s"Ayo you are gonna poison me with ${e.getMessage}?")
}

Seems that this onComplete is like a combination of then and catch in JS!

Note on onComplete

n.b. There were onSuccess and onFailure in previous versions of Scala. But they are now deprecated. Let’s look at their function signatures.

onSuccess[U](pf: PartialFunction[Nothing, U])(implicit executor: ExecutionContext): Unit
onFailure[U](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit
onComplete[U](f: Try[Nothing] => U)(implicit executor: ExecutionContext): Unit

The good news is that, instead of writing two partial callback functions, now you only need to write a single callback. Here, Try[T] is equivalent to Either[Throwable, T]

The source code of Future.scala is here

ExecutionContext

In the first snippet, we import concurrent.ExecutionContext.Implicits.globaland the onComplete function has a parameter implicit executor of ExecutionContext type.

Ah, this is some crap that no one needs to worry about in when writing Promise in JS.

ExecutionContext is a virtual place where computations take place asynchronously. It is very similar to the ThreadPoolExecutorin Python.

ExecutionContext.global in Scala is essentially a ForkJoinPool. We use global for illustration purpose only. Depending on the scenario, you might want to choose or even implement an ExecutionContext to use resources optimally.

For example, when you do matrix multiplication, which is likely to take a longtime, you can put them in a Future to prevent blocking. But matrix multiplication is just a series of multiplication and additions. You can split the calculations into chunks, and run chunks on multiple cores in parallel.

Just imagine you are making multiple omelets. A kitchen with multiple stoves is probably desirable.

Read more

Scala Docs: overviews of Futures and Promises

Scala Docs: ExecutionContext

Future.scala source code