View mode: basic / threaded / horizontal-split · Log in · Help
March 09, 2012
[dmd-internals] Throwing Errors
The issue of catching Errors came up in D.learn today, and I need some 
clarification. It has been my understanding that anything which is thrown which 
is not derived from Exception skips all destructors, scope statements, and 
finally blocks, meaning that it's generally unsafe to catch them, because your 
program is potentially in an invalid state. However, it was brought to my 
attention that the compiler does not currently follow this behavior - all 3 of 
those get run for Errors at present. So, the question is whether I'm just 
completely misunderstanding something or whether something has changed.

Is it guaranteed that all thrown Throwables will result in all destructors, 
scope statements (exit and failure at least), and finally blocks that they pass 
being executed? Or is it only guaranteed for Exception and its derived types 
and just so happens to work for other exception types right now?

I've been completely certain that such was _not_ guaranteed unless the 
exception type is Exception or derived from Exception, but I can't find any 
support for that searching the docs or newsgroup save for what I've said about 
it myself. So, I'd like official clarification on the matter.

- Jonathan M Davs
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
March 09, 2012
Re: [dmd-internals] Throwing Errors
On 3/9/2012 6:29 PM, Jonathan M Davis wrote:
> The issue of catching Errors came up in D.learn today, and I need some
> clarification. It has been my understanding that anything which is thrown which
> is not derived from Exception skips all destructors, scope statements, and
> finally blocks, meaning that it's generally unsafe to catch them, because your
> program is potentially in an invalid state. However, it was brought to my
> attention that the compiler does not currently follow this behavior - all 3 of
> those get run for Errors at present. So, the question is whether I'm just
> completely misunderstanding something or whether something has changed.
>
> Is it guaranteed that all thrown Throwables will result in all destructors,
> scope statements (exit and failure at least), and finally blocks that they pass
> being executed? Or is it only guaranteed for Exception and its derived types
> and just so happens to work for other exception types right now?

It just so happens to work. It's wrong.

> I've been completely certain that such was _not_ guaranteed unless the
> exception type is Exception or derived from Exception, but I can't find any
> support for that searching the docs or newsgroup save for what I've said about
> it myself. So, I'd like official clarification on the matter.
>


_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
March 12, 2012
Re: [dmd-internals] Throwing Errors
On Mar 9, 2012, at 9:38 PM, Walter Bright wrote:
> 
> On 3/9/2012 6:29 PM, Jonathan M Davis wrote:
>> The issue of catching Errors came up in D.learn today, and I need some
>> clarification. It has been my understanding that anything which is thrown which
>> is not derived from Exception skips all destructors, scope statements, and
>> finally blocks, meaning that it's generally unsafe to catch them, because your
>> program is potentially in an invalid state. However, it was brought to my
>> attention that the compiler does not currently follow this behavior - all 3 of
>> those get run for Errors at present. So, the question is whether I'm just
>> completely misunderstanding something or whether something has changed.
>> 
>> Is it guaranteed that all thrown Throwables will result in all destructors,
>> scope statements (exit and failure at least), and finally blocks that they pass
>> being executed? Or is it only guaranteed for Exception and its derived types
>> and just so happens to work for other exception types right now?
> 
> It just so happens to work. It's wrong.

I'm on the fence about whether attempting cleanup when an Error is thrown is desired behavior.  If there is no cleanup, why allow Errors to be caught at all?  We may as well simply call abort() at the point they're thrown.
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
March 12, 2012
Re: [dmd-internals] Throwing Errors
It would be hard to write a framework around D unit tests, for
instance, where you need to catch AssertErrors if things weren't
cleaned up properly (or if it just called abort()). That's just the
first thing that comes to mind.

Regards,
Alex

