I'm working on using Futures for the first time in Scala and am working through an example of using the flatMap combinator; I've been following this discussion:
http://docs.scala-lang.org/overviews/core/futures.html
Specifically, this example:
val usdQuote = future { connection.getCurrentValue(USD) }
val chfQuote = future { connection.getCurrentValue(CHF) }
val purchase = for {
usd <- usdQuote
chf <- chfQuote
if isProfitable(usd, chf)
} yield connection.buy(amount, chf)
purchase onSuccess {
case _ => println("Purchased " + amount + " CHF")
}
is translated to this:
val purchase = usdQuote flatMap {
usd =>
chfQuote
.withFilter(chf => isProfitable(usd, chf))
.map(chf => connection.buy(amount, chf))
}
What I'm having a bit of trouble grasping is how and when this is flatMap executed?
I understand that usdQuote and chfQuote are executed by "some thread" at "some time" and their registered callback functions called, questions are:
a) Are usdQuote and chfQuote executed concurrently? (I'm pretty sure they are).
b) How does flatMap assign the value of the Future useQuote to usd? As in, does it get called when the operation usdQuote completes?
c) What thread is executing the 'flatMap' and 'map' operation (probably more of a follow-on from the last question).
Cheers.
I'm face the same question... And i found useful this general explanation about for-comprehesion. May be this helps:
For-Comprehensions
A for-comprehension is syntactic sugar for
map
,flatMap
andfilter
operations on collections.The general form is
for (s) yield e
s
is a sequence of generators and filtersp <- e
is a generatorif f
is a filter{ s }
instead of( s )
if you want to use multiple lines without requiring semicolonse
is an element of the resulting collectionExample 1:
is equivalent to
Translation Rules
A for-expression looks like a traditional for loop but works differently internally
for (x <- e1) yield e2
is translated toe1.map(x => e2)
for (x <- e1 if f) yield e2
is translated tofor (x <- e1.filter(x => f)) yield e2
for (x <- e1; y <- e2) yield e3
is translatedto e1.flatMap(x => for (y <- e2) yield e3)
This means you can use a for-comprehension for your own type, as long as you define map, flatMap and filter
Example 2:
is equivalent to
is equivalent to
You also have a good example of concurrent
Future
execution in "Scala notes – Futures – 3 (Combinators and Async)" from Arun Manivannan.Code:
for-comprehension:
flatmap:
Test:
It does illustrate that:
a) When you created them you've already started them executing against the implicit ExecutionContext in scope, so they're potentially running concurrently as it depends on how that is executing them.
b) It doesn't really assign the value as such, but the implementation uses the onComplete method to cause the function you've passed to be triggered once a result has been reached. At the current time this should link to that flatMap method I'm referring to: https://github.com/scala/scala/blob/v2.11.2/src/library/scala/concurrent/Future.scala#L246
c) Those are running via the ExecutionContext previously mentioned, consider also that if those Future instances can be running on different ExecutionContexts, so parts of the for-comprehension can be running on different thread pools.