I am struggling to understand the for comprehension and exception handling in Scala.
If the first statement in a for comprehension fails , recover is not able to catch the exception.
Code where recover catches the exception successfully(Exception thrown in 2nd statement):
import scala.util.{Success, Try}
object ExceptionThrownIn2ndStatement {
def failTryUnit(x: Unit): Try[Int] = {
println(x)
val a = 1 / 0
new Success(a)
}
def main(args: Array[String]): Unit = {
(for {
var0 <- Try(println("Zeroth function"))
varFailure <- failTryUnit(var0) //exception thrown here
var1 <- Try(println("first function", varFailure))
} yield var1) recover { case e =>
println("Exception caught", e) //exception caught here
}
}
}
Output :
Zeroth function
()
(Exception caught,java.lang.ArithmeticException: / by zero)
Code where recover does NOT catch the exception successfully :
import scala.util.{Success, Try}
object ExceptionThrownIn1stStatement {
def failTryUnit(x: Unit): Try[Int] = {
println(x)
val a = 1 / 0
new Success(a)
}
def main(args: Array[String]): Unit = {
(for {
varFailure <- failTryUnit({}) //exception thrown here
var0 <- Try(println("zeroth function", varFailure))
var1 <- Try(println("first function", var0))
} yield var1) recover { case e =>
println("Exception caught",e) //Exception does not get caught here
}
}
}
Output:
()
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExceptionThrownIn1stStatement$.failTryUnit(ExceptionThrownIn1stStatement.scala:6)
at ExceptionThrownIn1stStatement$.main(ExceptionThrownIn1stStatement.scala:12)
at ExceptionThrownIn1stStatement.main(ExceptionThrownIn1stStatement.scala)
Edit : I understand that this is not the way recover is supposed to be used.
I am just confused as to why this happens. Please help me understand this. I am new to Scala.
Here is a shorter example that demonstrates the same behavior:
Success(42).flatMap(x => { assert(false); Success(x + 58) })
vs.
{ assert(false); Success(42) }.flatMap(x => Success(x + 58))
The first one will return a Failure with a caught error. The second one will crash with an AssertionError.
The first returns a Failure because that's the semantics of Trys flatMap - it catches all exceptions that occur during the execution of the function passed to it.
The second one crashes immediately, because the very first statement is an assert(false), so you never get to the point where you construct a Try in the first place, the AssertionError is thrown before the first Success constructor is invoked. It wouldn't matter whether you append more recovers on it or not - no Try will ever be instantiated in this program.
Here is what you would have to do to catch the exception occurring during the very first calculation (42):
Try { assert(false); 42 }.flatMap(x => Success(x + 58))
In your code, that would be
def failTryUnit(x: Unit): Try[Int] = Try {
println(x)
1 / 0
}
I have just come across a quite baffling anomaly in scala. Say I define the following three lines of code:
def f(d: Int): String = throw new RuntimeException("Catch this")
Some(0).map { x => try { f(x) } catch { case ex: Exception => println("Caught first"); "" } }
Some(0).map { try { f(_) } catch { case ex: Exception => println("Caught second"); "" } }
When I run this only "Caught first" gets printed out. It seems that when I use a placeholder in my map function the catch body is never invoked.
Can someone say why this would it be? Could it be a compiler bug? I have tested it with scala 2.11.6
The second version expands to:
Some(0).map { try { x => f(x) } catch { case ex: Exception => println("Caught second"); "" } }
That is, f(_) expands to x => f(x) within the try block, so it remains an unapplied function. The unapplied function will not throw an exception, so the try/catch block returns it and it is used by Option#map where it throws the exception.
I've been working up my answer to Is there a standard Scala function for running a block with a timeout?, and have run into a problem if an exception is thrown in a Future.
def runWithTimeout[T](timeoutMs: Long)(f: => T) : Option[T] = {
awaitAll(timeoutMs, future(f)).head.asInstanceOf[Option[T]]
}
So that
runWithTimeout(50) { "result" } should equal (Some("result"))
runWithTimeout(50) { Thread.sleep(100); "result" } should equal (None)
But if I throw an exception in my block it doesn't leak, but is swallowed - so that the following fails with "..no exception was thrown"
intercept[Exception] {
runWithTimeout(50) { throw new Exception("deliberate") }
}.getMessage should equal("deliberate")
Syserr has a stack trace with the message
<function0>: caught java.lang.Exception: deliberate
but I can't find where in the Scala runtime that is printed.
Apart from wrapping f in another block which catches exceptions and propagates them if thrown, is there any way to persuade awaitAll and/or Future to throw?
Short answer: no.
Exceptions don't do what you want when you're working in a threaded context, because you want to know about the exception in the caller, and the exception happens in the future's thread.
Instead, if you want to know what the exception was, you should return an Either[Exception,WhatYouWant]--of course, you have to catch that exception within the future and package it up.
scala> scala.actors.Futures.future{
try { Right("fail".toInt) } catch { case e: Exception => Left(e) }
}
res0: scala.actors.Future[Product with Serializable with Either[Exception,Int]] = <function0>
scala> res0() // Apply the future
res1: Product with Serializable with Either[Exception,Int] =
Left(java.lang.NumberFormatException: For input string: "fail")
Disclaimer: I work for Typesafe
Or.... you could use Akka and it would give you what you want without you having to go through hoops for it.
val f: Future[Int] = actor !!! message
Then
f.get
Will throw the exception that happened in the actor
f.await.exception
will give you an Option[Throwable]
Working my way through #Rex Kerr's suggestion, I've created
object Timeout {
val timeoutException = new TimeoutException
def runWithTimeout[T](timeoutMs: Long)(f: => T) : Either[Throwable, T] = {
runWithTimeoutIgnoreExceptions(timeoutMs)(exceptionOrResult(f)) match {
case Some(x) => x
case None => Left(timeoutException)
}
}
def runWithTimeout[T](timeoutMs: Long, default: T)(f: => T) : Either[Throwable, T] = {
val defaultAsEither: Either[Throwable, T] = Right(default)
runWithTimeoutIgnoreExceptions(timeoutMs, defaultAsEither)(exceptionOrResult(f))
}
def runWithTimeoutIgnoreExceptions[T](timeoutMs: Long)(f: => T) : Option[T] = {
awaitAll(timeoutMs, future(f)).head.asInstanceOf[Option[T]]
}
def runWithTimeoutIgnoreExceptions[T](timeoutMs: Long, default: T)(f: => T) : T = {
runWithTimeoutIgnoreExceptions(timeoutMs)(f).getOrElse(default)
}
private def exceptionOrResult[T](f: => T): Either[Throwable, T] =
try {
Right(f)
} catch {
case x => Left(x)
}
}
so that
#Test def test_exception {
runWithTimeout(50) { "result" }.right.get should be ("result")
runWithTimeout(50) { throw new Exception("deliberate") }.left.get.getMessage should be ("deliberate")
runWithTimeout(50) { Thread.sleep(100); "result" }.left.get should be (Timeout.timeoutException)
runWithTimeout(50, "no result") { "result" }.right.get should be ("result")
runWithTimeout(50, "no result") { throw new Exception("deliberate") }.left.get.getMessage should be ("deliberate")
runWithTimeout(50, "no result") { Thread.sleep(100); "result" }.right.get should be ("no result")
}
Again, I'm a bit of a Scala novice, so would welcome feedback.
scala.concurrent.ops.future includes exception handling.
So, instead of importing scala.actors.Futures.future, import scala.concurrent.ops.future instead.
That simple change in which import is there will cause the caller's call to .get to rethrow the exception. It works great!
Or use Future.liftTryTry, turns it from Future[Object] to Future[Try[Object]], and you can match on the Try[Object] and check for an exception case Throw(e) and log / exit gracefully
You need to override the method exceptionHandler in order to catch exceptions. So your option is to define your own future method so it creates a MyFutureActor with exceptionHandler.
EDIT: FutureActor is private, so subclassing it isn't possible.
Another option is to use links to know when exceptions happened.
However, I think Rex Kerr's approach is better - just wrap the function in something that will catch the Exception. Too bad future doesn't already do that.
Is it possible to catch an exception raised within behaviour? Where to place the try/catch? I know that react uses exceptions to reuse the same thread for different actors and that´s why I don´t know where to put the try/catch. I want to catch certain exceptions by myself for logging.
import scala.actors._
def behaviour: PartialFunction[Any,Unit] = {
case x =>
println(x)
throw new IllegalStateException
}
val a = new Actor {
def act {
loop {
react {
behaviour
}
}
}
}
a.start
a ! "Bam"
eThe Actor has a exception handler function which can be overridden:
override def exceptionHandler = {
case e: Exception =>
println(e.getMessage())
}
Whenever a exception is raised in the actor that would normally cause it to terminate - the exceptionHandler partial function is applied to the exception.
Edit
With Exception filter:
class ExceptionalActor extends Actor{
def act() {
loop {
react {
case "bad" => throw new NoSuchFieldException("Bad Message")
case "impossible" => throw new Exception("Impossible Exception")
case m => println("non-bad message " + m )
}
}
}
override def exceptionHandler = {
case e: NoSuchFieldException => println("handled " + e.getMessage() )
}
}
object Tester extends App {
val eActr = new ExceptionalActor
eActr start
eActr ! "any message1"
eActr ! "bad"
eActr ! "any message2"
eActr ! "impossible"
eActr ! "any message3"
}
produces:
non-bad message any message1
handled Bad Message
non-bad message any message2
org.scratch.act.ExceptionalActor#7f5663a2: caught java.lang.Exception: Impossible Exception
:
And actor death.
ref: Actors in Scala
Experimenting with Scala... I'm trying to define something analogous to the "#" hack in PHP (which means, ignore any exception in the following statement).
I managed to get a definition that works:
def ignoreException(f: () => Unit) = {
try {
f();
}
catch {
case e: Exception => println("exception ignored: " + e);
}
}
And use it like this:
ignoreException( () => { someExceptionThrowingCodeHere() } );
Now here is my question... Is there anyway I can simplify the usage and get rid of the () =>, and maybe even the brackets?
Ultimately I'd like the usage to be something like this:
`#` { someExceptionThrowingCodeHere(); }
# is reserved in Scala (for pattern matching), but would you accept ##?
scala> def ##(block: => Unit): Unit = try {
block
} catch {
case e => printf("Exception ignored: %s%n", e)
}
$at$at: (=> Unit)Unit
scala> ## {
println("before exception")
throw new RuntimeException()
println("after exception")
}
before exception
Exception ignored: java.lang.RuntimeException
I'm not convinced this is a good idea, however ☺
You don't have to use a function as your parameter, a "by-name" parameter will do:
def ignoreException(f: =>Unit) = {
try {
f
}
catch {
case e: Exception => println("exception ignored: " + e)
}
}
ignoreException(someExceptionThrowingCodeHere())
Eric.