On Mon, Mar 12, 2012 at 8:34 PM, Sean Kelly <sean@invisibleduck.org> wrote:
> On Mar 9, 2012, at 9:38 PM, Walter Bright wrote:
>>
>> On 3/9/2012 6:29 PM, Jonathan M Davis wrote:
>>> The issue of catching Errors came up in D.learn today, and I need some
>>> clarification. It has been my understanding that anything which is thrown which
>>> is not derived from Exception skips all destructors, scope statements, and
>>> finally blocks, meaning that it's generally unsafe to catch them, because your
>>> program is potentially in an invalid state. However, it was brought to my
>>> attention that the compiler does not currently follow this behavior - all 3 of
>>> those get run for Errors at present. So, the question is whether I'm just
>>> completely misunderstanding something or whether something has changed.
>>>
>>> Is it guaranteed that all thrown Throwables will result in all destructors,
>>> scope statements (exit and failure at least), and finally blocks that they pass
>>> being executed? Or is it only guaranteed for Exception and its derived types
>>> and just so happens to work for other exception types right now?
>>
>> It just so happens to work. It's wrong.
>
> I'm on the fence about whether attempting cleanup when an Error is thrown is desired behavior.  If there is no cleanup, why allow Errors to be caught at all?  We may as well simply call abort() at the point they're thrown.
> _______________________________________________
> dmd-internals mailing list
> dmd-internals@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-internals
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
March 12, 2012
Re: [dmd-internals] Throwing Errors
On 12 mar 2012, at 21:06, Alex wrote:

> It would be hard to write a framework around D unit tests, for
> instance, where you need to catch AssertErrors if things weren't
> cleaned up properly (or if it just called abort()). That's just the
> first thing that comes to mind.
> 
> Regards,
> Alex
> 


I completely agree. That's what I've been discussion in the "learn" newsgroup. I had a look through the source code of druntime and found "onAssertError". I don't know if it's used or not but sounds exactly like the function I need. But unfortunately the function to set the assert handler is deprecated. 

http://dlang.org/phobos/core_exception.html#onAssertError
http://dlang.org/phobos/core_exception.html#setAssertHandler

-- 
/Jacob Carlborg
March 12, 2012
Re: [dmd-internals] Throwing Errors
On 12 March 2012 20:34, Sean Kelly <sean@invisibleduck.org> wrote:
> On Mar 9, 2012, at 9:38 PM, Walter Bright wrote:
>>
>> On 3/9/2012 6:29 PM, Jonathan M Davis wrote:
>>> The issue of catching Errors came up in D.learn today, and I need some
>>> clarification. It has been my understanding that anything which is thrown which
>>> is not derived from Exception skips all destructors, scope statements, and
>>> finally blocks, meaning that it's generally unsafe to catch them, because your
>>> program is potentially in an invalid state. However, it was brought to my
>>> attention that the compiler does not currently follow this behavior - all 3 of
>>> those get run for Errors at present. So, the question is whether I'm just
>>> completely misunderstanding something or whether something has changed.
>>>
>>> Is it guaranteed that all thrown Throwables will result in all destructors,
>>> scope statements (exit and failure at least), and finally blocks that they pass
>>> being executed? Or is it only guaranteed for Exception and its derived types
>>> and just so happens to work for other exception types right now?
>>
>> It just so happens to work. It's wrong.
>
> I'm on the fence about whether attempting cleanup when an Error is thrown is desired behavior.  If there is no cleanup, why allow Errors to be caught at all?  We may as well simply call abort() at the point they're thrown.

I went to a lot of trouble to ensure the exception chaining behaviour
of Errors vs Exceptions.

Personally, I just don't buy the argument that the entire system is in
an invalid state when an Error occurs. It's a sign that some subsystem
is in a invalid state, but how much of the whole app is invalid,
depends on the particular situation. For example, if you're
extensively using class invariants and contracts, and you get an
AssertError, then the possible damage is pretty small. Especially if
it is an assert failure in a pure @safe function; cleanup will be
perfectly safe in that situation.

I would have thought that if you had a truly fatal error, you would
have called exit() or something, instead of throwing an Error.
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
March 12, 2012
Re: [dmd-internals] Throwing Errors
On Monday, March 12, 2012 21:29:25 Don Clugston wrote:
> I went to a lot of trouble to ensure the exception chaining behaviour
> of Errors vs Exceptions.
> 
> Personally, I just don't buy the argument that the entire system is in
> an invalid state when an Error occurs. It's a sign that some subsystem
> is in a invalid state, but how much of the whole app is invalid,
> depends on the particular situation. For example, if you're
> extensively using class invariants and contracts, and you get an
> AssertError, then the possible damage is pretty small. Especially if
> it is an assert failure in a pure @safe function; cleanup will be
> perfectly safe in that situation.
> 
> I would have thought that if you had a truly fatal error, you would
> have called exit() or something, instead of throwing an Error.

