Friday 18 December 2015

Future in Scala


Future is a placeholder object for a value that may not yet exist. By default, futures and promises are non-blocking, making use of callbacks instead of typical blocking operations. Blocking is still possible - for cases where it is absolutely necessary, futures can be blocked on (although this is discouraged).
Future and Promises revolve around ExecutionContexts, responsible for executing computations.

Future

Scala’s Future[T], residing in the scala.concurrent package, is a container type, representing a computation that is supposed toeventually result in a value of type T.
Future is a write-once container – after a future has been completed, it is effectively immutable. Also, the Future type only provides an interface for reading the value to be computed. The task of writing the computed value is achieved via a Promise.
An ExecutionContext is something that can execute our future, and you can think of it as something like a thread pool.

The simplest way to create a future object is to invoke the future method which starts an asynchronous computation and returns a future holding the result of that computation. The result becomes available once the future completes.


  1. import scala.concurrent._
  2. import ExecutionContext.Implicits.global
  3. val session = socialNetwork.createSessionFor("user", credentials)
  4. val f: Future[List[Friend]] = Future {
  5. session.getFriends()
  6. }
  7. f onComplete {
  8. case Success(posts) => for (post <- posts) println(post)
  9. case Failure(t) => println("An error has occured: " + t.getMessage)
  10. }

Callback
If the future has already been completed when registering the callback, then the callback may either be executed asynchronously, or sequentially on the same thread. 
Callbacks for futures are partial functions. You can pass a callback to the onSuccess method. It will only be called if the Futurecompletes successfully, and if so, it receives the computed value as its input. Usually, it’s better to combine these two and register a completion callback that will handle both cases. The input parameter for that callback is a Try
Since callback requires the value in the future to be available, it can only be called after the future is completed. However, there is no guarantee it will be called by the thread that completed the future or the thread which created the callback. Instead, the callback is executed by some thread, at some time after the future object is completed. We say that the callback is executed eventually.
Furthermore, the order in which the callbacks are executed is not predefined, even between different runs of the same application. In fact, the callbacks may not be called sequentially one after the other, but may concurrently execute at the same time. 

Composing futures

Future is a container type, made it possible for you to map them, flat map them, or use them in for comprehensions .


val temperatureOkay: Future[Boolean] = heatWaterFuture(Water(25))
      .map { water =>
              println("we're in the future!")
             (80 to 85).contains(water.temperature)
      }

That mapping function gets executed as soon as your Future[Water] instance has completed successfully. If your instance of Future[Water] fails, what’s taking place in the function you passed to map will never happen. Instead, the result of calling map will be a Future[Boolean]containing a Failure.

If the computation of one Future depends on the result of another, you’ll likely want to resort to flatMap to avoid a deeply nested structure of futures.

val flatFuture: Future[Boolean] = heatWaterFuture(Water(25))
        .flatMap {
               water => temperatureOkayFuture(water)
       }

val flatFuture: Future[Boolean] = for {
      heatedWater <- heatWaterFuture(Water(25))
      okay <- temperatureOkayFuture(heatedWater)
} yield okay


Instead of calling flatMap, you’ll usually want to write a for comprehension, which is essentially the same, but reads a lot clearer. 


If you do use Futures be careful to not close over the session object.The session might get closed outside the Future. Instead create the session inside the Future and close it after the Future completes, e.g. using andThen.


Reference:
http://docs.scala-lang.org/overviews/core/futures.html
http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html

No comments:

Post a Comment