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.
To elaborate those existing answers here a simple result to demonstrate how
for
comprehension works.Its bit lengthy functions yet they worth taking look into it.
A function that give us a range of integers
A function that give us a range of chars
Using these function calls within the for comprehension.
For these below lines we can make out that all the function calls are synchronous i.e.
createAsciiChars
function call is not executed untilcreateIntegers
completes its execution.Making these function
createAsciiChars
,createIntegers
calls outside thefor
comprehensions will be asynchronous execution.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 monadicflatMap
:r <- monad
intomonad.flatMap(r => ... )
it looks like an imperative computation (what a monad is all about), you bind a computation result to the
r
. Andyield
part is desugared intomap
call. Result type depends on the type ofmonad
's.Future
trait has aflatMap
andmap
functions, so we can use for comprehension with it. In your example can be desugared into the following code:Parallelism aside
It goes without saying that if execution of
future2
depends onr1
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.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.However this is able to run in parallel and the for comprehension aggregates the results:
It allows
r1
,r2
,r3
to run in parallel, if possible. It may not be possible, depending things like how many threads are available to execute Future computations, but by using this syntax you are telling the compiler to run these computations in parallel if possible, then execute theyield()
when all have completed.