digitalmars.D - Exception hierarchy refactoring
- Matthew (19/19) Sep 09 2004 I've persuaded big-W that the exception hierarchy refactoring can wait n...
- Ben Hinkle (25/44) Sep 10 2004 I'd like to see something like Java's and C#'s support. I'll pick the Ja...
- Ben Hinkle (32/88) Sep 10 2004 Let me add I'd like to see some standard exceptions, too. For example th...
- Nick (17/17) Sep 10 2004 How about a static opCall in exceptions? This can be done in two ways, I...
- Regan Heath (16/117) Sep 11 2004 I think we need a good definition of what is an 'Error' and what is an
- Ben Hinkle (6/16) Sep 12 2004 yeah - that could be. I just thought it should be an Exception because u...
- Regan Heath (6/14) Sep 12 2004 I agree. So are you also suggesting that an Error is uncatchable?
- Ben Hinkle (21/37) Sep 12 2004 Anything is catchable according to the language spec. The code
- Regan Heath (11/49) Sep 12 2004 Indeed. IIRC Matthew once suggested that Error should be uncatchable, I
- Sean Kelly (41/75) Sep 12 2004 I think Matthew said Errors should be unrecoverable, not uncatchable.
- Regan Heath (13/91) Sep 13 2004 I agree. If you cannot catch it, there is no point in throwing it.
- Nick (10/24) Sep 13 2004 I don't think the above is lazy. In fact, I think that's the way it shou...
- Ben Hinkle (8/36) Sep 13 2004 Catching all exceptions is what I meant by lazy. Usually one should catc...
- Nick (35/51) Sep 14 2004 For many cases I agree with you, but in some cases you will want to catc...
- Sean Kelly (5/16) Sep 12 2004 They will probably mostly be platform-dependent. Something that results...
- Garett Bass (10/14) Sep 12 2004 I don't understand why you would have to write your "own for
- Ben Hinkle (7/23) Sep 12 2004 true - I can share my own exceptions between the libraries that I write
- Sean Kelly (5/5) Sep 10 2004 Semi-related. I just posted a bunch of exception issues to the bugs for...
- Farmer (202/215) Sep 15 2004 I propose this (over-engineered) java-like exception hierarchy:
- Sean Kelly (29/82) Sep 15 2004 In this case, I would argue that TooManyThreadsError and OutOfMemoryErro...
- Farmer (63/139) Sep 15 2004 First, to clear up one misunderstanding:
- Sean Kelly (16/76) Sep 15 2004 Ah, thanks for clearing this up. That distinction between Exceptions an...
- Farmer (22/65) Sep 16 2004 Yes, it's an Error, but making errors sometimes is a good thing.
- Sean Kelly (12/37) Sep 16 2004 Combined with DBC, this should hopefully be pretty obvious, as I'd expec...
- Ben Hinkle (49/79) Sep 15 2004 Very nice post! You've convinced me of the general ideas. Some comments,
- Farmer (89/177) Sep 16 2004 I felt exactly the same way. And then I thought that the hierarchy is we...
- Sean Kelly (11/69) Sep 19 2004 I like having the system-generated exceptions at the top-level rather
- Farmer (23/35) Sep 20 2004 Just some alternative names for "checked/unchecked", that I made up myse...
- Regan Heath (12/54) Sep 20 2004 Going by your previous descriptions..
-
Farmer
(11/23)
Sep 21 2004
Regan Heath
wrote in - Regan Heath (11/33) Sep 21 2004 this is just plain wrong.
- Nick (4/8) Sep 22 2004 I agree with your definition, but doesn't this mean that _all_ thrown
- Sjoerd van Leent (10/24) Sep 22 2004 I disagree with this. A RuntimeError is an error which occurs when it is...
- Regan Heath (23/45) Sep 22 2004 That's not my definition.
- Nick (5/50) Sep 23 2004 Seeing as different people seems to have different opinions on the defin...
- Regan Heath (37/104) Sep 23 2004 Well of course IMO other people have the 'wrong' definition of RunTime :...
- Regan Heath (26/35) Sep 22 2004 I see what you mean, perhaps my definition is a little vague still,
-
Farmer
(33/42)
Sep 20 2004
Farmer
wrote in - Regan Heath (21/68) Sep 20 2004 I think if you re-factor the tree into something like:
- Farmer (7/31) Sep 21 2004 The problem is, that some/most people want to have a common base class f...
- Regan Heath (27/52) Sep 21 2004 Why?
- Sean Kelly (4/15) Sep 21 2004 If D doesn't support catching interfaces then it should. That the compi...
- Farmer (37/42) Sep 22 2004 I suppose, you're right.
- Matthew (5/220) Sep 15 2004 Just wanted to thank you for a very detailed and thought-provoking analy...
- Farmer (43/43) Sep 20 2004 Here's an interesting proposal of an refactored exception hierarchy for
- Sean Kelly (18/24) Sep 30 2004 Thanks for the links. My Java experience is quite a few years out of da...
I've persuaded big-W that the exception hierarchy refactoring can wait no longer, but to do so I've had to volunteer to marshal the efforts. My plan is as follows: 1. Solicit *on-topic* criticisms from the newsgroup 2. Put on my code reviewer's hat, and do a detailed analysis and criticism of the current situation. I'll do this *before* I read any of these criticisms, so as to be unbiased in the review. This means you've a week or so before I'll be digesting and collating any responses from the community, so please take your time to provide considered comments. 3. Amalgamate these two sets of information (along with any prior posts on the subject that I can easily find in the ng) into a (hopefully) simple recommendation for necessary changes to Walter. (If it doesn't fit into three pages (+ listings) or less, I shall consider it a failure.) 4. Release the findings, and Walter's response (if it counters any of the recommendations), to the community for *on-topic* debate. 5. Implement any changes, gratefully taking advantage of any volunteers who popped up their hands in steps 1. or 4.. Note: please resist the temptation to wander OT, or get in slagging matches. I'm barely less busy than Walter at the moment, so am just going to ignore any posts (and their sub-threads) like that, and any useful criticisms contained therein will be wasted. Hopefully, by the time we hit 0.103 we should be in good shape. If the process works, we might start a trend. Cheers Matthew
Sep 09 2004
names: class Throwable { this(char[] msg = null, Throwable cause = null) {...} Throwable cause() { getter for cause } char[] toString() {...} void print() {...} // should not allocate any memory } class Error : Throwable {...} // non-recoverable error class Exception : Throwable {...} // recoverable error The only Error subclasses should be AssertError, SwitchError. All subclasses of Exception should have names that end with Exception. "Matthew" <admin.hat stlsoft.dot.org> wrote in message news:chrebn$12f7$1 digitaldaemon.com...I've persuaded big-W that the exception hierarchy refactoring can wait nolonger, but to do so I've had to volunteer tomarshal the efforts. My plan is as follows: 1. Solicit *on-topic* criticisms from the newsgroup 2. Put on my code reviewer's hat, and do a detailed analysis and criticismof the current situation. I'll do this*before* I read any of these criticisms, so as to be unbiased in thereview. This means you've a week or so before I'llbe digesting and collating any responses from the community, so pleasetake your time to provide considered comments.3. Amalgamate these two sets of information (along with any prior posts onthe subject that I can easily find in the ng)into a (hopefully) simple recommendation for necessary changes to Walter.(If it doesn't fit into three pages (+listings) or less, I shall consider it a failure.) 4. Release the findings, and Walter's response (if it counters any of therecommendations), to the community for*on-topic* debate. 5. Implement any changes, gratefully taking advantage of any volunteerswho popped up their hands in steps 1. or 4..Note: please resist the temptation to wander OT, or get in slaggingmatches. I'm barely less busy than Walter at themoment, so am just going to ignore any posts (and their sub-threads) likethat, and any useful criticisms containedtherein will be wasted. Hopefully, by the time we hit 0.103 we should be in good shape. If theprocess works, we might start a trend.Cheers Matthew
Sep 10 2004
Let me add I'd like to see some standard exceptions, too. For example there should be a module called something like std.exceptions that at least ArgumentException OutOfMemoryException NotSupportedException NotImplementedException IndexOutOfBoundsException I suggest this because I have several libraries that use these exceptions (except OutOfMemory, actually) and writing my own for each library is annoying and error-prone. For example if I want to perform some argument checking on an input to a function and throw an Exception if the argument is illegal then I could write import std.exceptions; ... void foo(int must_be_positive) { if (must_be_positive <= 0) throw new ArgumentException("must_be_positive must be positive"); ... } Plus having a standard "index out of bounds" exception comes in handy with user-defined container classes. -Ben "Ben Hinkle" <bhinkle mathworks.com> wrote in message news:chsbiq$1hdf$1 digitaldaemon.com...names: class Throwable { this(char[] msg = null, Throwable cause = null) {...} Throwable cause() { getter for cause } char[] toString() {...} void print() {...} // should not allocate any memory } class Error : Throwable {...} // non-recoverable error class Exception : Throwable {...} // recoverable error The only Error subclasses should be AssertError, SwitchError. Allsubclassesof Exception should have names that end with Exception. "Matthew" <admin.hat stlsoft.dot.org> wrote in message news:chrebn$12f7$1 digitaldaemon.com...noI've persuaded big-W that the exception hierarchy refactoring can waitlonger, but to do so I've had to volunteer tocriticismmarshal the efforts. My plan is as follows: 1. Solicit *on-topic* criticisms from the newsgroup 2. Put on my code reviewer's hat, and do a detailed analysis andof the current situation. I'll do thison*before* I read any of these criticisms, so as to be unbiased in thereview. This means you've a week or so before I'llbe digesting and collating any responses from the community, so pleasetake your time to provide considered comments.3. Amalgamate these two sets of information (along with any prior poststhe subject that I can easily find in the ng)Walter.into a (hopefully) simple recommendation for necessary changes to(If it doesn't fit into three pages (+thelistings) or less, I shall consider it a failure.) 4. Release the findings, and Walter's response (if it counters any ofrecommendations), to the community forlike*on-topic* debate. 5. Implement any changes, gratefully taking advantage of any volunteerswho popped up their hands in steps 1. or 4..Note: please resist the temptation to wander OT, or get in slaggingmatches. I'm barely less busy than Walter at themoment, so am just going to ignore any posts (and their sub-threads)that, and any useful criticisms containedtherein will be wasted. Hopefully, by the time we hit 0.103 we should be in good shape. If theprocess works, we might start a trend.Cheers Matthew
Sep 10 2004
How about a static opCall in exceptions? This can be done in two ways, I think: 1: or 2: (my favourite) Just my two cents... Nick
Sep 10 2004
I think we need a good definition of what is an 'Error' and what is an 'Exception'. I would have said 'OutOfMemory' was an error... however as per Matthew's request lets not debate this here :) Ben, when you said "The only Error subclasses should be AssertError, SwitchError" did you mean? "The only Error subclasses (defined in std.exception) should be AssertError, SwitchError" or "The only Error subclasses (that should ever exist) should be AssertError, SwitchError" ? On Fri, 10 Sep 2004 10:40:50 -0400, Ben Hinkle <bhinkle mathworks.com> wrote:Let me add I'd like to see some standard exceptions, too. For example there should be a module called something like std.exceptions that at least ArgumentException OutOfMemoryException NotSupportedException NotImplementedException IndexOutOfBoundsException I suggest this because I have several libraries that use these exceptions (except OutOfMemory, actually) and writing my own for each library is annoying and error-prone. For example if I want to perform some argument checking on an input to a function and throw an Exception if the argument is illegal then I could write import std.exceptions; ... void foo(int must_be_positive) { if (must_be_positive <= 0) throw new ArgumentException("must_be_positive must be positive"); ... } Plus having a standard "index out of bounds" exception comes in handy with user-defined container classes. -Ben "Ben Hinkle" <bhinkle mathworks.com> wrote in message news:chsbiq$1hdf$1 digitaldaemon.com...-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/Java names: class Throwable { this(char[] msg = null, Throwable cause = null) {...} Throwable cause() { getter for cause } char[] toString() {...} void print() {...} // should not allocate any memory } class Error : Throwable {...} // non-recoverable error class Exception : Throwable {...} // recoverable error The only Error subclasses should be AssertError, SwitchError. Allsubclassesof Exception should have names that end with Exception. "Matthew" <admin.hat stlsoft.dot.org> wrote in message news:chrebn$12f7$1 digitaldaemon.com...noI've persuaded big-W that the exception hierarchy refactoring can waitlonger, but to do so I've had to volunteer tocriticismmarshal the efforts. My plan is as follows: 1. Solicit *on-topic* criticisms from the newsgroup 2. Put on my code reviewer's hat, and do a detailed analysis andof the current situation. I'll do thison*before* I read any of these criticisms, so as to be unbiased in thereview. This means you've a week or so before I'llbe digesting and collating any responses from the community, so pleasetake your time to provide considered comments.3. Amalgamate these two sets of information (along with any priorpoststhe subject that I can easily find in the ng)Walter.into a (hopefully) simple recommendation for necessary changes to(If it doesn't fit into three pages (+thelistings) or less, I shall consider it a failure.) 4. Release the findings, and Walter's response (if it counters any ofrecommendations), to the community forlike*on-topic* debate. 5. Implement any changes, gratefully taking advantage of anyvolunteers who popped up their hands in steps 1. or 4..Note: please resist the temptation to wander OT, or get in slaggingmatches. I'm barely less busy than Walter at themoment, so am just going to ignore any posts (and their sub-threads)that, and any useful criticisms containedtherein will be wasted. Hopefully, by the time we hit 0.103 we should be in good shape. If theprocess works, we might start a trend.Cheers Matthew
Sep 11 2004
I would have said 'OutOfMemory' was an error... however as per Matthew's request lets not debate this here :)yeah - that could be. I just thought it should be an Exception because user code should be given a chance to free up cached objects that are sitting around in object pools and such. To abort the program because someone tried to allocate a massive object seems extreme.Ben, when you said "The only Error subclasses should be AssertError, SwitchError" did you mean? "The only Error subclasses (defined in std.exception) should be AssertError, SwitchError" or "The only Error subclasses (that should ever exist) should be AssertError, SwitchError" ?I meant the first one. Users can define Errors - though I can't think of any off the top of my head.
Sep 12 2004
On Sun, 12 Sep 2004 11:57:09 -0400, Ben Hinkle <bhinkle4 juno.com> wrote:I agree. So are you also suggesting that an Error is uncatchable? This needs to be decided upon and well defined. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/I would have said 'OutOfMemory' was an error... however as per Matthew's request lets not debate this here :)yeah - that could be. I just thought it should be an Exception because user code should be given a chance to free up cached objects that are sitting around in object pools and such. To abort the program because someone tried to allocate a massive object seems extreme.
Sep 12 2004
Regan Heath wrote:On Sun, 12 Sep 2004 11:57:09 -0400, Ben Hinkle <bhinkle4 juno.com> wrote:Anything is catchable according to the language spec. The code try { ... } catch (Object e) { ... } will catch anything. The question is what should be caught when people are lazy and say try { ... } catch (Exception e) { ... } Should OutOfMemory be caught? Maybe, maybe not. What I would really like is the ability to register a delegate with the GC so that when it can't allocate any more memory it calls the delegate(s) to make a last-ditch effort to free up some memory and try the allocation again and if that fails then throw the exception. If the GC did that then I'd say go ahead and make OutOfMemory an Error because at that point there really isn't any memory left.I agree. So are you also suggesting that an Error is uncatchable?I would have said 'OutOfMemory' was an error... however as per Matthew's request lets not debate this here :)yeah - that could be. I just thought it should be an Exception because user code should be given a chance to free up cached objects that are sitting around in object pools and such. To abort the program because someone tried to allocate a massive object seems extreme.This needs to be decided upon and well defined. Regan
Sep 12 2004
On Sun, 12 Sep 2004 21:50:52 -0400, Ben Hinkle <bhinkle4 juno.com> wrote:Regan Heath wrote:Indeed. IIRC Matthew once suggested that Error should be uncatchable, I was wondering if anyone else felt that way too. My reservation against it is: What if a library is throwing an error (which should have perhaps been an exception), if you cannot catch it, and your application must not simply abort, you cannot use that library.On Sun, 12 Sep 2004 11:57:09 -0400, Ben Hinkle <bhinkle4 juno.com> wrote:Anything is catchable according to the language spec. The code try { ... } catch (Object e) { ... } will catch anything.I agree. So are you also suggesting that an Error is uncatchable?I would have said 'OutOfMemory' was an error... however as per Matthew's request lets not debate this here :)yeah - that could be. I just thought it should be an Exception because user code should be given a chance to free up cached objects that are sitting around in object pools and such. To abort the program because someone tried to allocate a massive object seems extreme.The question is what should be caught when people are lazy and say try { ... } catch (Exception e) { ... } Should OutOfMemory be caught? Maybe, maybe not.I think it depends on the application in question.What I would really like is the ability to register a delegate with the GC so that when it can't allocate any more memory it calls the delegate(s) to make a last-ditch effort to free up some memory and try the allocation again and if that fails then throw the exception. If the GC did that then I'd say go ahead and make OutOfMemory an Error because at that point there really isn't any memory left.Yes, that would be nice. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 12 2004
Regan Heath wrote:On Sun, 12 Sep 2004 21:50:52 -0400, Ben Hinkle <bhinkle4 juno.com> wrote:I think Matthew said Errors should be unrecoverable, not uncatchable. Either way, that's how I would like to classify Errors. There's no point in throwing something that's uncatchable when you could just terminate the application instead.Anything is catchable according to the language spec. The code try { ... } catch (Object e) { ... } will catch anything.Indeed. IIRC Matthew once suggested that Error should be uncatchable, I was wondering if anyone else felt that way too.My reservation against it is: What if a library is throwing an error (which should have perhaps been an exception), if you cannot catch it, and your application must not simply abort, you cannot use that library.If an Error is thrown, then the application is likely in an undefined state and can not continue anyway. Certainly not producing correct behavior anyway. I would prefer to have the application halt and have a process monitor attempt to restart the application.Agreed. Though it may still be nice to keep OutOfMemory as an exception. For example, say I'm crazy and write an application like this: Eventually the application is either going to run out of stack or heap space and will either explode or signal an OutOfMemory condition. Assuming OutOfMemory is signalled, a delegate may not be able to free up memory for another buffer allocation without some aggressively evil destruction of memory that should be left alone. However if an exception is thrown then the entire heap should be freed up purely as a side-effect of stack unwinding. In this case the application could continue to run just fine, and an Error would be overkill. SeanThe question is what should be caught when people are lazy and say try { ... } catch (Exception e) { ... } Should OutOfMemory be caught? Maybe, maybe not.I think it depends on the application in question.What I would really like is the ability to register a delegate with the GC so that when it can't allocate any more memory it calls the delegate(s) to make a last-ditch effort to free up some memory and try the allocation again and if that fails then throw the exception. If the GC did that then I'd say go ahead and make OutOfMemory an Error because at that point there really isn't any memory left.Yes, that would be nice.
Sep 12 2004
On Sun, 12 Sep 2004 22:28:35 -0700, Sean Kelly <sean f4.ca> wrote:Regan Heath wrote:Ahh yes, sorry for miss-representing you Matthew. :)On Sun, 12 Sep 2004 21:50:52 -0400, Ben Hinkle <bhinkle4 juno.com> wrote:I think Matthew said Errors should be unrecoverable, not uncatchable.Anything is catchable according to the language spec. The code try { ... } catch (Object e) { ... } will catch anything.Indeed. IIRC Matthew once suggested that Error should be uncatchable, I was wondering if anyone else felt that way too.Either way, that's how I would like to classify Errors. There's no point in throwing something that's uncatchable when you could just terminate the application instead.I agree. If you cannot catch it, there is no point in throwing it.Agreed, provided the Error really does mean it's un-recoverable. My example was trying to suggest a miss classified error, or rather one that is not un-recoverable for this particular application. So the defintion of 'Error' is 'something that is un-recoverable' or something similar, I think we need a solid definition of this.My reservation against it is: What if a library is throwing an error (which should have perhaps been an exception), if you cannot catch it, and your application must not simply abort, you cannot use that library.If an Error is thrown, then the application is likely in an undefined state and can not continue anyway. Certainly not producing correct behavior anyway. I would prefer to have the application halt and have a process monitor attempt to restart the application.True, you've convinced me. I don't think OutOfMemory is un-recoverable. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/Agreed. Though it may still be nice to keep OutOfMemory as an exception. For example, say I'm crazy and write an application like this: Eventually the application is either going to run out of stack or heap space and will either explode or signal an OutOfMemory condition. Assuming OutOfMemory is signalled, a delegate may not be able to free up memory for another buffer allocation without some aggressively evil destruction of memory that should be left alone. However if an exception is thrown then the entire heap should be freed up purely as a side-effect of stack unwinding. In this case the application could continue to run just fine, and an Error would be overkill.The question is what should be caught when people are lazy and say try { ... } catch (Exception e) { ... } Should OutOfMemory be caught? Maybe, maybe not.I think it depends on the application in question.What I would really like is the ability to register a delegate with the GC so that when it can't allocate any more memory it calls the delegate(s) to make a last-ditch effort to free up some memory and try the allocation again and if that fails then throw the exception. If the GC did that then I'd say go ahead and make OutOfMemory an Error because at that point there really isn't any memory left.Yes, that would be nice.
Sep 13 2004
In article <ci2udp$gqr$1 digitaldaemon.com>, Ben Hinkle says...The question is what should be caught when people are lazy and say try { ... } catch (Exception e) { ... } Should OutOfMemory be caught? Maybe, maybe not.I don't think the above is lazy. In fact, I think that's the way it should be done (print out the error message and continue running.) An out of memory is usually not recoverable, so it should be an Error I think. But what is and is not recoverable can vary from program to program. If you want to continue on OutOfMemory, just catch it explicitly.What I would really like is the ability to register a delegate with the GC so that when it can't allocate any more memory it calls the delegate(s) to make a last-ditch effort to free up some memory and try the allocation again and if that fails then throw the exception. If the GC did that then I'd say go ahead and make OutOfMemory an Error because at that point there really isn't any memory left.GC callback functions is a good idea, IMHO. A callback for before/after garbage collection runs, and maybe a "this object/memory area is about to be destructed/freed" callback. Nick
Sep 13 2004
Nick wrote:In article <ci2udp$gqr$1 digitaldaemon.com>, Ben Hinkle says...Catching all exceptions is what I meant by lazy. Usually one should catch the smallest collection of exceptions as possible. Eg: catch StreamException or ThreadException etc. Catching all exceptions is a very wide net.The question is what should be caught when people are lazy and say try { ... } catch (Exception e) { ... } Should OutOfMemory be caught? Maybe, maybe not.I don't think the above is lazy. In fact, I think that's the way it should be done (print out the error message and continue running.) An out of memory is usually not recoverable, so it should be an Error I think. But what is and is not recoverable can vary from program to program. If you want to continue on OutOfMemory, just catch it explicitly.I'm curious, what use-case do you have in mind for a per-object callback? I could imagine a post-destructor callback so that AJ (for instance) could install a memory-wiper routine.What I would really like is the ability to register a delegate with the GC so that when it can't allocate any more memory it calls the delegate(s) to make a last-ditch effort to free up some memory and try the allocation again and if that fails then throw the exception. If the GC did that then I'd say go ahead and make OutOfMemory an Error because at that point there really isn't any memory left.GC callback functions is a good idea, IMHO. A callback for before/after garbage collection runs, and maybe a "this object/memory area is about to be destructed/freed" callback.Nick
Sep 13 2004
In article <ci5a1k$1948$1 digitaldaemon.com>, Ben Hinkle says...Nick wrote:For many cases I agree with you, but in some cases you will want to catch all exceptions at one single point, without necessarily knowing what kind of exceptions they are. For example if you are calling external library functions.I don't think the above is lazy. In fact, I think that's the way it should be done (print out the error message and continue running.) An out of memory is usually not recoverable, so it should be an Error I think. But what is and is not recoverable can vary from program to program. If you want to continue on OutOfMemory, just catch it explicitly.Catching all exceptions is what I meant by lazy. Usually one should catch the smallest collection of exceptions as possible. Eg: catch StreamException or ThreadException etc. Catching all exceptions is a very wide net.I had an example in mind, but it isn't a very good example. I thought it could be used instead of finalizers when you have objects which depend on each other. For example: So now both objects are guaranteed to be alive when BufferedFile.flush() is called. But since you are not supposed to rely on object destruction, you are not guaranteed that callback() gets called at all. Therefore it is not a very usable example. NickGC callback functions is a good idea, IMHO. A callback for before/after garbage collection runs, and maybe a "this object/memory area is about to be destructed/freed" callback.I'm curious, what use-case do you have in mind for a per-object callback? I could imagine a post-destructor callback so that AJ (for instance) could install a memory-wiper routine.
Sep 14 2004
Ben Hinkle wrote:They will probably mostly be platform-dependent. Something that results in memory corruption would be an Error, possibly some sort of halt instruction, etc. SeanBen, when you said "The only Error subclasses should be AssertError, SwitchError" did you mean? "The only Error subclasses (defined in std.exception) should be AssertError, SwitchError" or "The only Error subclasses (that should ever exist) should be AssertError, SwitchError" ?I meant the first one. Users can define Errors - though I can't think of any off the top of my head.
Sep 12 2004
"Ben Hinkle" wrote:I suggest this because I have several libraries that use these exceptions (except OutOfMemory, actually) and writing my own for each library is annoying and error-prone.I don't understand why you would have to write your "own for each library". Why can't you simply write a single exception library that exposes these exceptions and have each of your other libraries use this exception library? Unless I misunderstand, this is exactly the purpose you are proposing that the phobos library's exception implementation would serve. Regards, Garett
Sep 12 2004
Garett Bass wrote:"Ben Hinkle" wrote:true - I can share my own exceptions between the libraries that I write though it means the exceptions are not in the same package as the library and I have to make sure all my libraries have the same version of the exceptions. I like to keep my libraries independent so that installing one doesn't step on another. Mostly I was thinking of exceptions that make sense across libraries written by possibly different people.I suggest this because I have several libraries that use these exceptions (except OutOfMemory, actually) and writing my own for each library is annoying and error-prone.I don't understand why you would have to write your "own for each library". Why can't you simply write a single exception library that exposes these exceptions and have each of your other libraries use this exception library? Unless I misunderstand, this is exactly the purpose you are proposing that the phobos library's exception implementation would serve. Regards, Garett
Sep 12 2004
Semi-related. I just posted a bunch of exception issues to the bugs forum. Link is here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D.bugs/1821 I'll write more about exceptions once I've had some time to think about the issue. Sean
Sep 10 2004
"Matthew" <admin.hat stlsoft.dot.org> wrote in news:chrebn$12f7$1 digitaldaemon.com:I've persuaded big-W that the exception hierarchy refactoring can wait no longer, but to do so I've had to volunteer to marshal the efforts. My plan is as follows: 1. Solicit *on-topic* criticisms from the newsgroup 2. Put on my code reviewer's hat, and do a detailed analysis and criticism of the current situation. I'll do this *before* I read any of these criticisms, so as to be unbiased in the review. This means you've a week or so before I'll be digesting and collating any responses from the community, so please take your time to provide considered comments. [snip]I propose this (over-engineered) java-like exception hierarchy: Object | |Throwable | |Error | | | |TooManyThreadsError | |OutOfMemoryError | |AssertionError | | | |ArrayBoundsError | |AssertError | |SwitchError | |Exception | |CheckedException | | | |FileException | ... |UncheckedException | |FormatException ... What's a Throwable? ------------------- By convention all exceptions derive from Throwable. It's still possible to throw any object, though. This way you can create your own exception hierarchy if needed. // Throwable contains an exception message and keeps track of // nested exceptions. class Throwable { private char[] msg; private Throwable next; this(char[] msg="", Throwable next=null); // returns a (user) message that describes the cause of the exception; // returns an empty string, if no message is available char[] getMessage(); // returns the nested exception or null if there is none Throwable getNext(); // returns a (somewhat cryptic) string char[] toString() { char[]rs=this.classinfo.name~": "~this.getMessage(); if (next) rs~="\n"~next.toString(); return rs; } } What are Errors? ---------------- Errors are thrown for exceptions that *might* require drastic means to recover from; like terminating the process or the thread, switching over to a backup system, rebooting computer (for Win9x), etc. When should an exception be derived from Error? 1.) when there are no guarantees when the exception occurs: At minimum a) there must be no resource leaks b) the destructor of an instance must be safely callable if an exception is thrown. If these minimum guarantees cannot be met, the exception is an Error. Furthermore, classes often have stronger guarantees, e.g. instance remains in a valid state if an exception is thrown. For cases that don't permit these stronger guarantees, an Error should be thrown instead of an Exception. 2.) when the exception might not be thrown in release builds: Although these exceptions could be safely catched in debug builds, the conditions that caused them would likely cause havoc for release builds. What about out of memory errors? ------------------------------- I argue that out of memory conditions are Errors, since in the days of virtual memory, most programmers assume that there is always enough memory available, unless a very large amount of memory is requested. Consequently, the vast majority of libraries don't come with exception guarantees when memory is running low. For the same reasons std.thread.Thread.start() should throw a TooManyThreadsError exception instead of a TooManyThreadsException. Why AssertionError? ------------------- Switch errors, array index errors and failed assert statements, mean all but one thing: A bug was revealed. // AssertionError doesn't provide an exception message, but stores // the location where the exception was thrown. class AssertionError : Error { private uint linnum; private char[] filename; this(char[] filename, uint linnum) { super(); this.filename=filename this.linnum=linnum } uint getLinenum(); char[] getFilename(); char[] toString() { return this.classinfo.name~" exception source: " ~filename~" ("~toString(linnum)~")"; } } Speaking of AssertionErrors, it would be useful if DMD offered an option "-spoiledprogrammer" for spoiled programmers. If this option is enabled, AssertionErrors would additionally contain * the function name for all AssertionErrors * the expression of an assert statement * the index that causes an ArrayBoundsError * the actual value that causes a SwitchError What are Exceptions? -------------------- Exceptions are thrown for conditions that leave the process in a defined state. Since Exceptions are thrown for predictable situations, it is usually easy to safely recover from the exceptional situation. We don't need no stinking checked exceptions! --------------------------------------------- Agreed, no checked exceptions. While the constant nagging of the Java compiler about undeclared checked exceptions isn't particularly useful, the concept behind them is. So, borrow the concept from Java, but not it's implementation. By convention, CheckedExceptions are thrown for errors that the programmer should carefully think about. Exceptions that derive from CheckedException * cannot be avoided by the programmer. For instance, opening a file, might fail: Even if you ensure that the file exists before opening the file, the file might have been deleted by the time it is actually opened! * might occur during the intended operation of a programm; they do not necessarily indicate bugs. * should be documented for all functions in the call hierarchy that might throw them When to use UncheckedExceptions ------------------------------- UncheckedExceptions are thrown for errors that don't require the programmer's attention, since these errors *usually* never happen. UncheckedExceptions usually indicate that a function is used in the wrong way by the caller. UncheckedExceptions * can be avoided for most use-cases. E.g. std.format.doFormat(...) throws a FormatException if the passed arguments do not match the format pattern. The exception can be avoided by passing a correct format pattern string. * usually indicate bugs, but not always * might not be documented in the function contract. Of course, it's good practice to do so, especially for functions that directly throw UncheckedExceptions. Errors vs. UncheckedExceptions ------------------------------ UncheckedExceptions * are part of the function's contract. As long as the contract isn't changed, the caller can rely on UncheckedExceptions beeing thrown. * leave the process in a defined state (exception guarantees like: no resource leaks, object instances remain valid, etc. permit that the the process can safely recover from the exception ) Errors * are not necessarily part of the function contract: Checks that throw Errors, might be absent in release builds or future versions of the function. * might leave the programm in an undefined state; should the Error be ignored, unpredictable follow-up errors might occur. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I also like Ben's idea to include a bunch of generic exception classes in the standard library. This would be particularly handy for quick and dirty programming. Farmer. After writing this post, I recognized that the base class Throwable is a bit pointless for runtime generated Errors. Since these Errors neither have a user message nor a nested exception. So here's another, less java-like exception hierarchy. The presented guidelines for using Exceptions/Errors remain valid for this hierarchy. Object | |TooManyThreads |OutOfMemory |AssertionError | |ArrayBoundsError | |AssertError | |SwitchError | |Exception | |CheckedException // should be catched | | | |FileException | ... |UncheckedException // safe to catch | | | |FormatException | ... | |UnrecoverableError // unsafe to catch | |NullArgumentError ...
Sep 15 2004
In article <Xns8FB0B405185D2itsFarmer 63.105.9.61>, Farmer says...I propose this (over-engineered) java-like exception hierarchy: Object | |Throwable | |Error | | | |TooManyThreadsError | |OutOfMemoryError | |AssertionError | | | |ArrayBoundsError | |AssertError | |SwitchError | |Exception | |CheckedException | | | |FileException | ... |UncheckedException | |FormatException .....What are Errors? ---------------- Errors are thrown for exceptions that *might* require drastic means to recover from; like terminating the process or the thread, switching over to a backup system, rebooting computer (for Win9x), etc. When should an exception be derived from Error? 1.) when there are no guarantees when the exception occurs: At minimum a) there must be no resource leaks b) the destructor of an instance must be safely callable if an exception is thrown. If these minimum guarantees cannot be met, the exception is an Error.In this case, I would argue that TooManyThreadsError and OutOfMemoryError should be derived from Exception, since they both meet these requirements.Furthermore, classes often have stronger guarantees, e.g. instance remains in a valid state if an exception is thrown. For cases that don't permit these stronger guarantees, an Error should be thrown instead of an Exception.Could you go into this a bit more? Are you just saying that, basically, if a class invariant is violated then an Error should be thrown? If so, I *think* I agree but I'll have to think about it.2.) when the exception might not be thrown in release builds: Although these exceptions could be safely catched in debug builds, the conditions that caused them would likely cause havoc for release builds.I'm having trouble thinking of an exception that might be recoverable in a debug build but not in a release build. Or do you mean only that they could be thrown and caught safely? And if this is the case, then I would argue that they shouldn't be Errors *or* Exceptions, but rather that the application should terminate with a core dump.What about out of memory errors? ------------------------------- I argue that out of memory conditions are Errors, since in the days of virtual memory, most programmers assume that there is always enough memory available, unless a very large amount of memory is requested.For a specific class of applications, yes. But what about systems programming, embedded systems, etc? I might argue that such applications should be designed such that an out of memory condition should never occur, but they certainly aren't designed as if memory were unlimited. I think OutOfMemory should be an Exception because it's a situation that some applications may want to recover from, not because that is expected of all applications.Consequently, the vast majority of libraries don't come with exception guarantees when memory is running low.I would argue that any library that is not exception safe is incorrect. It shouldn't matter what kind of exception it is. So I assume that any library that doesn't document otherwise at least provides the basic guarantee.For the same reasons std.thread.Thread.start() should throw a TooManyThreadsError exception instead of a TooManyThreadsException.For the same reason, I think this should be an exception :) The user should be able to choose whether this constitutes an application failure. As for checked vs. unchecked exceptions, I'm not sure I understand the difference. Are you saying that checked exceptions should be handled explicitly while unchecked exceptions can be caught via the Exception base class, the error reported, and that's it? Obviously, all exceptions must be handled somewhere or the application will terminate. Sean
Sep 15 2004
First, to clear up one misunderstanding: Unlike Matthew, I don't imply any mandatory way to recover from any kind of errors. It should be possible to freely choose how to deal with errors to the maximum extend that the given hardware permits. Sean Kelly <sean f4.ca> wrote in news:cia1l4$1jfe$1 digitaldaemon.com:In article <Xns8FB0B405185D2itsFarmer 63.105.9.61>, Farmer says...If I think more about it, destructors of instances must be callable at *any rate*. Otherwise use of auto classes (RAII) would become an unsafe practice.What are Errors? ---------------- Errors are thrown for exceptions that *might* require drastic means to recover from; like terminating the process or the thread, switching over to a backup system, rebooting computer (for Win9x), etc. When should an exception be derived from Error? 1.) when there are no guarantees when the exception occurs: At minimum a) there must be no resource leaks b) the destructor of an instance must be safely callable if an exception is thrown. If these minimum guarantees cannot be met, the exception is an Error.In this case, I would argue that TooManyThreadsError and OutOfMemoryError should be derived from Exception, since they both meet these requirements.Yes. But this isn't restricted to class invariants. For example a function that adds an element to a container guarantees transactional behaviour in case of Exceptions. If for some reasons the function cannot ensure this guarantee, it could throw an Error as a last resort. E.g. A programmer puts an assert statement between statements that must never cause an exception. And now the assert statement actually fails.Furthermore, classes often have stronger guarantees, e.g. instance remains in a valid state if an exception is thrown. For cases that don't permit these stronger guarantees, an Error should be thrown instead of an Exception.Could you go into this a bit more? Are you just saying that, basically, if a class invariant is violated then an Error should be thrown? If so, I *think* I agree but I'll have to think about it.For example: void foo(Object o) { debug { if (o is null) throw new NullArgumentException(); } o.toString(); } main() { foo(null); } For debug builds an Exception is thrown that is definitely recoverable. But in release builds a seg fault is likely. What I meant is, that you should throw an NullArgumentError for such cases.2.) when the exception might not be thrown in release builds: Although these exceptions could be safely catched in debug builds, the conditions that caused them would likely cause havoc for release builds.I'm having trouble thinking of an exception that might be recoverable in a debug build but not in a release build. Or do you mean only that they could be thrown and caught safely?And if this is the case, then I would argue that they shouldn't be Errors *or* Exceptions, but rather that the application should terminate with a core dump.Terminating the application might be the right thing for most cases, but it shouldn't be the only option.It certainly depends on D's target audience: Is the target audience limited to pedantic programmers that do life critical applications? Or does it include programmers that rely on GCs to release resources? If you're doing systems programming and you designed your programm really correctly and use libraries that are equally well designed. Nothing shall stop you from catching an OutOfMemoryError and just continue.What about out of memory errors? ------------------------------- I argue that out of memory conditions are Errors, since in the days of virtual memory, most programmers assume that there is always enough memory available, unless a very large amount of memory is requested.For a specific class of applications, yes. But what about systems programming, embedded systems, etc? I might argue that such applications should be designed such that an out of memory condition should never occur, but they certainly aren't designed as if memory were unlimited. I think OutOfMemory should be an Exception because it's a situation that some applications may want to recover from, not because that is expected of all applications.I agree, but still argue that we programmers are suppossed to write *correct* programms (or at least working programms), based on *incorrect* libraries. Actually, the whole point of the exception hierarchy is, to make it easier to accomplish this.Consequently, the vast majority of libraries don't come with exception guarantees when memory is running low.I would argue that any library that is not exception safe is incorrect. It shouldn't matter what kind of exception it is. So I assume that any library that doesn't document otherwise at least provides the basic guarantee.That's *one* option: provide a user setting that specifies what happens for a given kind of application failure.For the same reasons std.thread.Thread.start() should throw a TooManyThreadsError exception instead of a TooManyThreadsException.For the same reason, I think this should be an exception :) The user should be able to choose whether this constitutes an application failure.As for checked vs. unchecked exceptions, I'm not sure I understand the difference. Are you saying that checked exceptions should be handled explicitly while unchecked exceptions can be caught via the Exception base class, the error reported, and that's it? Obviously, all exceptions must be handled somewhere or the application will terminate.No. While there might be a certain trend how checked vs. unchecked exceptions are typically handled. It is not the definite decision criteria. It's more important what the cause for an exception is: CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. UncheckedExceptions: cause is internal: Caller can avoid them, consequently a programmer should usually focus on how to *prevent* the exception. Whether an exception is checked or unchecked depends on the anticipated use of an API. For example the function int atoi(char[] number) converts a string to an integer. If the passed string isn't a valid number should a CheckedException or an UncheckedException be thrown? It depends on the function's intended purpose: If its purpose is to convert a number then it should throw an UncheckedException. But if its purpose is to "check if a string is a number and convert it" then the function should throw a CheckedException. Farmer.
Sep 15 2004
In article <Xns8FB1A4F92693itsFarmer 63.105.9.61>, Farmer says...First, to clear up one misunderstanding: Unlike Matthew, I don't imply any mandatory way to recover from any kind of errors. It should be possible to freely choose how to deal with errors to the maximum extend that the given hardware permits.Ah, thanks for clearing this up. That distinction between Exceptions and Errors is one I'd been assuming.Ah okay. Then I do agree :)Could you go into this a bit more? Are you just saying that, basically, if a class invariant is violated then an Error should be thrown? If so, I *think* I agree but I'll have to think about it.Yes. But this isn't restricted to class invariants. For example a function that adds an element to a container guarantees transactional behaviour in case of Exceptions. If for some reasons the function cannot ensure this guarantee, it could throw an Error as a last resort. E.g. A programmer puts an assert statement between statements that must never cause an exception. And now the assert statement actually fails.Gotcha. So it's an Error to make the programmer more likely to notice and fix the problem during development. In practice I would probably use asserts for this, which would classify them as errors anyway.I'm having trouble thinking of an exception that might be recoverable in a debug build but not in a release build. Or do you mean only that they could be thrown and caught safely?For example: void foo(Object o) { debug { if (o is null) throw new NullArgumentException(); } o.toString(); } main() { foo(null); } For debug builds an Exception is thrown that is definitely recoverable. But in release builds a seg fault is likely. What I meant is, that you should throw an NullArgumentError for such cases.True enough. I suppose even memory corruption is recoverable in some scenarios (segmented memory) so perhaps it's inadvisable to have the language mandate behavior in this regard. Though I suppose we're still stuck with termination if 2+ exceptions are thrown simultaneously.And if this is the case, then I would argue that they shouldn't be Errors *or* Exceptions, but rather that the application should terminate with a core dump.Terminating the application might be the right thing for most cases, but it shouldn't be the only option.This was due to my (incorrect) assumption that Errors necessitated program termination.That's *one* option: provide a user setting that specifies what happens for a given kind of application failure.For the same reasons std.thread.Thread.start() should throw a TooManyThreadsError exception instead of a TooManyThreadsException.For the same reason, I think this should be an exception :) The user should be able to choose whether this constitutes an application failure.Ah, that makes perfect sense. In that case, I think this is a valuable distinction to make. Good work! SeanAs for checked vs. unchecked exceptions, I'm not sure I understand the difference. Are you saying that checked exceptions should be handled explicitly while unchecked exceptions can be caught via the Exception base class, the error reported, and that's it? Obviously, all exceptions must be handled somewhere or the application will terminate.No. While there might be a certain trend how checked vs. unchecked exceptions are typically handled. It is not the definite decision criteria. It's more important what the cause for an exception is: CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. UncheckedExceptions: cause is internal: Caller can avoid them, consequently a programmer should usually focus on how to *prevent* the exception.
Sep 15 2004
Sean Kelly <sean f4.ca> wrote in news:ciajpr$1s3t$1 digitaldaemon.com:In article <Xns8FB1A4F92693itsFarmer 63.105.9.61>, Farmer says...[snip]Yes, it's an Error, but making errors sometimes is a good thing. Asserts have one inconvenience: You can't tell at a glance what caused them. And who is responsible for the failure? The callee or the caller? That's why a programmer might prefer to throw an Error that contains additional information. But if an AssertError included: * the assertion expression * the location of the assertion: in-contract, out-contract, class- invariant or function body * stacktrace then in most cases, you could tell what causes an assertion, without using a debugger (or even looking at your code if you know it well).Gotcha. So it's an Error to make the programmer more likely to notice and fix the problem during development. In practice I would probably use asserts for this, which would classify them as errors anyway.I'm having trouble thinking of an exception that might be recoverable in a debug build but not in a release build. Or do you mean only that they could be thrown and caught safely?For example: void foo(Object o) { debug { if (o is null) throw new NullArgumentException(); } o.toString(); } main() { foo(null); } For debug builds an Exception is thrown that is definitely recoverable. But in release builds a seg fault is likely. What I meant is, that you should throw an NullArgumentError for such cases.I'm not sure how D is supposed to handle this situation. I tried to simply throw an exception within a destructor (just 1 exception was active) but the programmed crashed with an exception error e0440001H. I shall take a look at the bug forum. I don't know if it's technically possible, but how about throwing a SimultanousExceptionError that contains both exceptions? Regards, Farmer.True enough. I suppose even memory corruption is recoverable in some scenarios (segmented memory) so perhaps it's inadvisable to have the language mandate behavior in this regard. Though I suppose we're still stuck with termination if 2+ exceptions are thrown simultaneously.And if this is the case, then I would argue that they shouldn't be Errors *or* Exceptions, but rather that the application should terminate with a core dump.Terminating the application might be the right thing for most cases, but it shouldn't be the only option.
Sep 16 2004
In article <Xns8FB1F10AFEB2AitsFarmer 63.105.9.61>, Farmer says...Sean Kelly <sean f4.ca> wrote in news:ciajpr$1s3t$1 digitaldaemon.com:Combined with DBC, this should hopefully be pretty obvious, as I'd expect most asserts to be inside in/out blocks.Gotcha. So it's an Error to make the programmer more likely to notice and fix the problem during development. In practice I would probably use asserts for this, which would classify them as errors anyway.Yes, it's an Error, but making errors sometimes is a good thing. Asserts have one inconvenience: You can't tell at a glance what caused them. And who is responsible for the failure? The callee or the caller?That's why a programmer might prefer to throw an Error that contains additional information. But if an AssertError included: * the assertion expression * the location of the assertion: in-contract, out-contract, class- invariant or function body * stacktrace then in most cases, you could tell what causes an assertion, without using a debugger (or even looking at your code if you know it well).Agreed. It would definately be nice if AssertError were more robust.I posted a bunch of bugs re: exceptions earlier this week. Basically, exceptions currently mess with stack unwinding such that auto classes aren't destructed when they should be. This makes testing the double-exception problem between difficult and impossible.True enough. I suppose even memory corruption is recoverable in some scenarios (segmented memory) so perhaps it's inadvisable to have the language mandate behavior in this regard. Though I suppose we're still stuck with termination if 2+ exceptions are thrown simultaneously.I'm not sure how D is supposed to handle this situation. I tried to simply throw an exception within a destructor (just 1 exception was active) but the programmed crashed with an exception error e0440001H. I shall take a look at the bug forum.I don't know if it's technically possible, but how about throwing a SimultanousExceptionError that contains both exceptions?Good question. I think this is possible but perhaps it's technically difficult to implement. I'll have to do some digging and see if I can find the reasoning behind current C++ exception behavior (or perhaps Walter knows?). Sean
Sep 16 2004
After writing this post, I recognized that the base class Throwable is a bit pointless for runtime generated Errors. Since these Errors neitherhave auser message nor a nested exception. So here's another, less java-like exception hierarchy. The presented guidelines for using Exceptions/Errors remain valid for this hierarchy. Object | |TooManyThreads |OutOfMemory |AssertionError | |ArrayBoundsError | |AssertError | |SwitchError | |Exception | |CheckedException // should be catched | | | |FileException | ... |UncheckedException // safe to catch | | | |FormatException | ... | |UnrecoverableError // unsafe to catch | |NullArgumentError ...Very nice post! You've convinced me of the general ideas. Some comments, though. It seems wierd to have Error at the top level and under UnrecoverableError. Also I'd like to toss around some more names (Checked and Unchecked don't mean too much to me). Finally I'd like ArrayBoundsError to subclass the more general (IllegalIndexException) and made into a MidSeverityException. Any class or container that wants to overload opIndex and is passed a bogus index can throw IllegalIndexException. Exception (has optional msg and cause. The message can contain the module and/or fcn ) | |LowSeverityException: sh*t happens | | | | FileException | | ArithmeticException | | |OverflowException | ... |MidSeverityException: most like a coding error to be tracked during debugging | | | | FormatException (maybe? I don't know what this is) | | IllegalIndexException: throw this when opIndex/Assign gets an illegal index | | ArrayBoundsException | | ArgumentException: throw this when someone passes you a bad input | | NotImplementedException: throw in a stub function that isn't done yet | | NotSupportedException: same as Java's - throw when something isn't supported. | ... |HighSeverityException: dangerous to continue program | | | | TooManyThreadsError | | OutOfMemoryError | | AssertError | ... To illustrate how to use the classification, let's take FormatException. Right now FormatException (actually it's currently called FormatError) is thrown in many contexts in std.format with a message that says what went wrong. So a bad input is FormatError("too few inputs") and int overflow is FormatError("int overflow"). I think rather than doing that format should throw ArgumentException("std.format: too few inputs") and OverflowException("std.format integer format overflow"). I'm a bit up in the air about putting the module or function in the message but as long as it is standardized it would be easy to trim that info out if one wanted to show the error message to a user. If we could get the stack trace out of an exception it would be much better, but getting the stack is non-trivial. -Ben
Sep 15 2004
"Ben Hinkle" <bhinkle mathworks.com> wrote in news:cia7sd$1n6u$1 digitaldaemon.com:I felt exactly the same way. And then I thought that the hierarchy is weird and asymmetrical: Could this be the D way? Here's the hierarchy again, with two changes (TooManyThreadsError was in the wrong place and everything ends with "Error" now): Object | |OutOfMemoryError |AssertionError | |ArrayBoundsError | |AssertError | |SwitchError | |Error |CheckedError // should be catched | |FileError | ... | |UncheckedError // safe to catch | |FormatError | ... | |UnrecoverableError // unsafe to catch |TooManyThreadsError ... I don't think, that it is too weird, as the only exceptions that are at the top level are truely special: They all belong to D's minimal RTL. These exceptions are directly mentioned in the D spec. For ArrayBoundsError, AssertError and SwitchError the constructor is even private, so only the compiler can create them. Also, this design has the advantage that it avoids any implication whether OutOfMemoryErrors and contract-violations are unrecoverable or not. Especially the opinions about OutOfMemoryError/Exception are quite opposite. except for OutOfMemoryError which had better been classified as an Exception) [From a purily philosophical point I even agree: OutOfMemoryError should be a checked exception!]After writing this post, I recognized that the base class Throwable is a bit pointless for runtime generated Errors. Since these Errors neitherhave auser message nor a nested exception. So here's another, less java-like exception hierarchy. The presented guidelines for using Exceptions/Errors remain valid for this hierarchy. Object | |TooManyThreads |OutOfMemory |AssertionError | |ArrayBoundsError | |AssertError | |SwitchError | |Exception | |CheckedException // should be catched | | | |FileException | ... |UncheckedException // safe to catch | | | |FormatException | ... | |UnrecoverableError // unsafe to catch | |NullArgumentError ...Very nice post! You've convinced me of the general ideas. Some comments, though. It seems wierd to have Error at the top level and under UnrecoverableError.Also I'd like to toss around some more names (Checked and Unchecked don't mean too much to me).They don't mean anything to me, either. I thought about other names, but always came up with names that I feel are too specific and provoke wrong ad- hoc decisions on the part of the programmer. As an mnemonic aid I think of "Checked/Unchecked" as "I should check the exception" and "I should leave it unchecked".Finally I'd like ArrayBoundsError to subclass the more general (IllegalIndexException) and made into a MidSeverityException. Any class or container that wants to overload opIndex and is passed a bogus index can throw IllegalIndexException.I disagree, since Errors vs. Exception cannot be mixed. If you wanted to throw an IllegalIndexError, then there's the problem that ArrayBoundsError already inherits from AssertionError. The other way round doesn't work too well either, since in general it is not possible to create an IllegalIndexException that contains a sensible filename linenumber context.Exception (has optional msg and cause. The message can contain the module and/or fcn ) | |LowSeverityException: sh*t happens | | | | FileException | | ArithmeticException | | |OverflowException | ... |MidSeverityException: most like a coding error to be tracked during debugging | | | | FormatException (maybe? I don't know what this is) | | IllegalIndexException: throw this when opIndex/Assign gets an | | illegal index | | ArrayBoundsException | | ArgumentException: throw this when someone passes you a bad input | | NotImplementedException: throw in a stub function that isn't done | | yet NotSupportedException: same as Java's - throw when something | | isn't supported. | ... |HighSeverityException: dangerous to continue program | | | | TooManyThreadsError | | OutOfMemoryError | | AssertError | ... To illustrate how to use the classification, let's take FormatException. Right now FormatException (actually it's currently called FormatError) is thrown in many contexts in std.format with a message that says what went wrong. So a bad input is FormatError("too few inputs") and int overflow is FormatError("int overflow"). I think rather than doing that format should throw ArgumentException("std.format: too few inputs") and OverflowException("std.format integer format overflow").I tend to agree about the ArgumentException, but I would prefer a MidSeverityException for all kinds of conversion errors, here. Initially I thought, that the more general exceptions, should be available as Low-, Mid- and High- Severity exceptions. The problem is that one would either have to make up 3 different names for one exception or have 3 classes that have the same name, but are in different modules. So, it seems this doesn't work so well with generic exceptions :-( So, It doesn't work! My conclusion is that the exception could be laid out in (at least) two ways: either * build up a deep class hierarchy in a "natural and object-oriented" way or * build up a rather shallow hierarchy around the notion of CheckedError, UncheckErrors and UnrecoverableErrors as virtually the only decision criteria Also we could simply forget about un/recoverable, un/checked and severities levels and just go with a simpler hierarchy like. Object | |OutOfMemoryError |AssertionError | |ArrayBoundsError | |AssertError | |SwitchError | |Error |PhobosError |... Probably, add a standard exception UnrecoverableError, if really needed.I'm a bit up in the air about putting the module or function in the message but as long as it is standardized it would be easy to trim that info out if one wanted to show the error message to a user. IfThat's a good idea. A standard way to include the code source of an exception, that is really needed: Why does doFormat() throw an FormatException instead of an ArgumentException, after all? I bet it is simply to know that the exception was caused by doFormat() or writef() and not by one of the zillons of other functions that all throw ArgumentException. But better don't put it into the exception message. Just store it in the separate property "source" and let Error.toString() include it. I'd like to have the exception message understandable for a technical-savy user, that knows nothing about programming. Things, that have only meaning to programmers should only be included by toString(). Farmer.
Sep 16 2004
Farmer wrote:Here's the hierarchy again, with two changes (TooManyThreadsError was in the wrong place and everything ends with "Error" now): Object | |OutOfMemoryError |AssertionError | |ArrayBoundsError | |AssertError | |SwitchError | |Error |CheckedError // should be catched | |FileError | ... | |UncheckedError // safe to catch | |FormatError | ... | |UnrecoverableError // unsafe to catch |TooManyThreadsError ... I don't think, that it is too weird, as the only exceptions that are at the top level are truely special: They all belong to D's minimal RTL. These exceptions are directly mentioned in the D spec. For ArrayBoundsError, AssertError and SwitchError the constructor is even private, so only the compiler can create them. Also, this design has the advantage that it avoids any implication whether OutOfMemoryErrors and contract-violations are unrecoverable or not.I like having the system-generated exceptions at the top-level rather than derived from Error. Doing such allows them to be caught but it has to be done explicitly. This prevents unintentional recovery from an out of memory condition by catching Error. I also like the basic idea of checked and unchecked errors, but I'm still not sure I like building the error heirarchy around them.So, It doesn't work! My conclusion is that the exception could be laid out in (at least) two ways: either * build up a deep class hierarchy in a "natural and object-oriented" way or * build up a rather shallow hierarchy around the notion of CheckedError, UncheckErrors and UnrecoverableErrors as virtually the only decision criteria Also we could simply forget about un/recoverable, un/checked and severities levels and just go with a simpler hierarchy like. Object | |OutOfMemoryError |AssertionError | |ArrayBoundsError | |AssertError | |SwitchError | |Error |PhobosError |... Probably, add a standard exception UnrecoverableError, if really needed.I'm a bit more inclined to go this route, though I can't say why exactly. Maybe it's just my pragmatic nature assuming that programmers won't inherit from the proper exception with the other inheritance design. Sean
Sep 19 2004
Farmer <itsFarmer. freenet.de> wrote in news:Xns8FB1F10BEFD73itsFarmer 63.105.9.61:"Ben Hinkle" <bhinkle mathworks.com> wrote in news:cia7sd$1n6u$1 digitaldaemon.com:Just some alternative names for "checked/unchecked", that I made up myself or came across in articles, forums or wiki pages. unchecked exception: -------------------- ProgrammingError UnexpectedError UnpredictableError UnrecoverableError AvoidableError LogicalError checked exception: ------------------ GeneralError ExternalError ExpectedError PredictableError RecoverableError UnavoidableError EnvironmentError EnvironmentalError My favorites are ProgrammingError and EnvironmentError or GeneralError.Also I'd like to toss around some more names (Checked and Unchecked don't mean too much to me).They don't mean anything to me, either. I thought about other names, but always came up with names that I feel are too specific and provoke wrong ad- hoc decisions on the part of the programmer. As an mnemonic aid I think of "Checked/Unchecked" as "I should check the exception" and "I should leave it unchecked".
Sep 20 2004
On Mon, 20 Sep 2004 15:13:17 +0000 (UTC), Farmer <itsFarmer. freenet.de> wrote:Farmer <itsFarmer. freenet.de> wrote in news:Xns8FB1F10BEFD73itsFarmer 63.105.9.61:Going by your previous descriptions.."Ben Hinkle" <bhinkle mathworks.com> wrote in news:cia7sd$1n6u$1 digitaldaemon.com:Just some alternative names for "checked/unchecked", that I made up myself or came across in articles, forums or wiki pages. unchecked exception: -------------------- ProgrammingError UnexpectedError UnpredictableError UnrecoverableError AvoidableError LogicalError checked exception: ------------------ GeneralError ExternalError ExpectedError PredictableError RecoverableError UnavoidableError EnvironmentError EnvironmentalError My favorites are ProgrammingError and EnvironmentError or GeneralError.Also I'd like to toss around some more names (Checked and Unchecked don't mean too much to me).They don't mean anything to me, either. I thought about other names, but always came up with names that I feel are too specific and provoke wrong ad- hoc decisions on the part of the programmer. As an mnemonic aid I think of "Checked/Unchecked" as "I should check the exception" and "I should leave it unchecked".CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception.this implies to me the problem is (perhaps) unique to this execution of the program, in other words it occurs only during runtime, as such I prefer 'RuntimeError'.UncheckedExceptions: cause is internal: Caller can avoid them, consequently a programmer should usually focus on how to *prevent* the exception.this implies to me the problem is in the code, in other words every execution will have this problem, as such I prefer 'ProgramError' or 'DebugError'. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 20 2004
Regan Heath <regan netwin.co.nz> wrote in news:opsem9tqo15a2sq9 digitalmars.com: [snip]Going by your previous descriptions..I wouldn't use the term 'RuntimeError' as it is too overloaded. Different people use it differently: RuntimeError = mainly programming errors [designers of Java] RuntimeError = errors of the JVM [critique of Java's exception hierarchy] RuntimeError = errors detected by the python interpreter [designers of the python] RuntimeError = anything that cannot be determined at compile time [you]CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception.this implies to me the problem is (perhaps) unique to this execution of the program, in other words it occurs only during runtime, as such I prefer 'RuntimeError'.
Sep 21 2004
On Tue, 21 Sep 2004 08:34:14 +0000 (UTC), Farmer <itsFarmer. freenet.de> wrote:Regan Heath <regan netwin.co.nz> wrote in news:opsem9tqo15a2sq9 digitalmars.com: [snip]this is just plain wrong.Going by your previous descriptions..I wouldn't use the term 'RuntimeError' as it is too overloaded. Different people use it differently: RuntimeError = mainly programming errors [designers of Java]CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception.this implies to me the problem is (perhaps) unique to this execution of the program, in other words it occurs only during runtime, as such I prefer 'RuntimeError'.RuntimeError = errors of the JVM [critique of Java's exception hierarchy]which is why they changed it to this, which IMO is identical toRuntimeError = anything that cannot be determined at compile time [you]which is my own understanding, and is also identical toRuntimeError = errors detected by the python interpreter [designers of the python]basically, all the above (except the flawed initial java one) are the same thing, errors that occur at the time of execution, or 'Runtime'. So I am even more sure now that 'RuntimeError' is the best term/name. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 21 2004
In article <opseo54ir25a2sq9 digitalmars.com>, Regan Heath says...[snip] basically, all the above (except the flawed initial java one) are the same thing, errors that occur at the time of execution, or 'Runtime'. So I am even more sure now that 'RuntimeError' is the best term/name.I agree with your definition, but doesn't this mean that _all_ thrown exceptions/errors are runtime errors? Nick
Sep 22 2004
Nick wrote:In article <opseo54ir25a2sq9 digitalmars.com>, Regan Heath says...I disagree with this. A RuntimeError is an error which occurs when it is layered as deep as Phobos (The runtime environment) or when there is something very wrong with memory access and/or an error not catchable by the compiler, but still a programming fault. All other errors (thrown not as deep as previous are) are normal errors, for example, an error which is thrown when a Date value is incorrect, i.e.: February 30th, 2004. Regards, Sjoerd[snip] basically, all the above (except the flawed initial java one) are the same thing, errors that occur at the time of execution, or 'Runtime'. So I am even more sure now that 'RuntimeError' is the best term/name.I agree with your definition, but doesn't this mean that _all_ thrown exceptions/errors are runtime errors? Nick
Sep 22 2004
On Wed, 22 Sep 2004 20:56:17 +0200, Sjoerd van Leent <svanleent wanadoo.nl> wrote:Nick wrote:That's not my definition. I based my definitions off Farmer's here: <quote> CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. </unquote> in other words: - it may not occur all the time, on every execution - it may be a temporary failure What do you mean by "programming fault" exactly? Do you mean the code is simply wrong i.e. foo(NULL); throws InvalidParameter, meaning NULL is not acceptable? If so, that is not a runtime exception it's a program exception by my definition.In article <opseo54ir25a2sq9 digitalmars.com>, Regan Heath says...I disagree with this. A RuntimeError is an error which occurs when it is layered as deep as Phobos (The runtime environment) or when there is something very wrong with memory access and/or an error not catchable by the compiler, but still a programming fault.[snip] basically, all the above (except the flawed initial java one) are the same thing, errors that occur at the time of execution, or 'Runtime'. So I am even more sure now that 'RuntimeError' is the best term/name.I agree with your definition, but doesn't this mean that _all_ thrown exceptions/errors are runtime errors? NickAll other errors (thrown not as deep as previous are) are normal errors, for example, an error which is thrown when a Date value is incorrect, i.e.: February 30th, 2004.It depends where that date comes from, if it comes from a file then it's a runtime error, if it's hard coded then it's a program error. Do you see the distinction my definition tries to make? Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 22 2004
Seeing as different people seems to have different opinions on the definition of a run time error, I think calling anything a RunTimeError will only cause confusion. I suggest avoiding the term altogether. Nick In article <opseq5h3u45a2sq9 digitalmars.com>, Regan Heath says...On Wed, 22 Sep 2004 20:56:17 +0200, Sjoerd van Leent <svanleent wanadoo.nl> wrote:Nick wrote:That's not my definition. I based my definitions off Farmer's here: <quote> CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. </unquote> in other words: - it may not occur all the time, on every execution - it may be a temporary failure What do you mean by "programming fault" exactly? Do you mean the code is simply wrong i.e. foo(NULL); throws InvalidParameter, meaning NULL is not acceptable? If so, that is not a runtime exception it's a program exception by my definition.In article <opseo54ir25a2sq9 digitalmars.com>, Regan Heath says...I disagree with this. A RuntimeError is an error which occurs when it is layered as deep as Phobos (The runtime environment) or when there is something very wrong with memory access and/or an error not catchable by the compiler, but still a programming fault.[snip] basically, all the above (except the flawed initial java one) are the same thing, errors that occur at the time of execution, or 'Runtime'. So I am even more sure now that 'RuntimeError' is the best term/name.I agree with your definition, but doesn't this mean that _all_ thrown exceptions/errors are runtime errors? NickAll other errors (thrown not as deep as previous are) are normal errors, for example, an error which is thrown when a Date value is incorrect, i.e.: February 30th, 2004.It depends where that date comes from, if it comes from a file then it's a runtime error, if it's hard coded then it's a program error. Do you see the distinction my definition tries to make? Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 23 2004
On Thu, 23 Sep 2004 10:24:28 +0000 (UTC), Nick <Nick_member pathlink.com> wrote:Seeing as different people seems to have different opinions on the definition of a run time error, I think calling anything a RunTimeError will only cause confusion. I suggest avoiding the term altogether.Well of course IMO other people have the 'wrong' definition of RunTime :) I think we can all agree runtime is the time at which it's running, can't we? Given that it's how you interpret the error that confuses things. I think this definition/explaination is what I mean. <quote me> I see what you mean, perhaps my definition is a little vague still, basically I looked at Farmers, here: <quote farmer> CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. </unquote> and came to the conclusion that runtime errors were things that happened which were not a direct result of faulting coding, whereas program errors are a result of faulty coding. A good example of a program error is invalid parameter, this error occurs when you the programmer forgets to code a check to check a parameter, or maybe hard codes a parameter incorrectly. A good example of a runtime error is a ConnectionError, you get one of those if the thing you're connecting to is not accepting connections, but there is nothing wrong with the code itself, it will work if you connect to something that is listening. So you cannot prevent runtime errors but you can prevent/fix program errors. You want to handle/catch runtime errors, but not program errors. That is the distinction. </quote me> ReganNick In article <opseq5h3u45a2sq9 digitalmars.com>, Regan Heath says...-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/On Wed, 22 Sep 2004 20:56:17 +0200, Sjoerd van Leent <svanleent wanadoo.nl> wrote:Nick wrote:That's not my definition. I based my definitions off Farmer's here: <quote> CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. </unquote> in other words: - it may not occur all the time, on every execution - it may be a temporary failure What do you mean by "programming fault" exactly? Do you mean the code is simply wrong i.e. foo(NULL); throws InvalidParameter, meaning NULL is not acceptable? If so, that is not a runtime exception it's a program exception by my definition.In article <opseo54ir25a2sq9 digitalmars.com>, Regan Heath says...I disagree with this. A RuntimeError is an error which occurs when it is layered as deep as Phobos (The runtime environment) or when there is something very wrong with memory access and/or an error not catchable by the compiler, but still a programming fault.[snip] basically, all the above (except the flawed initial java one) are the same thing, errors that occur at the time of execution, or 'Runtime'. So I am even more sure now that 'RuntimeError' is the best term/name.I agree with your definition, but doesn't this mean that _all_ thrown exceptions/errors are runtime errors? NickAll other errors (thrown not as deep as previous are) are normal errors, for example, an error which is thrown when a Date value is incorrect, i.e.: February 30th, 2004.It depends where that date comes from, if it comes from a file then it's a runtime error, if it's hard coded then it's a program error. Do you see the distinction my definition tries to make? Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 23 2004
In article <opses4yynq5a2sq9 digitalmars.com>, Regan Heath says...On Thu, 23 Sep 2004 10:24:28 +0000 (UTC), Nick <Nick_member pathlink.com> wrote:Seeing as different people seems to have different opinions on the definition of a run time error, I think calling anything a RunTimeError will only cause confusion. I suggest avoiding the term altogether.Well of course IMO other people have the 'wrong' definition of RunTime :) I think we can all agree runtime is the time at which it's running, can't we? Given that it's how you interpret the error that confuses things. I think this definition/explaination is what I mean. <quote me> I see what you mean, perhaps my definition is a little vague still, basically I looked at Farmers, here: <quote farmer> CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. </unquote> and came to the conclusion that runtime errors were things that happened which were not a direct result of faulting coding, whereas program errors are a result of faulty coding. A good example of a program error is invalid parameter, this error occurs when you the programmer forgets to code a check to check a parameter, or maybe hard codes a parameter incorrectly. A good example of a runtime error is a ConnectionError, you get one of those if the thing you're connecting to is not accepting connections, but there is nothing wrong with the code itself, it will work if you connect to something that is listening. So you cannot prevent runtime errors but you can prevent/fix program errors. You want to handle/catch runtime errors, but not program errors. That is the distinction. </quote me> ReganNick In article <opseq5h3u45a2sq9 digitalmars.com>, Regan Heath says...-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/On Wed, 22 Sep 2004 20:56:17 +0200, Sjoerd van Leent <svanleent wanadoo.nl> wrote:Nick wrote:That's not my definition. I based my definitions off Farmer's here: <quote> CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. </unquote> in other words: - it may not occur all the time, on every execution - it may be a temporary failure What do you mean by "programming fault" exactly? Do you mean the code is simply wrong i.e. foo(NULL); throws InvalidParameter, meaning NULL is not acceptable? If so, that is not a runtime exception it's a program exception by my definition.In article <opseo54ir25a2sq9 digitalmars.com>, Regan Heath says...I disagree with this. A RuntimeError is an error which occurs when it is layered as deep as Phobos (The runtime environment) or when there is something very wrong with memory access and/or an error not catchable by the compiler, but still a programming fault.[snip] basically, all the above (except the flawed initial java one) are the same thing, errors that occur at the time of execution, or 'Runtime'. So I am even more sure now that 'RuntimeError' is the best term/name.I agree with your definition, but doesn't this mean that _all_ thrown exceptions/errors are runtime errors? NickAll other errors (thrown not as deep as previous are) are normal errors, for example, an error which is thrown when a Date value is incorrect, i.e.: February 30th, 2004.It depends where that date comes from, if it comes from a file then it's a runtime error, if it's hard coded then it's a program error. Do you see the distinction my definition tries to make? Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 30 2004
Sorry for the late reply (and for the double post, stupid enter key...) In article <opses4yynq5a2sq9 digitalmars.com>, Regan Heath says...As I'm sure you know there's no such thing as a 'wrong' definition. There may however be inconsistencies between different definitions of the same term.Seeing as different people seems to have different opinions on the definition of a run time error, I think calling anything a RunTimeError will only cause confusion. I suggest avoiding the term altogether.Well of course IMO other people have the 'wrong' definition of RunTime :)I think we can all agree runtime is the time at which it's running, can't we?Yes.Given that it's how you interpret the error that confuses things. I think this definition/explaination is what I mean. <quote me> I see what you mean, perhaps my definition is a little vague still, basically I looked at Farmers, here: <quote farmer> CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. </unquote> and came to the conclusion that runtime errors were things that happened which were not a direct result of faulting coding, whereas program errors are a result of faulty coding.In short, you call something a runtime error if the _cause_ of the error happens at runtime, ie. it is external, whereas internal errors (bugs) you define not to be runtime errors. But, first of all, in the context of compiled languages, a runtime error is very often defined as any error that _occurs_ at runtime, in other words anything that is not a compile time error. So this definition might lead to confusion. Secondly I'm not sure if I agree that dividing exception classes into bugs/nonbug classes is very practical. For example in the date example, it's hard to tell (when throwing the exception) whether the invalid date came directly from the user ("runtime error") or a bad algorithm/hard coded date ("program error".) Nick
Sep 30 2004
On Wed, 22 Sep 2004 14:10:36 +0000 (UTC), Nick <Nick_member pathlink.com> wrote:In article <opseo54ir25a2sq9 digitalmars.com>, Regan Heath says...I see what you mean, perhaps my definition is a little vague still, basically I looked at Farmers, here: <quote> CheckedExceptions: cause is external: Caller cannot avoid them, consequently a programmer should usually focus on how to *handle* the exception. </unquote> and came to the conclusion that runtime errors were things that happened which were not a direct result of faulting coding, whereas program errors are a result of faulty coding. A good example of a program error is invalid parameter, this error occurs when you the programmer forgets to code a check to check a parameter, or maybe hard codes a parameter incorrectly. A good example of a runtime error is a ConnectionError, you get one of those if the thing you're connecting to is not accepting connections, but there is nothing wrong with the code itself, it will work if you connect to something that is listening. So you cannot prevent runtime errors but you can prevent/fix program errors. You want to handle/catch runtime errors, but not program errors. That is the distinction. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/[snip] basically, all the above (except the flawed initial java one) are the same thing, errors that occur at the time of execution, or 'Runtime'. So I am even more sure now that 'RuntimeError' is the best term/name.I agree with your definition, but doesn't this mean that _all_ thrown exceptions/errors are runtime errors?
Sep 22 2004
Farmer <itsFarmer. freenet.de> wrote in news:Xns8FB1F10BEFD73itsFarmer 63.105.9.61: [snip]Initially I thought, that the more general exceptions, should be available as Low-, Mid- and High- Severity exceptions. The problem is that one would either have to make up 3 different names for one exception or have 3 classes that have the same name, but are in different modules. So, it seems this doesn't work so well with generic exceptions :-( So, It doesn't work!Example for the problem ----------------------- The obvious exception hierarchy for a database package could be: DBError QueryError DBConnectionError * QueryError is thrown if a query cannot be processed due to invalid syntax of an SQL statement * DBConnectionError is thrown if the connection to the DBMS cannot be established or breaks down. QueryError indicates a programming error (midseverity) while DBConnectionError indicates an environmental error (lowseverity). Unfortunately, it is impossible to include this information (programming vs. environmental error) in the hierarchy, since both exceptions already inherit from the general DBError class. Multi-Inheritance ----------------- One solution might be to use interfaces, as they allow multi-inheritance. DBError QueryError (implements IProgrammingError) DBConnectionError (implements IEnvironmentError) Currently, I'm not sure whether D supports catching interfaces: DMD compiled a simple example that catches an interface; at runtime the exception was even correctly catched, but the pointer-handle (reference) was bogus: when a method was called on the pointer an AV occured, although the pointer wasn't null. Even if D supports interfaces for exceptions. Every exception class has to explicitly dispatch all methods of an exception interface. A mixin should help here, though. Farmer.
Sep 20 2004
On Mon, 20 Sep 2004 15:13:18 +0000 (UTC), Farmer <itsFarmer. freenet.de> wrote:Farmer <itsFarmer. freenet.de> wrote in news:Xns8FB1F10BEFD73itsFarmer 63.105.9.61: [snip]I think if you re-factor the tree into something like: (using my preferred names, yours are in ()) |RuntimeError(EnvironmentError) | |-DBError | |-DBConnectionError | |ProgramError(ProgrammingError) | |-SQLError | |-SQLSyntaxError then the problem vanishes. The justification for this refactoring is that SQLSyntaxError refers specifically to an SQL statement, which need not be associated with any particular database and/or connection to a database, i.e. you might write this function: bool verifySqlSyntax(char[] string){} and it might throw the SQLSyntaxError. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/Initially I thought, that the more general exceptions, should be available as Low-, Mid- and High- Severity exceptions. The problem is that one would either have to make up 3 different names for one exception or have 3 classes that have the same name, but are in different modules. So, it seems this doesn't work so well with generic exceptions :-( So, It doesn't work!Example for the problem ----------------------- The obvious exception hierarchy for a database package could be: DBError QueryError DBConnectionError * QueryError is thrown if a query cannot be processed due to invalid syntax of an SQL statement * DBConnectionError is thrown if the connection to the DBMS cannot be established or breaks down. QueryError indicates a programming error (midseverity) while DBConnectionError indicates an environmental error (lowseverity). Unfortunately, it is impossible to include this information (programming vs. environmental error) in the hierarchy, since both exceptions already inherit from the general DBError class. Multi-Inheritance ----------------- One solution might be to use interfaces, as they allow multi-inheritance. DBError QueryError (implements IProgrammingError) DBConnectionError (implements IEnvironmentError) Currently, I'm not sure whether D supports catching interfaces: DMD compiled a simple example that catches an interface; at runtime the exception was even correctly catched, but the pointer-handle (reference) was bogus: when a method was called on the pointer an AV occured, although the pointer wasn't null. Even if D supports interfaces for exceptions. Every exception class has to explicitly dispatch all methods of an exception interface. A mixin should help here, though.
Sep 20 2004
Regan Heath <regan netwin.co.nz> wrote in news:opsem953pg5a2sq9 digitalmars.com:I think if you re-factor the tree into something like: (using my preferred names, yours are in ()) |RuntimeError(EnvironmentError) | |-DBError | |-DBConnectionError | |ProgramError(ProgrammingError) | |-SQLError | |-SQLSyntaxError then the problem vanishes.The problem is, that some/most people want to have a common base class for all exceptions of a data base package.The justification for this refactoring is that SQLSyntaxError refers specifically to an SQL statement, which need not be associated with any particular database and/or connection to a database, i.e. you might write this function:Actually, it isn't always clear whether an SQLSyntaxError is a programming or an environmental error, since it depends on the database what syntax is supported.bool verifySqlSyntax(char[] string){} and it might throw the SQLSyntaxError. Regan
Sep 21 2004
On Tue, 21 Sep 2004 08:34:17 +0000 (UTC), Farmer <itsFarmer. freenet.de> wrote:Regan Heath <regan netwin.co.nz> wrote in news:opsem953pg5a2sq9 digitalmars.com:Why? I assume so they can go catch(DBError e) { } to catch any/all errors with the DB.I think if you re-factor the tree into something like: (using my preferred names, yours are in ()) |RuntimeError(EnvironmentError) | |-DBError | |-DBConnectionError | |ProgramError(ProgrammingError) | |-SQLError | |-SQLSyntaxError then the problem vanishes.The problem is, that some/most people want to have a common base class for all exceptions of a data base package.I didn't know that. So there are 2 types of syntax error, a program one and a runtime one. If you use program and runtime top level exceptions there is no way you can put all DB errors in the same tree, however, I don't think it matters, after all you don't want to catch the program errors, only the runtime ones so.. |RuntimeError(EnvironmentError) | |-DBError | |-DBConnectionError | |-SQLSyntaxError | |ProgramError(ProgrammingError) | |-ProgramDBError | |-ProgramSQLSyntaxError basically make the names of the program errors the same as the runtime ones, except with a prefix or something (after all you're not catching them in general so the runtime one should have the easy/intuitive name) Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/The justification for this refactoring is that SQLSyntaxError refers specifically to an SQL statement, which need not be associated with any particular database and/or connection to a database, i.e. you might write this function:Actually, it isn't always clear whether an SQLSyntaxError is a programming or an environmental error, since it depends on the database what syntax is supported.
Sep 21 2004
In article <Xns8FB5AEC64E2C6itsFarmer 63.105.9.61>, Farmer says...Multi-Inheritance ----------------- One solution might be to use interfaces, as they allow multi-inheritance. DBError QueryError (implements IProgrammingError) DBConnectionError (implements IEnvironmentError) Currently, I'm not sure whether D supports catching interfaces: DMD compiled a simple example that catches an interface; at runtime the exception was even correctly catched, but the pointer-handle (reference) was bogus: when a method was called on the pointer an AV occured, although the pointer wasn't null.If D doesn't support catching interfaces then it should. That the compiler doesn't balk at the syntax implies that this is legal and therefore a bug. Sean
Sep 21 2004
Sean Kelly <sean f4.ca> wrote in news:cipncc$1fqb$1 digitaldaemon.com:If D doesn't support catching interfaces then it should. That the compiler doesn't balk at the syntax implies that this is legal and therefore a bug.I suppose, you're right. Unfortunately, interfaces are not so useful for the exception hierarchy. I can see only 2 possibilities. 1.) have separate branches for programming errors/environmental errors Error (implements IError) DBError QueryError (implements IProgrammingError) DBConnectionError (implements IEnvironmentError) advantage: By catching IEnvironmentError, it is easy to let IProgrammingErrors propagate. disadvantage: Every exception class must implement either IProgrammingError or IEnvironmentError. This requires some effort and therefore is unlikely to work well in practice. Furthermore it's possible to implement both IProgrammingError and IEnvironmentError by accident. 2.) only use interfaces to tag programming errors Error DBError QueryError (implements IProgrammingError) DBConnectionError advantage: Doesn't require much effort for library writers. disadvantage: To propagate IProgrammingErrors, more work is required: try { blah blah blah } catch (IProgrammingError e) { throw e; } catch (Error) { print ops, sth. is wrong with the data base. } That's almost the way it works in Java. Overall, I like the second approach better. It has less benefits, but is also far less obtrusive. Regards, Farmer.
Sep 22 2004
Just wanted to thank you for a very detailed and thought-provoking analysis. I'll be examining this a lot more next week when I do my analysis, and may have some questions to level at you at that time. Cheers Matthew "Farmer" <itsFarmer. freenet.de> wrote in message news:Xns8FB0B405185D2itsFarmer 63.105.9.61..."Matthew" <admin.hat stlsoft.dot.org> wrote in news:chrebn$12f7$1 digitaldaemon.com:I've persuaded big-W that the exception hierarchy refactoring can wait no longer, but to do so I've had to volunteer to marshal the efforts. My plan is as follows: 1. Solicit *on-topic* criticisms from the newsgroup 2. Put on my code reviewer's hat, and do a detailed analysis and criticism of the current situation. I'll do this *before* I read any of these criticisms, so as to be unbiased in the review. This means you've a week or so before I'll be digesting and collating any responses from the community, so please take your time to provide considered comments. [snip]I propose this (over-engineered) java-like exception hierarchy: Object | |Throwable | |Error | | | |TooManyThreadsError | |OutOfMemoryError | |AssertionError | | | |ArrayBoundsError | |AssertError | |SwitchError | |Exception | |CheckedException | | | |FileException | ... |UncheckedException | |FormatException ... What's a Throwable? ------------------- By convention all exceptions derive from Throwable. It's still possible to throw any object, though. This way you can create your own exception hierarchy if needed. // Throwable contains an exception message and keeps track of // nested exceptions. class Throwable { private char[] msg; private Throwable next; this(char[] msg="", Throwable next=null); // returns a (user) message that describes the cause of the exception; // returns an empty string, if no message is available char[] getMessage(); // returns the nested exception or null if there is none Throwable getNext(); // returns a (somewhat cryptic) string char[] toString() { char[]rs=this.classinfo.name~": "~this.getMessage(); if (next) rs~="\n"~next.toString(); return rs; } } What are Errors? ---------------- Errors are thrown for exceptions that *might* require drastic means to recover from; like terminating the process or the thread, switching over to a backup system, rebooting computer (for Win9x), etc. When should an exception be derived from Error? 1.) when there are no guarantees when the exception occurs: At minimum a) there must be no resource leaks b) the destructor of an instance must be safely callable if an exception is thrown. If these minimum guarantees cannot be met, the exception is an Error. Furthermore, classes often have stronger guarantees, e.g. instance remains in a valid state if an exception is thrown. For cases that don't permit these stronger guarantees, an Error should be thrown instead of an Exception. 2.) when the exception might not be thrown in release builds: Although these exceptions could be safely catched in debug builds, the conditions that caused them would likely cause havoc for release builds. What about out of memory errors? ------------------------------- I argue that out of memory conditions are Errors, since in the days of virtual memory, most programmers assume that there is always enough memory available, unless a very large amount of memory is requested. Consequently, the vast majority of libraries don't come with exception guarantees when memory is running low. For the same reasons std.thread.Thread.start() should throw a TooManyThreadsError exception instead of a TooManyThreadsException. Why AssertionError? ------------------- Switch errors, array index errors and failed assert statements, mean all but one thing: A bug was revealed. // AssertionError doesn't provide an exception message, but stores // the location where the exception was thrown. class AssertionError : Error { private uint linnum; private char[] filename; this(char[] filename, uint linnum) { super(); this.filename=filename this.linnum=linnum } uint getLinenum(); char[] getFilename(); char[] toString() { return this.classinfo.name~" exception source: " ~filename~" ("~toString(linnum)~")"; } } Speaking of AssertionErrors, it would be useful if DMD offered an option "-spoiledprogrammer" for spoiled programmers. If this option is enabled, AssertionErrors would additionally contain * the function name for all AssertionErrors * the expression of an assert statement * the index that causes an ArrayBoundsError * the actual value that causes a SwitchError What are Exceptions? -------------------- Exceptions are thrown for conditions that leave the process in a defined state. Since Exceptions are thrown for predictable situations, it is usually easy to safely recover from the exceptional situation. We don't need no stinking checked exceptions! --------------------------------------------- Agreed, no checked exceptions. While the constant nagging of the Java compiler about undeclared checked exceptions isn't particularly useful, the concept behind them is. So, borrow the concept from Java, but not it's implementation. By convention, CheckedExceptions are thrown for errors that the programmer should carefully think about. Exceptions that derive from CheckedException * cannot be avoided by the programmer. For instance, opening a file, might fail: Even if you ensure that the file exists before opening the file, the file might have been deleted by the time it is actually opened! * might occur during the intended operation of a programm; they do not necessarily indicate bugs. * should be documented for all functions in the call hierarchy that might throw them When to use UncheckedExceptions ------------------------------- UncheckedExceptions are thrown for errors that don't require the programmer's attention, since these errors *usually* never happen. UncheckedExceptions usually indicate that a function is used in the wrong way by the caller. UncheckedExceptions * can be avoided for most use-cases. E.g. std.format.doFormat(...) throws a FormatException if the passed arguments do not match the format pattern. The exception can be avoided by passing a correct format pattern string. * usually indicate bugs, but not always * might not be documented in the function contract. Of course, it's good practice to do so, especially for functions that directly throw UncheckedExceptions. Errors vs. UncheckedExceptions ------------------------------ UncheckedExceptions * are part of the function's contract. As long as the contract isn't changed, the caller can rely on UncheckedExceptions beeing thrown. * leave the process in a defined state (exception guarantees like: no resource leaks, object instances remain valid, etc. permit that the the process can safely recover from the exception ) Errors * are not necessarily part of the function contract: Checks that throw Errors, might be absent in release builds or future versions of the function. * might leave the programm in an undefined state; should the Error be ignored, unpredictable follow-up errors might occur. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I also like Ben's idea to include a bunch of generic exception classes in the standard library. This would be particularly handy for quick and dirty programming. Farmer. After writing this post, I recognized that the base class Throwable is a bit pointless for runtime generated Errors. Since these Errors neither have a user message nor a nested exception. So here's another, less java-like exception hierarchy. The presented guidelines for using Exceptions/Errors remain valid for this hierarchy. Object | |TooManyThreads |OutOfMemory |AssertionError | |ArrayBoundsError | |AssertError | |SwitchError | |Exception | |CheckedException // should be catched | | | |FileException | ... |UncheckedException // safe to catch | | | |FormatException | ... | |UnrecoverableError // unsafe to catch | |NullArgumentError ...
Sep 15 2004
Here's an interesting proposal of an refactored exception hierarchy for Java(TM): "Messy Exception Hierarchy" http://c2.com/cgi/wiki?MessyExceptionHierarchy I found it when I googled a bit to widen my view about exceptions. More links follow: *) "Standard Exception Classes in Python 1.5" http://www.sourcekeg.co.uk/www.python.org/doc/essays/stdexceptions.html <quote> We looked into introducing more groups of related exceptions, but couldn't decide on the best grouping. In a language as dynamic as Python, it's hard to say whether TypeError is a "program error", a "runtime error" or an "environmental error", so we decided to leave it undecided. It could be argued that NameError and AttributeError should be derived from LookupError, but this is questionable and depends entirely on the application. </quote> Comment: * 3 classes of errors: program errors, runtime errors and environmental errors * deciding about an exception hierarchy is very difficult: both, grouping according to the 3 classes of errors and grouping by specialization was desired, but not wasn't manageable. *) "Best Practices for Exception Handling" http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html Definitely, a good article about Exceptions for Java developers; though not everyone agrees with some of the recommended practices. *) "Beware the dangers of generic Exceptions" http://www.javaworld.com/javaworld/jw-10-2003/jw-1003-generics.html An article that shows how dangerous (top-level?) generic Exceptions can be. *) "Exceptional Java by Alan Griffiths" http://www.octopull.demon.co.uk/java/ExceptionalJava.html Report about difficulties that arised with exceptions in one real word project. The report also presents *one* solution for the encountered problems. *) proto pattern "Generalize On Exception Behavior" http://www.c2.com/cgi/wiki?GeneralizeOnExceptionBehavior A good wiki page about the advantages and disadvantages of generalized exceptions. This page is informative and contains lots of sample code, but it also requires a lot of reading. My insight about (Java) exceptions is, that in practise, Java programmers use exceptions very differently. This is somewhat surprising, since Java progammers usually share a very uniform way of dealing with problems. Indeed recommendations of actual Java programmers often contradict each other.
Sep 20 2004
In article <Xns8FB5AEC4C993AitsFarmer 63.105.9.61>, Farmer says...*) "Best Practices for Exception Handling" http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.htmlThanks for the links. My Java experience is quite a few years out of date and this clarified some suspicions I had about checked vs. unchecked exceptions. While I like the idea of differentiating between programmer errors and other erros, I'm not sure how well this concept maps into D, because D (and C++) don't have any language support for checked exceptions. Further, I would argue (as I think I did in another part of this thread) that programmer errors should be handled by DBC and AssertErrors rather than inheriting from some alternate portion of the exception heirarchy. ie. I don't see much utility in having a programmer define separate generic catch blocks for checked and unchecked exceptions.My insight about (Java) exceptions is, that in practise, Java programmers use exceptions very differently. This is somewhat surprising, since Java progammers usually share a very uniform way of dealing with problems. Indeed recommendations of actual Java programmers often contradict each other.This has been my experience with Java as well, and is one reason why it never really appealed to me as a language. I think D would do better to somewhat follow C++ in this case and prefer a less structured and expansive exception heirarchy, at least so far as Phobos is concerned. All exceptions are unchecked by language design, but ideally still heirarchically arranged to allow for easy handling of different sorts of errors. Sean
Sep 30 2004