When an Error is thrown, the program is in a potentially invalid state. How 
invalid it is, depends on the Error. And the fact that cleanup isn't 
guaranteed _definitely_ puts the program in an invalid state when an Error is 
thrown unless it's caught very close to its throw point.

I'm not sure how much it matters whether there is any attempt to cleanup from 
Errors except that if the Error _does_ indicate something which would 
invalidate the cleanup code, it could cause serious problems. The main one 
that I can think of is OutOfMemoryError, since if any cleanup code then tries 
to allocate anything, it's going to fail. Of course, that would then result in 
_another_ OutOfMemoryError, so it may be that that pretty much takes care of 
itself and really isn't a big deal.

Certainly, in the general case, even if cleanup _is_ guaranteed, catching 
Errors is a bad idea because of the types of problems that they generally 
indicate. But there _are_ cases where catching Errors can be useful - the most 
prevalent one being catching AssertErrors in unit tests. Anyone trying to use 
a fancier unit testing framework (which I don't personally see any need for, 
but some people are _very_ interested in it - e.g. Jacob Carlborg) is going to 
have to do that. And in rare cases, even catching OutOfMemoryError makes some 
sense. You just have to know what you're doing and be careful.

The _biggest_ thing with Errors is simply that they're not Exceptions, so

catch(Exception e) {}

won't catch them, and nothrow isn't affected by them. That right there provides 
their primary benefit. Personally, I'm on the fence as to whether attempting 
cleanup when an Error is thrown is a good idea or not. Certainly, in the unit 
testing case, it would certainly be desirable. Most of the rest, it probably 
doesn't matter all that much, but it would arguably be desirable to skip 
cleanup for them so that the amount of weird stuff that can happen on shutting 
down the program can be minimized. But of course, it also makes it harder to 
guarantee that certain things are done on shutdown, and it's not all that 
uncommon to have stuff that you want to _guarantee_ runs on shutdown, even if 
it's not a clean shutdown (or even _especially_ if it's not a clean shutdown).

The other thing to consider is the fact that very few people seem to 
understand that Errors in flight aren't guaranteed to execute scope statements, 
destructors, or finally blocks. So, there's definitely code being written which 
relies on behavior that is not guaranteed. The fact that it currently happens 
in most (all?) cases just makes it worse, since then there's more stuff that 
will break (particularly unit testing frameworks like Jacob's) when it does. 
Heck, simply being able to rely on scope(failure) running for AssertErrors 
would be valuable for unit testing, since it makes it much easier to output 
extra information on failures. And I expect that _that_ is done quite 
frequently. I'm pretty sure that I've done it a number of times myself, 
forgetting that that's not guaranteed to work. So, there's definitely code out 
there which relies on Errors triggering all of the appropriate cleanup stuff 
just like Exceptions do.

I'd argue that we should decide whether cleanup on Errors should be guaranteed 
or not and then make it so that the compiler _always_ follows this behavior so 
that the behavior - whatever it may be - _is_ guaranteed. Having the behavior 
be undefined is just causing problems.

- Jonathan M Davis
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
March 12, 2012
Re: [dmd-internals] Throwing Errors
On Mar 12, 2012, at 1:13 PM, Jacob Carlborg wrote:

> On 12 mar 2012, at 21:06, Alex wrote:
> 
>> It would be hard to write a framework around D unit tests, for
>> instance, where you need to catch AssertErrors if things weren't
>> cleaned up properly (or if it just called abort()). That's just the
>> first thing that comes to mind.
> 
> I completely agree. That's what I've been discussion in the "learn" newsgroup. I had a look through the source code of druntime and found "onAssertError". I don't know if it's used or not but sounds exactly like the function I need. But unfortunately the function to set the assert handler is deprecated. 
> 
> http://dlang.org/phobos/core_exception.html#onAssertError
> http://dlang.org/phobos/core_exception.html#setAssertHandler

The handler is deprecated because DMD doesn't generate a valid call stack for _d_assert (which calls onAssertError) so it's impossible to return from the assert handler without throwing.  This rendered the assert handler largely useless and after a few years of no one using it I decided to deprecate it.  I'd be happy to keep the assert handler if people actually want it though, or if DMD changes its codegen.  Personally, I'd like to be able to assert without throwing in some testing situations, and overriding a handler seems like an appropriate way to do this.
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
March 12, 2012
Re: [dmd-internals] Throwing Errors
On 3/12/2012 12:34 PM, Sean Kelly wrote:
>
> I'm on the fence about whether attempting cleanup when an Error is thrown is desired behavior.  If there is no cleanup, why allow Errors to be caught at all?  We may as well simply call abort() at the point they're thrown.
>

So that an informative message can be printed, the backup engaged, attempt to 
shut down gracefully, log the failure details to a file, etc.
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
March 12, 2012
Re: [dmd-internals] Throwing Errors
On 12 March 2012 22:06, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> On Monday, March 12, 2012 21:29:25 Don Clugston wrote:
>> I went to a lot of trouble to ensure the exception chaining behaviour
>> of Errors vs Exceptions.
>>
>> Personally, I just don't buy the argument that the entire system is in
>> an invalid state when an Error occurs. It's a sign that some subsystem
>> is in a invalid state, but how much of the whole app is invalid,
>> depends on the particular situation. For example, if you're
>> extensively using class invariants and contracts, and you get an
>> AssertError, then the possible damage is pretty small. Especially if
>> it is an assert failure in a pure @safe function; cleanup will be
>> perfectly safe in that situation.
>>
>> I would have thought that if you had a truly fatal error, you would
>> have called exit() or something, instead of throwing an Error.
>
> When an Error is thrown, the program is in a potentially invalid state. How
> invalid it is, depends on the Error. And the fact that cleanup isn't
> guaranteed _definitely_ puts the program in an invalid state when an Error is
> thrown unless it's caught very close to its throw point.
>
> I'm not sure how much it matters whether there is any attempt to cleanup from
> Errors except that if the Error _does_ indicate something which would
> invalidate the cleanup code, it could cause serious problems. The main one
> that I can think of is OutOfMemoryError, since if any cleanup code then tries
> to allocate anything, it's going to fail. Of course, that would then result in
> _another_ OutOfMemoryError, so it may be that that pretty much takes care of
> itself and really isn't a big deal.
>
> Certainly, in the general case, even if cleanup _is_ guaranteed, catching
> Errors is a bad idea because of the types of problems that they generally
> indicate. But there _are_ cases where catching Errors can be useful - the most
> prevalent one being catching AssertErrors in unit tests. Anyone trying to use
> a fancier unit testing framework (which I don't personally see any need for,
> but some people are _very_ interested in it - e.g. Jacob Carlborg) is going to
> have to do that. And in rare cases, even catching OutOfMemoryError makes some
> sense. You just have to know what you're doing and be careful.
>
> The _biggest_ thing with Errors is simply that they're not Exceptions, so
>
> catch(Exception e) {}
>
> won't catch them, and nothrow isn't affected by them. That right there provides
> their primary benefit. Personally, I'm on the fence as to whether attempting
> cleanup when an Error is thrown is a good idea or not. Certainly, in the unit
> testing case, it would certainly be desirable. Most of the rest, it probably
> doesn't matter all that much, but it would arguably be desirable to skip
> cleanup for them so that the amount of weird stuff that can happen on shutting
> down the program can be minimized. But of course, it also makes it harder to
> guarantee that certain things are done on shutdown, and it's not all that
> uncommon to have stuff that you want to _guarantee_ runs on shutdown, even if
> it's not a clean shutdown (or even _especially_ if it's not a clean shutdown).
>
> The other thing to consider is the fact that very few people seem to
> understand that Errors in flight aren't guaranteed to execute scope statements,
> destructors, or finally blocks.

Well  I've never heard that before, and I wrote the code on Windows to
make sure that they do get executed.
It's not an accident that it works.
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
« First   ‹ Prev
1 2 3 4 5
Top | Discussion index | About this forum | D home