7

When I make a future, or apply methods like onSuccess and map, I can specify ExecutionContext for them.

For example,

val f = future {
  // code
} executionContext

f.map(someFunction)(executionContext)

f onSuccess {
  // code
} executionContext

However, if I use a for-comprehension of future, how can I specify ExecutionContext for the yield part?

for {
  f <- future1
  g <- future2
} yield {
  // code to be executed after future1 onSuccess and future2 onSuccess
  // What ExecutionContext runs this code?
} // (executionContext) here does not work

And, what ExecutionContext runs the code in yield if not specified?


EDIT

OK. Thanks to answers, I found something.
If I don't define or import implicit ExecutionContext (like Implicits.global), the for-comprehension does not compile. That means, for-comprehension uses implicit ExecutionContext.

Then, how can I use for-comprehension without implicit ExecutionContext, i.e. how to specify?

Naetmul
  • 11,923
  • 6
  • 46
  • 72
  • See my answer for the underlying reason of why the `for` comprehensions won't compile if you don't have an `implicit` specified. – mikołak Jan 21 '14 at 11:29
  • @flavian In simple situation, that works. But if there are two ExecutionContext to use for for-comprehension, how can I specify? It will show errors like `ambiguous implicit values`. I can block each time I define or import implicit vals or defs & for-comprehension, but is there another way? – Naetmul Jan 21 '14 at 11:35
  • just to be absolutely sure - do you mean a single `for`-comprehension with multiple generators (in which case flavian's answer works) or multiple consequent `for`-comprehensions? – mikołak Jan 21 '14 at 13:32
  • @TheTerribleSwiftTomato I meant a single for-comprehension with multiple generators. The solution was not that simple, but Scala doesn't seem to support explicit ExecutionContext for for-comprehension... – Naetmul Jan 21 '14 at 14:02

2 Answers2

9

The ExecutionContext parameter is actually implicit. That means you can:

import scala.concurrent.ExecutionContext

implicit val context = ExecutionContext.fromExecutor(//etc)
for {
  f <- future1
  g <- future2
} yield {
  // code to be executed after future1 onSuccess and future2 onSuccess
  // What ExecutionContext runs this code?: the one above.
}

You also have a default, namely scala.concurrent.ExecutionContext.Implicits.global. This has as many threads as the processors on the running machine.

It won't be used by all Futures by default, you still have to import it.

Update: If you really want to specifiy, although it's not recommended, you can unwrap the for yield

val combined = futureA.flatMap(x => futureB)(context)
flavian
  • 26,242
  • 10
  • 57
  • 95
  • What if there are two implicit ExecutionContexts in scope and you need to select one? – kostya Jul 30 '15 at 02:45
  • 1
    @kostya you can use selective aliasing like this: `import com.bla.bla.{ contextToDiscard => _, _ }`. This will import just one of them into scope if it's a package import causing the problems. Another way is to move imports that bring in the executors to a lower scope. – flavian Jul 30 '15 at 09:24
1

Since for comprehensions are "mapped" to map/flatMap operations, and the ExecutionContext parameters of those are implicit, I guess you can try to add an implicit val in the local scope:

implicit val myContext:ExecutionContext = ...

.

I don't believe there is a "default" implicit ExecutionContext, but the most commonly used one is ExecutionContext.Implicits.global .

mikołak
  • 9,335
  • 1
  • 45
  • 68