On Monday, 25 April 2016 at 08:42:33 UTC, Shachar Shemesh wrote:
There is a problem with scope(exit) and scope(failure) running
when Error types exceptions are thrown. It throws the program
into code paths that are really not healthy.
Imagine, for example, code handling linked lists. We do
manipulations on linked lists, and put a scope(exit) that
clears stuff up.
Now imagine that somewhere inside, we have an assert that makes
sure that everything is still in order. If it's not, then an
AsserError is thrown, which derive from Error. The scope(exit)
runs, but since things are not where they should be (hence the
assert), we segfault. All the useful stuff that the assert was
supposed to provide us is now gone, replaced by cleanup code
that had no business running under those circumstances.
Even when not harmful, this is, often, useless. Even if the
cleanup proceeds correctly, what is the sense of cleaning up
when the program is in serious trouble?
The above is not categorically always true. In Weka, for
example, we are using exceptions derived from Error to force
all fibers of a certain logical component to exit. It is useful
that these exceptions are not caught. In those cases, there are
some types of cleanups that we do want to take place, but not
others.
Some way to control this would be appreciated.
Shachar
So, if I understand correctly, you want scope(exit) and
scope(failure) code to run only when an exception not derived
from Error is thrown (because otherwise the program is in an
undefined state), but you need an uncatchable exception, so you
can't derive from Exception?
Then why don't you use this:
class Fault : Throwable
{ /* ... */ }
// Error: can only catch class objects derived from Exception in
@safe code, not 'Fault':
try
faultThrowingFunc()
catch (Fault f) //
// ...
And change `assert (expr, "Error msg")` to `expr || abort("Error
msg")`, which will cleanly terminate the program immediately,
instead of throwing AssertError and choking on scope blocks.
Example: http://dpaste.dzfl.pl/5a557d982230