Alexander Arendar
Alexander Arendar

Reputation: 3425

Slight difference in Future.zip and Future.zipWith implementation. Why?

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

Answers (1)

Viktor Klang
Viktor Klang

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

Related Questions