Are Errors in a Future body rethrown, as per the documentation?

295 views
Skip to first unread message

Andrew Phillips

unread,
Jul 13, 2015, 4:09:34 PM7/13/15
to scala-l...@googlegroups.com
Hi all

With regard to the handling of Errors, the "Futures and Promises" documentation [1] states:

ExecutionException - stored when the computation fails due to an unhandled InterruptedException, Error or a scala.util.control.ControlThrowable. In this case the ExecutionException has the unhandled exception as its cause. These exceptions are rethrown in the thread executing the failed asynchronous computation.

Is this latter statement true in general, e.g. also if you supply your own ExecutionContext? Or does it depend on the ExecutionContext implementation?

In this example at least, nothing seems to be rethrown (or passed to reportFailure, for that matter):

Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_40).

import scala.concurrent.Future
import scala.concurrent.ExecutionContext
import scala.util.{Failure, Success}

implicit object SameThreadExecutionContext extends ExecutionContext {
  override def execute(runnable: Runnable): Unit = {
    println("DEBUG: running " + runnable)
    runnable.run()
  }
  override def reportFailure(t: Throwable): Unit = ??? // never called?
}

scala> Future { throw new Error("bang!") }.value
DEBUG: running scala.concurrent.impl.Future$PromiseCompletingRunnable@887b5d0
res1: Option[scala.util.Try[Nothing]] = Some(Failure(java.util.concurrent.ExecutionException: Boxed Error))

Am I missing something or misreading the docs here?

Regards

ap

Viktor Klang

unread,
Jul 13, 2015, 5:05:12 PM7/13/15
to scala-l...@googlegroups.com
Hi Andrew,

I think that behaviour was changed later on.
See the revision history / Issues for details. 

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Cheers,

Andrew Phillips

unread,
Jul 13, 2015, 6:17:12 PM7/13/15
to scala-l...@googlegroups.com
Hi Viktor

> See the revision history / Issues for details. 

Thanks for the hint. The last change related to this seems to have been SI-7029 ("Fork join execution context loses fatal exceptions") [1], which added code to pass any exceptions caught to the fork-join pool thread's uncaught exception handler [2]. The above example is not related to the fork-join executor, however.

The discussion in the issue has hopefully put me on the right track, though: what seems to be the case is that only fatal exceptions (as determined by NonFatal [3]) are re-thrown...and this includes ControlThrowable and InterruptedException, but not Error.

Tweaking my original example to use InterruptedException gives the desired result:

scala> Future { throw new InterruptedException("bang!") }.value
DEBUG: running scala.concurrent.impl.Future$PromiseCompletingRunnable@7e6ce0a3
java.lang.InterruptedException: bang!
  at $anonfun$1.apply(<console>:12)
  at $anonfun$1.apply(<console>:12)
  at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future
.scala:24)
  at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)

  at SameThreadExecutionContext$.execute(<console>:13)
  at scala.concurrent.impl.Future$.apply(Future.scala:31)
  at scala.concurrent.Future$.apply(Future.scala:492)
  ... 33 elided


Regards

ap

Viktor Klang

unread,
Jul 13, 2015, 6:40:30 PM7/13/15
to scala-l...@googlegroups.com

Andrew,

Indeed, also see revisions to NonFatal.

--
Cheers,

Reply all
Reply to author
Forward
0 new messages