I don’t think this is workable. The behavior of the library has been that ControlThrowable
is not caught:
Instances of ControlThrowable
should not normally be caught.
As a convenience, NonFatal
does not match ControlThrowable
.
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 NonFatal
and although 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.
Alternatively, leave NonFatal
and 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. Try.withControl
).