Book Image

Building Applications with Scala

By : Diego Pacheco
Book Image

Building Applications with Scala

By: Diego Pacheco

Overview of this book

<p>Scala is known for incorporating both object-oriented and functional programming into a concise and extremely powerful package. However, creating an app in Scala can get a little tricky because of the complexity the language has. This book will help you dive straight into app development by creating a real, reactive, and functional application. We will provide you with practical examples and instructions using a hands-on approach that will give you a firm grounding in reactive functional principles.</p> <p>The book will take you through all the fundamentals of app development within Scala as you build an application piece by piece. We’ve made sure to incorporate everything you need from setting up to building reports and scaling architecture. This book also covers the most useful tools available in the Scala ecosystem, such as Slick, Play, and Akka, and a whole lot more. It will help you unlock the secrets of building your own up-to-date Scala application while maximizing performance and scalability.</p>
Table of Contents (17 chapters)
Building Applications with Scala
Credits
About the Author
Acknowledgments
About the Reviewer
www.PacktPub.com
Preface

Futures


Futures enable an efficient way to write parallel operations in a nonblocking IO fashion. Futures are placeholder objects for values that might not exist yet. Futures are composable, and they work with callbacks instead of traditional blocking code.

Simple Future code in Scala REPL

$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_77).
Type in expressions for evaluation. Or try :help.
scala> import concurrent.Future
import concurrent.Future
scala> import concurrent.ExecutionContext.Implicits.global
import concurrent.ExecutionContext.Implicits.global
scala> 
scala> val f: Future[String] = Future { "Hello world!" }
f: scala.concurrent.Future[String] = Success(Hello world!)
scala> 
scala> println("Result: " + f.value.get.get)
Result: Hello world!
scala> 
scala> println("Result: " + f)
Result: Success(Hello world!)
scala>

In order to work with futures in Scala, we have to import concurrent.Future. We also need an executor, which is a way to work with threads. Scala has a default set of execution services. You can tweak it if you like, however, for now we can just use the defaults; to do that, we just import concurrent.ExecutionContext.Implicits.global.

It's possible to retrieve the Future value. Scala has a very explicit API, which makes the developer's life easier, and also gives good samples for how we should code our own APIs. Future has a method called value, which returns Option[scala.util.Try[A]] where A is the generic type you are using for the future; for our case, it's a String A. Try is a different way to do a try...catch, and this is safer, because the caller knows beforehand that the code they are calling may fail. Try[Optional] means that Scala will try to run some code and the code may fail -- even if it does not fail, you might receive None or Some. This type of system makes everybody's lives better, because you can have Some or None as the Option return. Futures are a kind of callback. For our previous sample code, the result was obtained quite quickly, however, we often use futures to call external APIs, REST services, Microservices, SOAP Webservices, or any code that takes time to run and might not get completed. Futures also work with Pattern Matcher. Let's see another sample code.

A complete Future sample at Scala REPL

$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_77).
Type in expressions for evaluation. Or try :help.
scala> import concurrent.Future
import concurrent.Future
scala> import concurrent.ExecutionContext.Implicits.global
import concurrent.ExecutionContext.Implicits.global
scala> import scala.util.{Success, Failure}
import scala.util.{Success, Failure}
scala> def createFuture():Future[Int] = {
     | Future { 
     | val r = scala.util.Random
     | if (r.nextInt(100)%2==0) 0 else throw new RuntimeException("ODD numbers are not good here :( ")
     | }
     | }
createFuture: ()scala.concurrent.Future[Int]
scala> def evaluateFuture(f:Future[_]) {
     | f.onComplete {
     | case Success(i) => println(s"A Success $i ")
     | case Failure(e) => println(s"Something went wrong. Ex: ${e.getMessage}")
     | }
     | }
evaluateFuture: (f: scala.concurrent.Future[_])Unit
scala> evaluateFuture(createFuture)
scala> Something went wrong. Ex: ODD numbers are not good here :( 
evaluateFuture(createFuture)
A Success 0 
scala> evaluateFuture(createFuture)
Something went wrong. Ex: ODD numbers are not good here :( 
scala> evaluateFuture(createFuture)
Something went wrong. Ex: ODD numbers are not good here :( 
scala> evaluateFuture(createFuture)
A Success 0 
scala> evaluateFuture(createFuture)
A Success 0 
scala>

There is a function called createFuture, which creates Future[Int] each time you call it. In the preceding code, we use scala.util.Random to generate random numbers between 0 and 99. If the number is even, we return a 0, which means success. However, if the number is odd, we return a RuntimeException, which will mean a failure.

There is a second function called evaluateFuture, which receives any Future. We allow a result of any kind of generic parameterized type of function, because we used the magic underscore _. Then we apply Pattern Matcher with two case classes: Success and Failure. In both the cases, we just print on stdin. We also use another interesting and handy Scala feature called String interpolation. We need to we start the String with s before "". This allows us to use expressions with $ and ${} to evaluate any variable in the context. This is a different approach for String concatenation from what we have done so far. Later, we made 6 calls for the evaluteFuture function, passing a new Future each time, created by the function createFuture.