Reputation: 2094
In scala.util.control.Exception, there are many functions to create catchers and the likes. However, in some cases, I find that I would like to translate/rename/wrap an exception like this:
class MyBaseException...
class MyDerivedException extends MyBaseException ...
class MyOtherDerivedException extends MyBaseException ...
try {
// some code throw new MyDerivedException
// some other code throw new java.lang.IllegalArgumentException
} catch {
case e: MyBaseException => throw e // Let every exceptions derived from MyBaseException go through unchanged
case NonFatal(e) => new MyOtherDerivedException(e)
}
This can also be done with a catch like that:
try{ ... } catch {
case NonFatal(e) if (!classOf[MyBaseException].isAssignableFrom(e.getClass)) => new MyOtherDerivedException(e)
}
So now, fitting that into scala.util.control.Exception catching syntax, I didn't find any way of doing that. In practice, I want something like that:
def wouldMatch(x: Throwable, classes: scala.collection.Seq[Class[_]]): Boolean =
classes exists (_ isAssignableFrom x.getClass)
def shouldRethrowIfMatchOrElse(x: Throwable, classes: scala.collection.Seq[Class[_]]): Boolean = {
if (wouldMatch(x, classes)) true
else shouldRethrow(x)
}
def catchingWithRethrow[T](c: Catcher[T])(exceptions: Class[_]*): Catch[T] = new Catch(c, None, { shouldRethrowIfMatchOrElse(_, exceptions) })
And be used like that:
val myCatching = catchingWithRethrow(nonFatalCatcher)(classOf[MyBaseException]).withApply(e => new MyOtherDerivedException(e))
myCatching {
// some code throw new MyDerivedException
// some other code throw new java.lang.IllegalArgumentException
}
I find that Catch[T] should have a withRethrow(...) function to override the third parameters. This probably would be more elegant like that:
val myCatching = catching(nonFatalCatcher).withRethrow(...).withApply(e => new MyOtherDerivedException(e))
Did I miss something in scala.util.control.Exception that could accomplish that without custom code?
What are your thoughts on this?
Upvotes: 1
Views: 281
Reputation: 3541
I find that Catch[T] should have a withRethrow(...) function to override the third parameters. [...] Did I miss something in scala.util.control.Exception that could accomplish that without custom code?
Maybe there is something like a withRethrow
in the standard library, but I haven't seen it either. Luckily, Scala allows us to enrich existing interfaces using implicit classes. Assuming you do not mind adding three lines of custom code, you could achieve the desired syntax:
implicit class WithRethrow[T](theCatch: Catch[T]) {
def withRethrow(exceptions: Class[_]*): Catch[T] = new Catch[T](theCatch.pf, theCatch.fin, t => exceptions exists (_.isAssignableFrom(t.getClass)))
}
With your use-case
// may need to import the implicit class if it is not already in scope
val myCatching = catching(nonFatalCatcher).withRethrow(classOf[MyBaseException]).withApply(e => throw new MyOtherDerivedException(e))
myCatching {
throw new OutOfMemoryError() // OutOfMemoryError is thrown because it is not non-fatal
throw new IllegalArgumentException // MyOtherDerivedException is thrown because IllegalArgumentException is not rethrown
throw new MyDerivedException // MyDerivedException is thrown because MyDerivedException is rethrown
}
Upvotes: 2
Reputation: 17431
It seems like a very specialized/unusual use case. It violates LSP. And using exceptions at all is unidiomatic in scala - scala.util.control.Exception
is mainly about catching exceptions that library functions might throw and translating them into more idiomatic expressions of potential failures.
If you want to do this then write your own code for it - it should be pretty straightforward. I really don't think this is a common enough use case for there to be a standard library function for it.
Upvotes: -1