digitalmars.D - Error derived from Exception is WRONG, DAMNIT
- downs (7/7) Mar 01 2008 Why is Error, in 2.0, _STILL_ derived from Exception?
- Bill Baxter (3/16) Mar 01 2008 +1-hoping-for-sudden-outbreak-of-common-sense
- Robert Fraser (4/17) Mar 01 2008 Agreed. While we're at it, let's switch around Java's Exception and
- Sean Kelly (16/23) Mar 01 2008 fixed. And make no mistake, this isn't just a matter of semantics, but a...
- downs (9/36) Mar 01 2008 All Errors are Exceptions because we say so. This model has no inherent ...
- Yigal Chripun (13/22) Mar 01 2008 The classical OOP example of a square that inherits from a rectangle
- Sean Kelly (12/17) Mar 01 2008 So the problem then becomes which errors to classify as non-recoverable....
- Yigal Chripun (26/46) Mar 01 2008 What you describe is already partly solved in Tango.
- Sean Reque (2/6) Mar 01 2008 This is an excellent idea! One of my favorite features of D is condition...
- Sean Kelly (25/73) Mar 02 2008 seems
- Christopher Wright (8/16) Mar 02 2008 It would be really nice if the trace included line numbers rather than
- Sean Kelly (4/6) Mar 02 2008 Unfortunately not. 'finally' blocks, scope(exit), and scoped object
- Janice Caron (20/22) Mar 01 2008 It is important that programs that work in Debug mode should also work
- downs (10/27) Mar 02 2008 Yeah, but if you simply catch _all_ exceptions, the compiler will never...
-
Janice Caron
(3/3)
Mar 02 2008
On 02/03/2008, downs
wrote: - Robert Fraser (2/31) Mar 02 2008 I limes.
- Sean Kelly (3/8) Mar 02 2008 Right. This is what I was thinking of with my comment about D being a s...
Why is Error, in 2.0, _STILL_ derived from Exception? I understand that this has come up before, which makes it all the more confusing that it's _STILL_ not fixed. And make no mistake, this isn't just a matter of semantics, but an actual bug causing actual problems, such as unexpected crashes. Let's see, the only use of making unrecoverable Errors a *special case* of recoverable Exceptions would be, um, if you wanted to catch unrecoverable Errors only ... Does anybody else see a problem with that statement? Like, that you're not supposed to catch unrecoverable errors in the first place? The problem with this ordering is that you end up _accidentally_ catching unrecoverable errors, which in turn leads to maybe not even noticing some critical error in debug mode, which in turn leads to different behavior between debug mode and release mode, such as mysterious, unexpected segmentation faults (say on Array Bounds Violation). I don't have to explain why this is a bad thing. Could this be changed? _Please_? --downs, slightly agitated :)
Mar 01 2008
downs wrote:Why is Error, in 2.0, _STILL_ derived from Exception? I understand that this has come up before, which makes it all the more confusing that it's _STILL_ not fixed. And make no mistake, this isn't just a matter of semantics, but an actual bug causing actual problems, such as unexpected crashes. Let's see, the only use of making unrecoverable Errors a *special case* of recoverable Exceptions would be, um, if you wanted to catch unrecoverable Errors only ... Does anybody else see a problem with that statement? Like, that you're not supposed to catch unrecoverable errors in the first place? The problem with this ordering is that you end up _accidentally_ catching unrecoverable errors, which in turn leads to maybe not even noticing some critical error in debug mode, which in turn leads to different behavior between debug mode and release mode, such as mysterious, unexpected segmentation faults (say on Array Bounds Violation). I don't have to explain why this is a bad thing. Could this be changed? _Please_? --downs, slightly agitated :)+1-hoping-for-sudden-outbreak-of-common-sense --bb
Mar 01 2008
downs wrote:Why is Error, in 2.0, _STILL_ derived from Exception? I understand that this has come up before, which makes it all the more confusing that it's _STILL_ not fixed. And make no mistake, this isn't just a matter of semantics, but an actual bug causing actual problems, such as unexpected crashes. Let's see, the only use of making unrecoverable Errors a *special case* of recoverable Exceptions would be, um, if you wanted to catch unrecoverable Errors only ... Does anybody else see a problem with that statement? Like, that you're not supposed to catch unrecoverable errors in the first place? The problem with this ordering is that you end up _accidentally_ catching unrecoverable errors, which in turn leads to maybe not even noticing some critical error in debug mode, which in turn leads to different behavior between debug mode and release mode, such as mysterious, unexpected segmentation faults (say on Array Bounds Violation). I don't have to explain why this is a bad thing. Could this be changed? _Please_? --downs, slightly agitated :)Agreed. While we're at it, let's switch around Java's Exception and RuntimeException, since RuntimeExceptions are also generally not supposed to be caught.
Mar 01 2008
== Quote from downs (default_357-line yahoo.de)'s articleWhy is Error, in 2.0, _STILL_ derived from Exception? I understand that this has come up before, which makes it all the more confusing that it's _STILL_ notfixed. And make no mistake, this isn't just a matter of semantics, but an actual bug causing actual problems, such as unexpected crashes.Let's see, the only use of making unrecoverable Errors a *special case* of recoverable Exceptionswould be, um, if you wanted to catch unrecoverable Errors only ...Does anybody else see a problem with that statement? Like, that you're not supposed to catchunrecoverable errors in the first place?The problem with this ordering is that you end up _accidentally_ catching unrecoverable errors, whichin turn leads to maybe not even noticing some critical error in debug mode, which in turn leads to different behavior between debug mode and release mode, such as mysterious, unexpected segmentation faults (say on Array Bounds Violation). I don't have to explain why this is a bad thing.Could this be changed? _Please_? --downs, slightly agitated :)I'm not sure I agree. First, I think it's important to note that all Errors are Exceptions, so the inheritance relationship makes sense. Also, I feel that all throwable objects should be classified as Exceptions, so I don't like the idea of having them both be siblings derived from Throwable. Finally, while it may be easy to catch and ignore Exceptions, I feel very strongly that this is bad programming practice. Exceptions should never be caught and ignored--particularly at such a granularity. I would prefer that a library stick to its guns and inspire a change in programmer mindset than to make allowances for such mistakes. Sean
Mar 01 2008
Sean Kelly wrote:== Quote from downs (default_357-line yahoo.de)'s articleAll Errors are Exceptions because we say so. This model has no inherent value except from the point of view of the current Phobos implementation. It makes more sense, from a user POV, to say that Exceptions are special cases of Errors that can be caught.Why is Error, in 2.0, _STILL_ derived from Exception? I understand that this has come up before, which makes it all the more confusing that it's _STILL_ notfixed. And make no mistake, this isn't just a matter of semantics, but an actual bug causing actual problems, such as unexpected crashes.Let's see, the only use of making unrecoverable Errors a *special case* of recoverable Exceptionswould be, um, if you wanted to catch unrecoverable Errors only ...Does anybody else see a problem with that statement? Like, that you're not supposed to catchunrecoverable errors in the first place?The problem with this ordering is that you end up _accidentally_ catching unrecoverable errors, whichin turn leads to maybe not even noticing some critical error in debug mode, which in turn leads to different behavior between debug mode and release mode, such as mysterious, unexpected segmentation faults (say on Array Bounds Violation). I don't have to explain why this is a bad thing.Could this be changed? _Please_? --downs, slightly agitated :)I'm not sure I agree. First, I think it's important to note that all Errors are Exceptions, so the inheritance relationship makes sense.Also, I feel that all throwable objects should be classified as Exceptions, so I don't like the idea of having them both be siblings derived from Throwable.Neither did I suggest this; actually, my thought was Exception : Error :)Finally, while it may be easy to catch and ignore Exceptions, I feel very strongly that this is bad programming practice. Exceptions should never be caught and ignored--particularly at such a granularity. I would prefer that a library stick to its guns and inspire a change in programmer mindset than to make allowances for such mistakes.What about cases where we just want to see if some operation succeeds, and if not, try something else instead, _regardless_ of the reason why it failed? Also, I'd argue that such a change would not be for the better. The whole *point* of Exceptions is that they are recoverable - if I want to catch and discard all of them, I don't want the compiler to give me moral lessons about error handling, I want it to *get the :bleep: out of my way and let me do what I want to do.* Not crash and burn in release mode. :)Sean--downs
Mar 01 2008
Sean Kelly wrote:I'm not sure I agree. First, I think it's important to note that all Errors are Exceptions, so the inheritance relationship makes sense. Also, I feel that all throwable objects should be classified as Exceptions, so I don't like the idea of having them both be siblings derived from Throwable. Finally, while it may be easy to catch and ignore Exceptions, I feel very strongly that this is bad programming practice. Exceptions should never be caught and ignored--particularly at such a granularity. I would prefer that a library stick to its guns and inspire a change in programmer mindset than to make allowances for such mistakes. SeanThe classical OOP example of a square that inherits from a rectangle comes to mind. sure, you can say that a square is a rectangle but inheritance in this case will cause breakage. for instance you can double one of the rectangle's edges. squares that inherit that method will break because if you double only one edge than you no longer have a square. My point is that errors have the same relation to exceptions. There is additional functionality that exceptions provide ( you can catch them and do stuff) which are not part of an error's interface. Errors should represent unrecoverable situations where the program must terminate. catching an error is, as downs said, a BUG. -- Yigal
Mar 01 2008
== Quote from Yigal Chripun (yigal100 gmail.com)'s articleMy point is that errors have the same relation to exceptions. There is additional functionality that exceptions provide ( you can catch them and do stuff) which are not part of an error's interface. Errors should represent unrecoverable situations where the program must terminate. catching an error is, as downs said, a BUG.So the problem then becomes which errors to classify as non-recoverable. Particularly in a systems language like D, I would be hesitant to dictate that almost any errors must necessarily terminate the program. Consider an array bounds error. This is a system-generated error that clearly indicates a program flaw, and yet the program is still in a valid state. The same could be said of other errors as well. When considering adding an Error class to Tango, I ended up deciding that there were very few if any errors that I felt were non-recoverable in every program where they may occur. Ultimately, it seems to make more sense to leave the decision to the programmer to determine recoverability. If the programmer really wants to generate an error intended to be unrecoverable, he can always throw an Object anyway. Sure, Objects can still be caught, but I think few programs actually do this (outside the catch{} statement anyway). Sean
Mar 01 2008
Sean Kelly wrote:== Quote from Yigal Chripun (yigal100 gmail.com)'s articleWhat you describe is already partly solved in Tango. There are callback functions that allow you as a systems programmer to change the default handler for such errors. so you already realized that these errors and asserts shouldn't be handled by a regular try catch block. to address your example: how can you state that a program with an array bounds error is in valid state? on the contrary, the program accessed an area of memory which it didn't supposed to access. either it read garbage data or worse, it wrote at a random memory location possibly overriding other info stored there. i.e. it is not in a valid state. in C that's usually results in a segmentation fault, which needs to be fixed at debug time. in a running program, would you really want to "catch" such an error and try to recover from it? most likely not. I think that downs' solution is a good one where exception inherits from error . thus, I could catch general Exception objects without worries, and if i need to handle errors in a different way, I can change appropriate handlers. By default, however, asserts and unrecoverable errors must terminate the system. they indicate errors in system logic (i.e. bugs) and should be handled while debugging. in production you can't really recover from an error in system logic. also, I think that the global "Exception" class should come with tracing enabled by default. why would anyone need an exception mechanism without tracing? --YigalMy point is that errors have the same relation to exceptions. There is additional functionality that exceptions provide ( you can catch them and do stuff) which are not part of an error's interface. Errors should represent unrecoverable situations where the program must terminate. catching an error is, as downs said, a BUG.So the problem then becomes which errors to classify as non-recoverable. Particularly in a systems language like D, I would be hesitant to dictate that almost any errors must necessarily terminate the program. Consider an array bounds error. This is a system-generated error that clearly indicates a program flaw, and yet the program is still in a valid state. The same could be said of other errors as well. When considering adding an Error class to Tango, I ended up deciding that there were very few if any errors that I felt were non-recoverable in every program where they may occur. Ultimately, it seems to make more sense to leave the decision to the programmer to determine recoverability. If the programmer really wants to generate an error intended to be unrecoverable, he can always throw an Object anyway. Sure, Objects can still be caught, but I think few programs actually do this (outside the catch{} statement anyway). Sean
Mar 01 2008
also, I think that the global "Exception" class should come with tracing enabled by default. why would anyone need an exception mechanism without tracing?This is an excellent idea! One of my favorite features of D is conditional compilation. With it, you can take advantage of all the high-level debugging tools available in other languages in debug mode, and compile them out in release. And there isn't a debug tool I probably use more than a simple stack trace of where the error occured. Adding this feature to D would make it a lot friendlier to others used to 4th generation languages. In my first class where I learned C, the teacher failed to teach us anything about debuggers. All i knew at the time was Java, and when I first read the words "Segmentation Fault" I stared back with utter horror. Where was my stack trace? Fortunately, since then I learned how to use GDB with the best of them. However, If D provided a default stacktrace of errors in debug mode, then inexperienced systems programmers wouldn't have to go through as much heartache, and the rest of us would save ourselves from having to use a debugger quite so often.
Mar 01 2008
== Quote from Yigal Chripun (yigal100 gmail.com)'s articleSean Kelly wrote:few if== Quote from Yigal Chripun (yigal100 gmail.com)'s articleMy point is that errors have the same relation to exceptions. There is additional functionality that exceptions provide ( you can catch them and do stuff) which are not part of an error's interface. Errors should represent unrecoverable situations where the program must terminate. catching an error is, as downs said, a BUG.So the problem then becomes which errors to classify as non-recoverable. Particularly in a systems language like D, I would be hesitant to dictate that almost any errors must necessarily terminate the program. Consider an array bounds error. This is a system-generated error that clearly indicates a program flaw, and yet the program is still in a valid state. The same could be said of other errors as well. When considering adding an Error class to Tango, I ended up deciding that there were veryseemsany errors that I felt were non-recoverable in every program where they may occur. Ultimately, ittheto make more sense to leave the decision to the programmer to determine recoverability. If the programmer really wants to generate an error intended to be unrecoverable, he can always throw an Object anyway. Sure, Objects can still be caught, but I think few programs actually do this (outsideAssuming that a write actually occurred at that location, if the location were in dynamic memory it would be technically possible to determine whether the written location was an allocated block or if it was an empty/unallocated block. Assuming it's the latter, the program is still in a valid state and may continue. This obviously wouldn't be the norm, but for some applications I might actually consider doing this and recovering if possible.catch{} statement anyway). SeanWhat you describe is already partly solved in Tango. There are callback functions that allow you as a systems programmer to change the default handler for such errors. so you already realized that these errors and asserts shouldn't be handled by a regular try catch block. to address your example: how can you state that a program with an array bounds error is in valid state? on the contrary, the program accessed an area of memory which it didn't supposed to access. either it read garbage data or worse, it wrote at a random memory location possibly overriding other info stored there. i.e. it is not in a valid state. in C that's usually results in a segmentation fault, which needs to be fixed at debug time. in a running program, would you really want to "catch" such an error and try to recover from it? most likely not.I think that downs' solution is a good one where exception inherits from error . thus, I could catch general Exception objects without worries, and if i need to handle errors in a different way, I can change appropriate handlers. By default, however, asserts and unrecoverable errors must terminate the system. they indicate errors in system logic (i.e. bugs) and should be handled while debugging. in production you can't really recover from an error in system logic.I think it depends. Let's say that this is an application that repeatedly polls some external sensor and passes the readings to an event handler. The event handler only accepts a range of values and tests the input parameters against this range within its "in" clause. Let's further assume that it's not crucial for every sample to be processed--say it's a temperature sensor and occasional samples may be thrown out so long as a valid sample is obtained within a specific interval. In this instance, a precondition failure should not cause the system to fail--the system is in a valid and recoverable state, and the bad sample could be thrown out and another obtained. But it's possible that the event code could have come from a third party where this behavior could not be altered, and performing the range check before calling the event may not be possible if this is a virtual call to any one of a collection of events (speaking of which--will we ever get inheritable pre/post-conditions like it says in the spec?).also, I think that the global "Exception" class should come with tracing enabled by default. why would anyone need an exception mechanism without tracing?It does as of the last Tango release. A third-party plug-is is still required to actually generate the trace, but it's not unlikely that we'll bundle these libraries in a future release. That said, I think there are valid reasons why tracing may not be preferable. For one thing, generating a stack trace causes a noticeable application slow-down, at least with flectioned. Unless the trace will be displayed to the user, there's really no reason to have them. Sean
Mar 02 2008
Sean Kelly wrote:It does as of the last Tango release. A third-party plug-is is still required to actually generate the trace, but it's not unlikely that we'll bundle these libraries in a future release. That said, I think there are valid reasons why tracing may not be preferable. For one thing, generating a stack trace causes a noticeable application slow-down, at least with flectioned. Unless the trace will be displayed to the user, there's really no reason to have them. SeanIt would be really nice if the trace included line numbers rather than addresses. Sure, there's addr2line, but it's rather annoying to have to invoke that, so I usually still have to employ tracing code. But that would be much slower. Could you do some sort of lazy evaluation of stack traces? I think the answer is at best 'not without some help from the compiler', since you can catch and rethrow and call functions in between.
Mar 02 2008
Christopher Wright wrote:Could you do some sort of lazy evaluation of stack traces?Unfortunately not. 'finally' blocks, scope(exit), and scoped object dtors can alter the stack, making a lazy trace unreliable. Sean
Mar 02 2008
On 02/03/2008, Yigal Chripun <yigal100 gmail.com> wrote:Errors should represent unrecoverable situationsIt is important that programs that work in Debug mode should also work in Release mode. For example: an ArrayBoundsException is not thrown in Release mode, therefore, it should not be catchable in Debug mode. However, I don't think that making a distinction between Error and Exception is the way to go here. I think a better way would be for ArrayBoundsException to be defined in Phobos as: debug class ArrayBoundsException : Exception That way, if you try to catch one, it will be a /compile-time/ error when you compile your release build. Beyond that, I don't think there should be a distinction. Provided that the axiom "what works in Debug mode also works in Release mode" holds (assuming the source compiles in both builds), there should be no need to make this artificial distinction. For example, if one were to write an operating system in D (a daunting task, but let's pretend to be ambitious for a moment). I would /not/ want an Error thrown by an application to kill the whole operating system. At some level, it has to catch the Error and shut down the errant program. The same may well be true, on a smaller scale, for applications and plugins - or even just trial routines.
Mar 01 2008
Janice Caron wrote:On 02/03/2008, Yigal Chripun <yigal100 gmail.com> wrote:Yeah, but if you simply catch _all_ exceptions, the compiler will never notice the mistake and the program will still crash. I like the idea in principle, but it would probably work better like this debug { class DebugModeException : Object { } // WAS Error class Exception : DebugModeException { } } else { class Exception : Object { } } --feepErrors should represent unrecoverable situationsIt is important that programs that work in Debug mode should also work in Release mode. For example: an ArrayBoundsException is not thrown in Release mode, therefore, it should not be catchable in Debug mode. However, I don't think that making a distinction between Error and Exception is the way to go here. I think a better way would be for ArrayBoundsException to be defined in Phobos as: debug class ArrayBoundsException : Exception That way, if you try to catch one, it will be a /compile-time/ error when you compile your release build.
Mar 02 2008
On 02/03/2008, downs <default_357-line yahoo.de> wrote: <a good idea> You're right. I like your idea better than mine.
Mar 02 2008
downs wrote:Janice Caron wrote:I limes.On 02/03/2008, Yigal Chripun <yigal100 gmail.com> wrote:Yeah, but if you simply catch _all_ exceptions, the compiler will never notice the mistake and the program will still crash. I like the idea in principle, but it would probably work better like this debug { class DebugModeException : Object { } // WAS Error class Exception : DebugModeException { } } else { class Exception : Object { } } --feepErrors should represent unrecoverable situationsIt is important that programs that work in Debug mode should also work in Release mode. For example: an ArrayBoundsException is not thrown in Release mode, therefore, it should not be catchable in Debug mode. However, I don't think that making a distinction between Error and Exception is the way to go here. I think a better way would be for ArrayBoundsException to be defined in Phobos as: debug class ArrayBoundsException : Exception That way, if you try to catch one, it will be a /compile-time/ error when you compile your release build.
Mar 02 2008
== Quote from Janice Caron (caron800 googlemail.com)'s articleFor example, if one were to write an operating system in D (a daunting task, but let's pretend to be ambitious for a moment). I would /not/ want an Error thrown by an application to kill the whole operating system. At some level, it has to catch the Error and shut down the errant program.Right. This is what I was thinking of with my comment about D being a systems programming language. Sean
Mar 02 2008