Why does the andThen of Future not chain the result?

Chen OT picture Chen OT · Jun 5, 2015 · Viewed 15.2k times · Source

The andThen meaning I learned from this answer is a function composer.

Say that

f andThen g andThen h

will equal to

h(g(f(x)))

This implies the h function will receive input from g(f(x))

But for the andThen in Future, all the closure of the following andThen always receives the result from the original Future.

Future{
    1
}.andThen{ case Success(x) =>
    println(x) // print 1
    Thread.sleep(2000)
    x * 2
}.andThen{ case Success(x) =>
    println(x) // print 1
    Thread.sleep(2000)
    x * 2
}

compare to

val func: Function1[Int, Int] = { x: Int =>
  x
}.andThen { y =>
  println(y) // print 1
  y * 2
}.andThen { z =>
  println(z) // print 2
  z * 2
}
func(1)

What is the reason to make Future::andThen(s) receive all the same result from original Future instead of chaining Future? I've observed that these chained andThen will be executed sequentially, so the reason may not be for parallel purpose.

Answer

Odomontois picture Odomontois · Jun 5, 2015

scala.concurrent.Future is designed as compromise of two asynchronous approaches:

  1. Object-oriented observer which allows binding of asynchronous handlers
  2. Functional monad which offers rich functional composition capabilities.

Reading Future.andThen's docs:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

So andThen is most likely from OOP universe. To gain similar similar result to Function1.andThen you could use map method :

Future(1).map {_ * 2}.map {_ * 2}

andThen differs from onComplete with one little thing: resulting Future of andThen still returning same result, but will wait until supplied observer will return or throw something. That's why there is written in the docs:

This method allows one to enforce that the callbacks are executed in a specified order.

Also note third line from docs:

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThen callbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

So it' completely do nothing with new Future's result. Could not even spoil it with it's ownt exception. This andThen and onComplete just sequential and parallel binding of observers.