I don’t think this is workable. The behavior of the library has been that
ControlThrowable is not caught:
ControlThrowable should not normally be caught.
As a convenience,
NonFatal does not match
That’s pretty clear. Just in case there was any doubt,
NonFatal says so too:
Note that scala.util.control.ControlThrowable, an internal Throwable, is not matched by
Try unfortunately doesn’t mention this itself, it does say what behavior it follows:
Note: only non-fatal exceptions are caught by the combinators on
Try (see scala.util.control.NonFatal).
If people have written code that breaks because they wanted something else, I think it’s on them to fix it rather than breaking the working code written by people who took the care to do the right thing.
The Scala library is not the only case where custom control flow is used. The really pernicious thing about changing existing behavior is that it seemed like a strong guarantee, and seemed like there was no way it could break, so it’s unlikely to be caught even if there were moderately careful unit tests, and the compiler is unlikely to help at all.
If we want different control constructs that work differently, I think we should just create the ones we want. For instance, we could have a
NonFatal-like thing called, say,
ThreadBound that will catch anything that you want to try not to let leak out of the thread (including stray control flow).
Let’s not pretend that catching control flow in a
Try is ever likely to be the desired outcome. Your control flow is not going to work the way you want if it leaks out into some
Try or other catch statement. It’s already broken. The question is only whether you handle the broken behavior within the thread or if it kills the thread.
So if you want something that works like
Try but catches
ControlThrowable, create a new one that does the right thing. Then existing correct code stays correct, and existing wrong code created without regard to control throwables can be converted into existing less perniciously wrong code by a search-and-replace.
ControlThrowable alone, but switch
Try to not use
NonFatal and somehow try to very clearly document that everyone who followed the link and understood what
Try was and was not going to catch should switch to using something else (e.g.