Sunday, 5 February 2017

Scala Future and Promise API With Examples

Post Brief TOC

  • Introduction
  • Scala Future API
  • Scala Promise API
  • Scala Promise API
Let us start exporting Scala Future and Promise API with some simple examples now.

Introduction

Scala Future and Promise API is defined in scala.concurrent package. This API is used to develop Concurrent and Parallel applications in Scala Language.
Future represents a Computation unit. This unit is executed by Promise and put into the Future.
In simple words, Future is an object to read that result and Promise is an object to execute that computation unit. Let us explore these concepts in-depth with some useful examples in the coming sections.




NOTE:- Please support my Blog by clicking Ads to deliver more and more useful tutorials.

Scala Future API

Future[T] contains a computation unit of type T. This computation is done sometime in future either successfully or not.
What is Computation Unit?
A Computation Unit is a block of code (which is used to perform a task or calculate some value etc.)
Generally, this Computation unit runs Synchronously. If we place this Computation unit in Future, it runs in Asynchronously.
If this computation is completed successfully, Future contains a value of type T.
If this computation is completed with failure, Future contains an exception of Type Throwable.
Like Scala Constructs: Option, Either, Try etc., Scala Future is also a Container type. It may contain a value or an exception in future.
It is write-only-once container. Once it’s completed, we cannot change it’s value that means it becomes Immutable.
Who writes that value into Future: Promise (Will discuss it in next section).
Future Companion Object:
object Future{
  def apply[T](body: => T): Future[T]
}
Here computation unit is body. As it’s computed Asynchronously, it is defined as “By-Name Parameter”.
Example:-
scala> import scala.concurrent.Future
import scala.concurrent.Future

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> val intFuture = Future(10)
intFuture: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@6b9ce1bf

Or

scala> val intFuture = Future{10}
intFuture: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@6b9ce1bf
We can use either parentheses or curly braces.
scala> val nameFuture = Future("Rams")
nameFuture: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@19fe4644

scala> nameFuture.value
res5: Option[scala.util.Try[String]] = Some(Success(Rams))

scala> nameFuture.value.get
res6: scala.util.Try[String] = Success(Rams)

scala> nameFuture.value.get.get
res7: String = Rams
Future Trait Definition:
trait Future[+T] extends Awaitable[T]{
 def map[S](f: T => S) :Future[S]
    def flatMap[S](f: T => Future[S]) :Future[S]
}
Complete Scala Future API:
Almost all Future functions contains ExecutionContext as implicit parameter.
object Future{
  def apply[T](body: => T)(implicit executor: ExecutionContext): Future[T]
}
trait Future[+T] extends Awaitable[T]{
 def map[S](f: T => S)(implicit executor: ExecutionContext) :Future[S]
    def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext) :Future[S]
}
Here executor is an implicit parameter, we don’t need to specify it.

What is an ExecutionContext?

ExecutionContext is a place where our Future’s Computation unit is executed.
Scala Language gives us a ready-made static global ExecutionContext in scala.concurrent.ExecutionContext.global.
NOTE:- In simple words, ExecutionContext is something similar to a Thread Pool (Java Guys also can understand this).
Future.sequence()
Future combinator API
Converting a list of Futures into a Single Future that means Collections of Futures into a Single Future
List[Future[T]] ======> List[T]
Example:-
scala> val pricesList:List[Future[Int]] = List(Future(1001),Future(999),Future(-2000),Future(1000))
pricesList: List[scala.concurrent.Future[Int]] = List(scala.concurrent.impl.Promise$DefaultPromise@680a66dd, scala.concurrent.impl.Promise$DefaultPromise@2dd8239, scala.concurrent.impl.Promise$DefaultPromise@472698d, scala.concurrent.impl.Promise$DefaultPromise@7b7683d4)

scala> val maxPrice:Future[Int] = Future.sequence(pricesList).map(_.max)
maxPrice: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@14fded9d

scala> maxPrice.map { price => println("Max price = " + price) }
res0: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@ebda593
Max price = 1001

Scala Promise API

As we discussed, Future is a placeholder to hold a computation unit (which retuns a value or exception and which does not yet exist). It is used to read that result. Where as Promise is used to finish that computation and write value into Future.
So, Future is used to read that value where as Promise is used to write that value.
In simple words, we can say that Future is used to Query or Read the result and Promise is used to Write or Put the result.
As we discussed, We can write the result into a Future only once. Once it is done, we cannot change that value. So Promise can write a value into Future only once.
A Promise instance is always linked to exactly one and only one instance of Future.
object Promise[T] {
  def apply[T](): Promise[T]
}
trait Promise[T]{
 def success(value: T) : this.type
 def failure(cause: Throwabale): this.type

  def future: Future[T]
}
Example:-
Empty Promise to Future
scala> val cityPromise = Promise[String]()
cityPromise: scala.concurrent.Promise[String] = scala.concurrent.impl.Promise$DefaultPromise@7f36b021

scala> val cityFuture = cityPromise.future
cityFuture: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@7f36b021

scala> cityFuture.value
res11: Option[scala.util.Try[String]] = None
Once a Promise or Future is completed (either successfully with a result or failure with an Exception), we cannot rerun them. Doing so will throw an error as shown below:
Example:-
scala> cityPromise.success("Hyderabad")
java.lang.IllegalStateException: Promise already completed.
Promise to write value to Future
Example:-
scala> val cityPromise = Promise[String]()
cityPromise: scala.concurrent.Promise[String] = scala.concurrent.impl.Promise$DefaultPromise@7d07e6aa

scala> cityPromise.success("Hyderabad")
res13: cityPromise.type = scala.concurrent.impl.Promise$DefaultPromise@7d07e6aa

scala> cityPromise.future.value.get.get
res15: String = Hyderabad

scala> cityPromise.future.map{ value => println(value) }
res16: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@770d65c2
Hyderabad
That is about Scala Future and Promise API with some simple examples.
NOTE:- Please support my Blog by clicking Ads to deliver more and more useful tutorials.
That’s it all about “Scala/Java Concurrency and Parallelism related Interview Questions and Answers”. We will discuss some more Scala Interview Questions in my coming posts.
Please drop me a comment if you like my post or have any issues/suggestions.
I love your valuable comments so much.