Scala futures and `andThen` exception propagation

exception, future, java, scala

Solution

Don't `throw` exception in `Future.successful {}`.

here is the correct way to do it

Future { throw new RuntimeException("test") } andThen
                  { case _ => println("test") }

You can understand the use of `andThen` using the following line of code

Future.successful { 1 } andThen { case _ =>  "foo" }

REPL

@ Future.successful { 1 } andThen { case _ =>  "foo" }
res7: Future[Int] = Success(1)

REPL

@ Future.successful { 1 } andThen { case _ =>  println("foo") }
foo
res8: Future[Int] = Success(1)

REPL

@ val result = Future.successful { 1 } andThen { case _ =>  "foo" }
result: Future[Int] = Success(1)

In the above examples

We can see that partial function after andthen is executed but partial function return type is ignored. Finally the resultant output is result of the `Future` which is the `Future[Int]`

This means `addThen` is used for executing side effecting function just after the `Future` is completed.

When Future is a Failure

REPL

@ val result = Future { throw new Exception("bar") } andThen { case _ =>  "foo" }
result: Future[Nothing] = Failure(java.lang.Exception: bar)

REPL

@ val result = Future { throw new Exception("bar") } andThen { case _ =>  println("foo") }
foo
result: Future[Nothing] = Failure(java.lang.Exception: bar)

Same is the case when future is a failure. Code after andThen executes and but the result of the code after andThen is ignored and final result is the Future result.

So `andThen` is used for running side effecting code as soon as Future completes. `andThen` also keeps the final output as `Future`s output.

This is how `andThen` is implemented in Standard library.

`andThen` resides inside the `Future` class

 def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = {
    val p = Promise[T]()
    onComplete {
      case r => try pf.applyOrElse[Try[T], Any](r, Predef.conforms[Try[T]]) finally p complete r
    }
    p.future
  }

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

Yes

`pf` is the side effecting code because its output type is not used (cannot be used). `p.future` is the new future he is talking about. `Promise` is completed with the previous `Future` result (look at the implementation of `addThen` above)

inside the finally block `p complete r` means new Future is created using `p.future` and it is completed using the previous future result which is `r`

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

Yes. You can chain multiple callbacks using multiple `andThen` calls and these callbacks are executed one after another in the order of `andThen` calls. This is compared to the `onComplete` methods that you can use it multiple times to register multiple callbacks, but the order of these callbacks is uncertain.

3) 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.

Yes

`r` which is the result of the previous future is given to `pf` (look at the andThen code above)

Problem

I'm reading Scala 2.11.8 documentation of `andThen` function in the scala.concurrent.Future module and it says the following: ``` def andThen[U](pf: PartialFunction[Try[T], U]) (implicit executor: ExecutionContext): Future[T] ``` Applies the side-effecting function to the result of this future, and returns a new future with the result of this future. This method allows one to enforce that the callbacks are executed in a specified order. 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. I'm not sure what does it exactly mean that exceptions are not propagated by `andThen` and there's also no example provided. For example if I do something like this: ``` Future.successful { throw new RuntimeException("test") } andThen { case _ => println("test") } ``` In Scala REPL I get: ``` java.lang.RuntimeException: test ... 32 elided ``` So the exception was propagated. Could someone please provide a meaningful example what does that exactly means and whether it is safe using `andThen` with code that my throw exceptions which I would like to recover from. Thank you.

Original source