Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala's "for comprehension" with futures

Tags:

scala

future

I am reading through the Scala Cookbook (http://shop.oreilly.com/product/0636920026914.do)

There is an example related to Future use that involves for comprehension.

So far my understanding about for comprehension is when use with a collection it will produce another collection with the same type. For example, if each futureX is of type Future[Int], the following should also be of type Future[Int]:

for {    r1 <- future1    r2 <- future2    r3 <- future3 } yield (r1+r2+r3) 

Could someone explain me what exactly happening when use <- in this code? I know if it was a generator it will fetch each element by looping.

like image 310
nish1013 Avatar asked Sep 27 '13 08:09

nish1013


People also ask

Is future blocking onComplete?

NOTE: With Future. onComplete() we are no longer blocking for the result from the Future but instead we will receive a callback for either a Success or a Failure.

How do you handle future Scala?

Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.

Are Futures monads?

Futures can be considered monads if you never construct them with effectful blocks (pure, in-memory computation), or if any effects generated are not considered as part of semantic equivalence (like logging messages). However, this isn't how most people use them in practice.

What is future sequence?

sequence takes a list of futures and transforms it into a single future of list in an asynchronous manner. For instance, assume that you have a list of independent jobs to be run simultaneously. In such a case, the list of futures can be composed into a single future of list using Future. sequence.


1 Answers

First about for comprehension. It was answered on SO many many times, that it's an abstraction over a couple of monadic operations: map, flatMap, withFilter. When you use <-, scalac desugars this lines into monadic flatMap:

r <- monad into monad.flatMap(r => ... )

it looks like an imperative computation (what a monad is all about), you bind a computation result to the r. And yield part is desugared into map call. Result type depends on the type of monad's.

Future trait has a flatMap and map functions, so we can use for comprehension with it. In your example can be desugared into the following code:

future1.flatMap(r1 => future2.flatMap(r2 => future3.map(r3 => r1 + r2 + r3) ) ) 

Parallelism aside

It goes without saying that if execution of future2 depends on r1 then you can't escape sequential execution, but if the future computations are independent, you have two choices. You can enforce sequential execution, or allow for parallel execution. You can't enforce the latter, as the execution context will handle this.

val res = for {    r1 <- computationReturningFuture1(...)    r2 <- computationReturningFuture2(...)    r3 <- computationReturningFuture3(...) } yield (r1+r2+r3) 

will always run sequentially. It can be easily explained by the desugaring, after which the subsequent computationReturningFutureX calls are only invoked inside of the flatMaps, i.e.

computationReturningFuture1(...).flatMap(r1 =>      computationReturningFuture2(...).flatMap(r2 =>          computationReturningFuture3(...).map(r3 => r1 + r2 + r3) ) ) 

However this is able to run in parallel and the for comprehension aggregates the results:

val future1 = computationReturningFuture1(...) val future2 = computationReturningFuture2(...) val future3 = computationReturningFuture3(...)  val res = for {    r1 <- future1    r2 <- future2    r3 <- future3 } yield (r1+r2+r3) 
like image 174
4lex1v Avatar answered Oct 01 '22 05:10

4lex1v