Reputation: 3425
Let's consider the following excerpt from scala.concurrent.Future.scala
:
def zip[U](that: Future[U]): Future[(T, U)] = {
implicit val ec = internalExecutor
flatMap { r1 => that.map(r2 => (r1, r2)) }
}
def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] =
flatMap(r1 => that.map(r2 => f(r1, r2)))(internalExecutor)
It does not differ a lot seemingly, except for the application of function f
in the zipWith
case. It is interesting to me, why the internalExecutor
(which just delegates to the current thread) is declared as implicit value in the zip
and thus used in both underlying map
and flatMap
calls, but is used explicitly only in the flatMap
call inside the zipWith
?
As I understand after some thinking, the f
function execution may involve some blocking or intensive computation which is out of Scala library control, and so the user should provide another execution context for it to not occasionally block the internalExecutor
(current thread). Is this understanding correct?
Upvotes: 4
Views: 455
Reputation: 26579
The application of f
is done with the supplied ExecutionContext
, and internalExecutor
is used to perform the flattening operation. The rule is basically: When the user supplies the logic, that logic is executed on the ExecutionContext
supplied by the user.
You could imagine that zipWith
was implemented as this.zip(that).map(f.tupled)
or that zip
was implemented as zipWith(Tuple2.apply)(internalExecutor)
.
Upvotes: 3