Getting Asynchronous in Scala : Part 1 (Future, Callbacks, Combinators etc.)

‘Only you can control your future.’ – Dr. Seuss

The above quote has a great correspondence with this blog. In the blog we will discuss what are Future values and how we access them.
During our journey we will be visiting,exploring and understanding following checkpoints :-
1). What are future (basics).
2). How to access them.
3). Basics about Macros.
4). The Async library in Scala

Voyage gears :-
1). Language – Scala
2). IDE – IntelliJ
3). Build Tool – SBT

Before start sailing, let us first know the purpose why we have set the sail high. The blog explains how one can code asynchronously in Scala i.e. executing multiple operations together (parallelism) without waiting for them to complete thus making optimum utilization of system hardware. One can avoid performance bottlenecks and enhance the overall responsiveness of the application by using asynchronous programming.

 

Checkpoint 1 ‘What is a Future?’ ->

A future is a place holder which holds a value that may become available at some point. A future value can be understood by following figure.

 

Future (2)

 

The image explains that a future is either not complete or complete and if it is complete, it may be a failure if some exception occurs or it may be successful if the computed value is accessed.

The operations which may take time to execute are enclosed under the Future scope which starts asynchronous computation and returns a Future value holding the result of the computation. The execution of the code enclosed in the future block depends on the execution context associated with the block. The execution context is the environment in which the code executes; it is further associated with a thread pool. The thread pool provides the threads on which the Future enclosed block of code is executed. Hence whenever code enclosed in Future block is encountered a new thread from the thread pool is picked for its execution thus performing many operations in parallel. We generally use ‘The Global Execution Context’ which is associated with ‘ForkJoinPool’.
The bulky paragraph above is explained via following code :-

 

Checkpoint 2 ‘Access result of Future’ ->

The figure in checkpoint 1 clearly shows the two probable results of the Future i.e. either success or failure. The result (value or exception) from a Future can be accessed by following ways :-
1). Callbacks
2). Combinators
3). For Comprehensive
4). Await.result
5). The async library (async,await)

Explaination :-

1). Callbacks ->

Result of a Future can be accessed by registering a callback for the Future. This callback is called asynchronously once the future is completed. A callback needs an execution context since it is also executed asynchronously. Callback can be registered using following methods :-
a). onComplete
b). onSuccess
c). onFailure

Explaination :-

a). The onComplete Method ->

The onComplete Method allows handling of both failed and successful future computations. Following example explains its use case :-

The above code clearly explains how the value returned by a future is accessed in case of a success or a failure.

b). The onSuccess Method ->

The onSuccess Method allows handling of only successful future computations. This callback is executed only when a future returns data otherwise its not executed. Following example explains its use case :-

c). The onFailure Method ->

The onFailure Method allows handling of only failed future computations. This callback is executed only when a future results in exception otherwise its not executed. Following example explains its use case :-

2). Combinators ->

Combinators are another way to access the value of a future. The combinators act on a future value and returns corresponding new future. Flatmap, map, filter, recover,recoverWith,fallBackTo are some of the examples of the combinator. One thing to note is that the combinators are internally implemented using callbacks. Combinators are used when we want the result of a Future variable/constant and perform computations on it and return the result of the computation as a new future. Following example demonstrate the usage of the combinators (map) :-

There is a problem in above code, if the result in the Future ‘futureResult’ is a failure, it yields an exception. Hence its a good practice to provide some kind of handler to handle the exception which may occur while using the futures. Recover, recoverWith, fallbackTo are some ways by which the exception generated by the future can be handled. The recover combinator creates a new future which holds the same result as the original future if original future completes successfully otherwise it handles the exception and provides a default value which acts as the resultant Future. Following examples explains the concept :

3). For Comprehensive ->

Combinators are a very efficient mechanism to access and use the value of a Future but they have a limitation i.e. it becomes a bit complex to use combinators when we have to use several futures to compute a result. For example we have to add two future values and return a new future as there sum. For comprehensive is used for situations like this when we have to use multiple future values to compute the result. Following example will explain there usage better :-

In above code the ‘addResult’ future is completed only when ‘first’ and ‘second’ future are completed. The ‘finalVerifiedResult’ gurentees that the final future value will always be a Success and will have the default value of -1 in case of Failure of ‘addResult’.

4). Await.result ->

Await is an object available in ‘scala.concurent’. It has two methods :-

1). ‘ready’. It waits for the “completed” state of an Awaitable(Future[T]).
2). ‘result’. It waits and returns the result (of type T) of an Awaitable(Future[T]).

Internally Await use blocking and with the ‘result()’ method it yields the result of associated Future by blocking the current thread and thus killing the asynchronous approach to code. Hence, It must be proffered to use Await only in test cases, to test the functionality of asynchronous code. Following example demonstrate the usage of Await :

Great we are now mid way of the journey. Hope you gain something out of the blog. The remaining two checkpoints i.e. ‘Basic About Macros’ and ‘The async library in Scala’ will be explored in the second part of the blog.

References :-

1). http://docs.scala-lang.org/overviews/core/futures.html

2). https://blog.knoldus.com/2015/07/28/asynchronous-programming-with-scalas-future-promises/

Special thanks to Creately.com for providing a great platform to build diagrams online.

Happy coding …

Written by 

Sahil is a Software Consultant, with experience of more than 2.5 years. He is Microsoft certified c# developer. He has sound knowledge of different technologies which include C#, C, SQL, Scala, Play, ANTLR4, Docker, Ansible, jenkins, Python, DataDog, Promethous, Lightbend Telemetry etc. His hobbies include of cooking , watching anime and Partying with friends.

15 thoughts on “Getting Asynchronous in Scala : Part 1 (Future, Callbacks, Combinators etc.)

  1. There is a little mistake in section ‘Callbacks’. While you are describing ‘onFailure’ method, actually you are using ‘onSuccess’ in the example provided.

      1. Just wondering, can we get it(article) corrected with this callback sections onFailure mistake? Because a newbie will get mis-leaded. Please take it as my gentle opinion/kind advice.

  2. Most clear and straightforward article about Futures in Scala, good job! If official Scala dovs were this clear I’m sure a lot more people would be using the language 🙂

  3. Hello Sahil, I have a doubt here. We know that future Callbacks are asynchronously executed by some thread. What about Future Combinators (Here I am talking about for comprehension)? If “for combinator” is executed asynchronously then how does compiler decide to not execute it by Main thread (but asynchronously)?

Leave a Reply

%d bloggers like this: