View mode: basic / threaded / horizontal-split · Log in · Help
April 11, 2005
recoverable and unrecoverable errors or exceptions
I'm looking into the Error/Exception situation in phobos and previous posts
by Walter and others generally argued that Exceptions are recoverable and
Errors are not. I believe there isn't an application-independent definition
of what recoverable means and I would like to pursue an exception class
hierarchy that doesn't distinguish the two (ie like C#). The distinction in
Java is poorly designed and can be covered in D by subclassing Object
directly. The existing class heirarchy in phobos and user code also
seemingly randomly subclasses Error or Exception.

For example the class hierachy I have in mind looks like
Object
 OutOfMemory
 AssertionFailure
 Exception
   FileException
   StreamException
   ... etc, all the other exceptions and subclasses ...

where Exception is
class Exception {
   char[] msg;
   Object cause;
   this(char[] msg, Object cause = null);
   void print(); // print this exception and any causes
   char[] toString(); // string summarizes this exception
}

For reference see
http://www.digitalmars.com/d/archives/digitalmars/D/6049.html
http://www.digitalmars.com/d/archives/digitalmars/D/9556.html
http://www.digitalmars.com/d/archives/digitalmars/D/10415.html

comments?
April 11, 2005
Re: recoverable and unrecoverable errors or exceptions
On Mon, 11 Apr 2005 19:37:21 -0400, Ben Hinkle <bhinkle@mathworks.com>  
wrote:
> I'm looking into the Error/Exception situation in phobos and previous  
> posts
> by Walter and others generally argued that Exceptions are recoverable and
> Errors are not.

That seemed to me to be the general consesus.

> I believe there isn't an application-independent definition
> of what recoverable means and I would like to pursue an exception class
> hierarchy that doesn't distinguish the two (ie like C#).

I agree.

> The distinction in Java is poorly designed and can be covered in D by  
> subclassing Object
> directly.

So if you want an un-recoverable error you subclass object and never catch  
Object directly?

> The existing class heirarchy in phobos and user code also
> seemingly randomly subclasses Error or Exception.

That's the way it seems to me also. That and the docs should note the  
exceptions/errors thrown by each method/function, but that's a task for  
after this one.

> For example the class hierachy I have in mind looks like
> Object
>   OutOfMemory
>   AssertionFailure
>   Exception
>     FileException
>     StreamException
>     ... etc, all the other exceptions and subclasses ...

Where does "missing/incorrect parameter" fit in? My feeling is that it's a  
subclass of Object and not Exception? or in fact should it be handled with  
an assert statement and thus be an AssertionFailure?

But you probably didn't want specifics at this point, so I'll be quiet  
now. ;)

> where Exception is
> class Exception {
>     char[] msg;
>     Object cause;
>     this(char[] msg, Object cause = null);
>     void print(); // print this exception and any causes
>     char[] toString(); // string summarizes this exception
> }
>
> For reference see
> http://www.digitalmars.com/d/archives/digitalmars/D/6049.html
> http://www.digitalmars.com/d/archives/digitalmars/D/9556.html
> http://www.digitalmars.com/d/archives/digitalmars/D/10415.html
>
> comments?

I think it's a great idea, I believe it needs to be done before D 1.0 and  
I'd like to help in any way I can.

Regan
April 12, 2005
Re: recoverable and unrecoverable errors or exceptions
>> The distinction in Java is poorly designed and can be covered in D by 
>> subclassing Object
>> directly.
>
> So if you want an un-recoverable error you subclass object and never catch 
> Object directly?

What do you have in mind as a user-defined unrecoverable error? I was 
expecting users to subclass Exception (or some subclass of Exception) by 
convention. The only case that comes to mind where I could see subclassing 
something else would be to mimic the built-in AssertionFailure by 
subclassing it and adding some custom behavior.
From a technical point of view anyone can throw or catch any Object.

>> For example the class hierachy I have in mind looks like
>> Object
>>   OutOfMemory
>>   AssertionFailure
>>   Exception
>>     FileException
>>     StreamException
>>     ... etc, all the other exceptions and subclasses ...
>
> Where does "missing/incorrect parameter" fit in? My feeling is that it's a 
> subclass of Object and not Exception? or in fact should it be handled with 
> an assert statement and thus be an AssertionFailure?

I see assertion failures as different than a incorrect parameters. An 
assertion is a statement that must *always* be true no matter how the user 
has called your function or used your object. If an assertion fails the 
internal state of your part of the system is in doubt. By contrast an 
incorrect parameter is to be expected. It can get confusing when one starts 
to consider the user code as part of the same system as the function being 
called, but then the user code can have asserts to make sure its own interal 
state is consistent. To be concrete I was thinking that ArgumentException 
would subclass Exception and have the .Net hierarchy
 Exception
   ArgumentException
     ArgumentNullException
     ArgumentOutOfRangeException

> But you probably didn't want specifics at this point, so I'll be quiet 
> now. ;)

please ask any/all questions. The more the better.
April 12, 2005
Re: recoverable and unrecoverable errors or exceptions
On Mon, 11 Apr 2005 21:01:40 -0400, Ben Hinkle <ben.hinkle@gmail.com>  
wrote:
>>> The distinction in Java is poorly designed and can be covered in D by
>>> subclassing Object
>>> directly.
>>
>> So if you want an un-recoverable error you subclass object and never  
>> catch
>> Object directly?
>
> What do you have in mind as a user-defined unrecoverable error?

Nothing new, I was looking at:
  OutOfMemory
  AssertionFailure

and thought, for most applications these are treated as unrecoverable  
errors.

> I was
> expecting users to subclass Exception (or some subclass of Exception) by
> convention.

Agreed, 99% (maybe 100%) of the time. I wondered however whether it was  
possible for a user to want to create an unrecoverable error, i.e. for  
their application "Foo" is unrecoverable, if so they can do so, by  
subclassing Object, and ensuring they never catch(Object), or catch it in  
main and exit. Thus their application will always fail hard on "Foo".

> The only case that comes to mind where I could see subclassing
> something else would be to mimic the built-in AssertionFailure by
> subclassing it and adding some custom behavior.

Yeah, to add their own custom unrecoverable error of some sort.

> From a technical point of view anyone can throw or catch any Object.

Yep. I was thinking in terms of a style/convention which would be used to  
add custom unrecoverable errors.

>>> For example the class hierachy I have in mind looks like
>>> Object
>>>   OutOfMemory
>>>   AssertionFailure
>>>   Exception
>>>     FileException
>>>     StreamException
>>>     ... etc, all the other exceptions and subclasses ...
>>
>> Where does "missing/incorrect parameter" fit in? My feeling is that  
>> it's a
>> subclass of Object and not Exception? or in fact should it be handled  
>> with
>> an assert statement and thus be an AssertionFailure?
>
> I see assertion failures as different than a incorrect parameters. An
> assertion is a statement that must *always* be true no matter how the  
> user
> has called your function or used your object. If an assertion fails the
> internal state of your part of the system is in doubt. By contrast an
> incorrect parameter is to be expected. It can get confusing when one  
> starts
> to consider the user code as part of the same system as the function  
> being
> called, but then the user code can have asserts to make sure its own  
> interal
> state is consistent.

What you say makes sense to me. I've never really used assertions.
Where I was getting confused was that I was looking at it backwards, eg.

foo(5)
if '5' is an invalid parameter, this will *always* fail.

foo(<convert input from user to int>);
this will fail sometimes.

is there any difference in how the calls above should be handled? or  
should both simply be "ArgumentOutOfRangeException"

> To be concrete I was thinking that ArgumentException
> would subclass Exception and have the .Net hierarchy
>   Exception
>     ArgumentException
>       ArgumentNullException
>       ArgumentOutOfRangeException

Call me lazy but "ArgumentOutOfRangeException" seems like a really long  
name to use.
Apart from that, sounds good.

Regan
April 12, 2005
Re: recoverable and unrecoverable errors or exceptions
>> I was
>> expecting users to subclass Exception (or some subclass of Exception) by
>> convention.
>
> Agreed, 99% (maybe 100%) of the time. I wondered however whether it was 
> possible for a user to want to create an unrecoverable error, i.e. for 
> their application "Foo" is unrecoverable, if so they can do so, by 
> subclassing Object, and ensuring they never catch(Object), or catch it in 
> main and exit. Thus their application will always fail hard on "Foo".

ok. Seems fine to me.

>> The only case that comes to mind where I could see subclassing
>> something else would be to mimic the built-in AssertionFailure by
>> subclassing it and adding some custom behavior.
>
> Yeah, to add their own custom unrecoverable error of some sort.
>
>> From a technical point of view anyone can throw or catch any Object.
>
> Yep. I was thinking in terms of a style/convention which would be used to 
> add custom unrecoverable errors.

I think if we have a convention something is wrong :-P. Why have a 
convention for something that is discouraged?

> foo(5)
> if '5' is an invalid parameter, this will *always* fail.
>
> foo(<convert input from user to int>);
> this will fail sometimes.
>
> is there any difference in how the calls above should be handled? or 
> should both simply be "ArgumentOutOfRangeException"

Personally I would prefer that ArgumentOutOfRangeException be used for 
arguments to functions that get checked at the start of the function. User 
input should get treated more gracefully than throwing an exception IMO:
 class InputOutOfRangeException {...}
 bar() {
 barstart:
   int x = ...  prompt the user ...
   if (x == 5) {printf("try again doofus"); goto barstart;}
   foo(x);
 }
 void foo(int x) {
   if (x == 5) throw new ArgumentOutOfRangeException("Caller is a doofus");
 }

>> To be concrete I was thinking that ArgumentException
>> would subclass Exception and have the .Net hierarchy
>>   Exception
>>     ArgumentException
>>       ArgumentNullException
>>       ArgumentOutOfRangeException
>
> Call me lazy but "ArgumentOutOfRangeException" seems like a really long 
> name to use.

Yeah. I agree. I'm tempted to suggest using Error instead of Exception 
because it is easier to read and type but I have a feeling that would send 
confusing signals to people used to "exceptions" and Exception. There was an 
earlier thread about names but I only vaguely remember Exception "won". 
Maybe we could shorten these ArgumentExceptions to ArgExceptions or 
ParamException since it's obvious what Arg and Param mean. So how about
    ParamException
      ParamNullException
      ParamRangeException

> Apart from that, sounds good.

ok
April 12, 2005
Re: recoverable and unrecoverable errors or exceptions
On Mon, 11 Apr 2005 22:52:46 -0400, Ben Hinkle <ben.hinkle@gmail.com>  
wrote:
>>> The only case that comes to mind where I could see subclassing
>>> something else would be to mimic the built-in AssertionFailure by
>>> subclassing it and adding some custom behavior.
>>
>> Yeah, to add their own custom unrecoverable error of some sort.
>>
>>> From a technical point of view anyone can throw or catch any Object.
>>
>> Yep. I was thinking in terms of a style/convention which would be used  
>> to
>> add custom unrecoverable errors.
>
> I think if we have a convention something is wrong :-P. Why have a
> convention for something that is discouraged?

Because unless we address the issue (of defining a custom unrecoverable  
error) people will do it anyway and might do it in some other weird way.  
At least this way we can explain why it's discouraged, when it might be  
okay to use it and how to use it. I'm not suggesting we encourage it, just  
that we acknowledge it's existance and give a suggestion.

>> foo(5)
>> if '5' is an invalid parameter, this will *always* fail.
>>
>> foo(<convert input from user to int>);
>> this will fail sometimes.
>>
>> is there any difference in how the calls above should be handled? or
>> should both simply be "ArgumentOutOfRangeException"
>
> Personally I would prefer that ArgumentOutOfRangeException be used for
> arguments to functions that get checked at the start of the function.  
> User
> input should get treated more gracefully than throwing an exception IMO:
>   class InputOutOfRangeException {...}
>   bar() {
>   barstart:
>     int x = ...  prompt the user ...
>     if (x == 5) {printf("try again doofus"); goto barstart;}
>     foo(x);
>   }
>   void foo(int x) {
>     if (x == 5) throw new ArgumentOutOfRangeException("Caller is a  
> doofus");
>   }

Thanks, that makes sense.

>>> To be concrete I was thinking that ArgumentException
>>> would subclass Exception and have the .Net hierarchy
>>>   Exception
>>>     ArgumentException
>>>       ArgumentNullException
>>>       ArgumentOutOfRangeException
>>
>> Call me lazy but "ArgumentOutOfRangeException" seems like a really long
>> name to use.
>
> Yeah. I agree. I'm tempted to suggest using Error instead of Exception
> because it is easier to read and type but I have a feeling that would  
> send
> confusing signals to people used to "exceptions" and Exception. There  
> was an
> earlier thread about names but I only vaguely remember Exception "won".

I think you're right (on both points).

> Maybe we could shorten these ArgumentExceptions to ArgExceptions or
> ParamException since it's obvious what Arg and Param mean. So how about
>      ParamException
>        ParamNullException
>        ParamRangeException
>

Just thinking about this, null and out of range are effectively the same  
thing, as null is "out of range" for a parameter that "cannot be null'. So  
we *could* just combine them.

But then, of course, the reason for not combining them is so we can catch  
them seperately:

void foo(int a){}

try {
  foo(5);
} catch(ParamNullException e) {
} catch(ParamRangeException e) {
}

Otherwise we could just say:

class ParamException {
  this(char[] param, char[] problem) {
  }
}

And have it print "ParamException: (%s) is %s", eg:
"ParamException: (a) is out of range"
"ParamException: (a) is null"
"ParamException: (a) is not my favourite number"
"ParamException: (a) is unlucky for some"

<Warning: wacky idea>
It's a pity the class tree isn't more 'obvious' then we could simply drop  
the redundant 'Exception' alltogether. eg.

Exception
  Parameter
    Null
    OutOfRange

Is this:

try {
} catch(OutOfRange e) {
}

really that opaque that it requires this:

try {
} catch(ParamRangeException e) {
}

?

Of course, it then becomes possible to have collisions within the tree.

Exception
  Aaaaa
    Here
  Bbbbb
    Here

Exception.Aaaaa.Here
Exception.Bbbbb.Here

are both called "Here".
</wacky idea>

Regan
April 12, 2005
Re: recoverable and unrecoverable errors or exceptions
"Regan Heath" <regan@netwin.co.nz> wrote in message
news:opso3kiga523k2f5@nrage.netwin.co.nz...
> On Mon, 11 Apr 2005 21:01:40 -0400, Ben Hinkle
> <ben.hinkle@gmail.com>  wrote:
>>>> The distinction in Java is poorly designed and can be covered
>>>> in D by
>>>> subclassing Object
>>>> directly.
>>>
>>> So if you want an un-recoverable error you subclass object and
>>> never  catch
>>> Object directly?
>>
>> What do you have in mind as a user-defined unrecoverable error?
>
> Nothing new, I was looking at:
>   OutOfMemory
>   AssertionFailure
>
> and thought, for most applications these are treated as
> unrecoverable  errors.

They may be, but that's quite wrong.

OutOfMemory is practically unrecoverable, but should not be classed
as an unrecoverable exception.
Conversely, AssertionFailure is practically recoverable, but most
certainly should be classed as unrecoverable. (And the language
should mandate and enforce the irrecoverability.)
April 12, 2005
Re: recoverable and unrecoverable errors or exceptions
"Ben Hinkle" <bhinkle@mathworks.com> wrote in message 
news:d3f1nh$rj4$1@digitaldaemon.com...
> I'm looking into the Error/Exception situation in phobos and 
> previous posts
> by Walter and others generally argued that Exceptions are 
> recoverable and
> Errors are not. I believe there isn't an application-independent 
> definition
> of what recoverable means

An exception that may not be quenched, or in whose quenching the 
runtime takes over to terminate the process.

Naturally, the system should provide an opportunity for cleanup of 
arbitrary sophistication, but the infrastructure should not support 
resuming normal processing. However meandering the path - as a 
consequence of the requirements of the application (e.g. dumping 
unsaved data in as fine a form as possible) - it must lead to 
process termination.

Off the top of my head, only CP violations are unrecoverable, so 
it's not exactly

>and I would like to pursue an exception class
> hierarchy that doesn't distinguish the two (ie like C#). The 
> distinction in
> Java is poorly designed and can be covered in D by subclassing 
> Object
> directly. The existing class heirarchy in phobos and user code 
> also
> seemingly randomly subclasses Error or Exception.

All of the that speaks to the likelihood that those hierarchies were 
ill-considered, rather than that there's an intrinsic problem in 
segregating the exceptions/errors. In my C++ work, I use exception 
classes (always derived directly/indirectly from std::exception) for 
exceptions, and types derived from ::stlsoft::unrecoverable for, er, 
unrecoverable errors. Works a treat, and never caused any probs. 
(I've had this stuff, coupled with a release-mode contract 
enforcement, and verbose, but immediate, application termination in 
a real-time multi-protocol financial system running the last 4-5 
months. It caught two fundamental design oversights in the first 
week, and hasn't uttered a peep since. All is working tickety-boo.)

> For example the class hierachy I have in mind looks like
> Object
>  OutOfMemory
>  AssertionFailure
>  Exception
>    FileException
>    StreamException
>    ... etc, all the other exceptions and subclasses ...
>
> where Exception is
> class Exception {
>    char[] msg;
>    Object cause;
>    this(char[] msg, Object cause = null);
>    void print(); // print this exception and any causes
>    char[] toString(); // string summarizes this exception
> }
>
> For reference see
> http://www.digitalmars.com/d/archives/digitalmars/D/6049.html
> http://www.digitalmars.com/d/archives/digitalmars/D/9556.html
> http://www.digitalmars.com/d/archives/digitalmars/D/10415.html
>
> comments?

Problems with the above:
   1. I want to see the ability to throw/catch an Object removed. 
(Or, if someone can possibly proffer a justification for wanting to 
do that - what has it ever benefited anyone in C++ to be able to 
throw a double? - incur a warning.) What's wrong with something 
Throwable? It's not like anyone will (or at least should!) be mixing 
an exception's duties with some other functionality, so there's no 
need to fear the constraints of a strict single-inheritance 
hierarchy.
   2. I grok that you've identified the strange nature of 
OutOfMemory, in so far as it's theoretically recoverable but 
practically irrecoverable (except when one is supplying custom 
allocation). I agree that it's not a simple straightforward issue. 
I'd suggest that this is the one area that needs more thinking 
(including how other resource exhaustion might relate).
   3. AssertionFailure - which I presume is the parent to a more 
detailed CP hierarchy - should be an Error, and irrecoverable (as 
per discussion above).

I'd started work some months ago on suggestions for how Errors 
should be intrinsically handled within the language. I'll try and 
dig it out and post it. But, AFAICR, I posit that they should be 
analogous to function-try blocks in C++: it's fine (in fact 
professionally questionable not!) to catch them and exercise the 
application-specific level of informing of the user / dumping data / 
logging to SysLog/event-log/file/whatever, but the runtime, *in all 
threads*, will always rethrow any caught error, and will also 
provide intrinsic "catch(Error) { exit(EXIT_FAILURE); }" at the 
topmost level. The way I achieve this in the 
::stlsoft::unrecoverable type is by ref-counting (similar to the 
shared_ptr mechanism) and the last one (copy, that is) out turns the 
lights off; it works a treat, as I mentioned above, and is not the 
least constricting, since it kindly waits until you've finished all 
your cleanup, even if you do several levels of cleanup by rethrowing 
the error. But since D holds exception objects by reference, all 
that jazz is unnecessary. In any case, such things are far better 
encapsulated in the language given that we (as I assert we do) want 
to avoid throwing of arbitrary types.

I know this is going to stir the same hornet's nest of people who 
feel like it's big-brother-ism, or who don't understand that a 
program that has violated its design is, from then on, invalid and 
open to *any* behaviour (obviously the more exotic things, like 
bringing down the internet or signalling to aliens that we want to 
be liberated by a benevolent megamilitarist, are somewhat less 
likely than the more prosaic). Killing it is the only right thing to 
do. And it's also the effective and convenient thing to do. As I've 
said, I've been running this stuff in the real world for some time, 
and clients always shit themselves at the prospect, but then 
completely come around when they see the speed at which the code 
reaches a point where it's no longer violating its design. In the 
words of the Pragmatic Programmers (section "DBC and Crashing 
Early", pp115, of TPP): "It's much easier to find and diagnose the 
problem by crashing early, at the site of the problem."

There is one valid scenario where errors should be quenchable: 
debuggers. For that, I have no immediate prescription, but I'm sure 
we can find a way to facilitate that without breaking the clean (and 
easily understand) delineation between exceptions and errors. (One 
idea might be that a base library function to turn on error 
quenching could be tied to the security infrastructure used by 
debuggers. Those with more experience than me in writing debuggers 
can no doubt some sense of this.)

Charon
April 12, 2005
Re: recoverable and unrecoverable errors or exceptions
> Off the top of my head, only CP violations are unrecoverable, so 
> it's not exactly

onerous or limiting
April 12, 2005
Re: recoverable and unrecoverable errors or exceptions
On Tue, 12 Apr 2005 15:16:55 +1000, Matthew  
<admin@stlsoft.dot.dot.dot.dot.org> wrote:
> "Regan Heath" <regan@netwin.co.nz> wrote in message
> news:opso3kiga523k2f5@nrage.netwin.co.nz...
>> On Mon, 11 Apr 2005 21:01:40 -0400, Ben Hinkle
>> <ben.hinkle@gmail.com>  wrote:
>>>>> The distinction in Java is poorly designed and can be covered
>>>>> in D by
>>>>> subclassing Object
>>>>> directly.
>>>>
>>>> So if you want an un-recoverable error you subclass object and
>>>> never  catch
>>>> Object directly?
>>>
>>> What do you have in mind as a user-defined unrecoverable error?
>>
>> Nothing new, I was looking at:
>>   OutOfMemory
>>   AssertionFailure
>>
>> and thought, for most applications these are treated as
>> unrecoverable  errors.
>
> They may be, but that's quite wrong.
>
> OutOfMemory is practically unrecoverable, but should not be classed
> as an unrecoverable exception.

Agreed, in part, why "class" it as anything but what it is?

> Conversely, AssertionFailure is practically recoverable, but most
> certainly should be classed as unrecoverable.

As above, why "class" it as anything but what it is?

> (And the language
> should mandate and enforce the irrecoverability.)

Disagree.

Regan
« First   ‹ Prev
1 2 3 4 5
Top | Discussion index | About this forum | D home