digitalmars.D - Making Errors errors
- Max Haughton (9/9) Jan 28 2021 It has been discussed in a different thread (Making throwing an
- Adam D. Ruppe (9/14) Jan 28 2021 Here's a crazy idea: when this switch is in place, it just never
- Max Haughton (10/25) Jan 28 2021 Not a bad idea. I think I'll try that first.
- sighoya (21/29) Jan 28 2021 Catastrophic in which sense? To the whole program?
- Paul Backus (4/15) Jan 28 2021 From now on, whenever this topic comes up, I'm just going to post
- sighoya (30/33) Jan 28 2021 I haven't consumed the whole page, but the examples of both
- H. S. Teoh (9/18) Jan 28 2021 [...]
- Paul Backus (16/21) Jan 28 2021 If out-of-bounds array access is defined by the language spec as
- sighoya (13/19) Jan 29 2021 Okay, if out-of-bound exceptions cause UB, then we can neither
- Paul Backus (2/13) Jan 29 2021 "Unrecoverable error" does not mean the same thing as UB.
- Timon Gehr (10/24) Jan 29 2021 Why is that an useful thing to mandate on the language level? I can
- Timon Gehr (4/10) Jan 29 2021 What you seem to ignore here is that it's the language's job to
- Timon Gehr (22/34) Jan 28 2021 Ideally, yes. The handler should not be allowed to return and it would
- Andre Pany (7/16) Jan 28 2021 What would be the effect of this change on the unit test runners
- Max Haughton (6/25) Jan 29 2021 It would need to be a flag, I doubt this will ever be the default
- Timon Gehr (3/19) Jan 29 2021 Even the language itself catches AssertError to implement in contract
- Atila Neves (6/25) Jan 29 2021 Depends on the usage. The reason that unit-threaded catches
- Jacob Carlborg (10/15) Jan 29 2021 I think there are two things that need to take into consideration:
It has been discussed in a different thread (Making throwing an error an instant failure, catching Error etc.) I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler, druntime, c etc.? The rationale makes perfect sense (Errors should indicate something has gone wrong, the program is in an invalid state - by definition you cannot recover), but the exact behaviour must be specified.
Jan 28 2021
On Thursday, 28 January 2021 at 17:59:41 UTC, Max Haughton wrote:I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler, druntime, c etc.?Here's a crazy idea: when this switch is in place, it just never actually honors your catch handlers. so then throw Error is the same as an uncaught exception and thus trigger the debugger at the throw site instantly.(Errors should indicate something has gone wrong, the program is in an invalid state)In real life Errors are rarely this extreme. Most of them indicate that the program *would* get into an invalid state if it proceeded, but since it stopped before actually executing it, things are still fine.
Jan 28 2021
On Thursday, 28 January 2021 at 18:33:17 UTC, Adam D. Ruppe wrote:On Thursday, 28 January 2021 at 17:59:41 UTC, Max Haughton wrote:Not a bad idea. I think I'll try that first. And that may well be true but when I use A assert, for example, I often think of it in the same context as one would in formal verification i.e if this is wrong something catastrophic has happened. If the problem is exceptional but ultimately recoverable use Exceptions. I also feel that, potentially against the grain of Phobos, parsers should not throw - e.g. std.conv probably fails more than it succeeds in many code bases.I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler, druntime, c etc.?Here's a crazy idea: when this switch is in place, it just never actually honors your catch handlers. so then throw Error is the same as an uncaught exception and thus trigger the debugger at the throw site instantly.(Errors should indicate something has gone wrong, the program is in an invalid state)In real life Errors are rarely this extreme. Most of them indicate that the program *would* get into an invalid state if it proceeded, but since it stopped before actually executing it, things are still fine.
Jan 28 2021
On Thursday, 28 January 2021 at 18:47:27 UTC, Max Haughton wrote:I often think of it in the same context as one would in formal verification i.e if this is wrong something catastrophic has happened.Catastrophic in which sense? To the whole program? As mentioned by Adam, logical errors rarely justify whole program abortion. Downstream code doesn't necessarily require computations to succeed on the whole line if it can deal with partial results or provide alternate ways to retrieve missing information.If the problem is exceptional but ultimately recoverable use Exceptions.Not all Exceptions are recoverable especially if we don't know how to deal with. But there may be exemptions silently ignore any kind of exception. The distinction between error and exception is sometimes hard to resolve. Is it a usual error if the document doesn't parse or is it exceptional? I think it all depends on subjective assumptions.I also feel that, potentially against the grain of Phobos, parsers should not throw - e.g. std.conv probably fails more than it succeeds in many code bases.This example seems reiterated infinite times and seems true in most cases as a parser error is just a value to deal with, we don't abort the program immediately, we collect errors in order to display them as a sequence of mistakes. And what to do for cases where aren't interested in any partial results, seldom, but such cases would rather be implemented with exception handling.
Jan 28 2021
On Thursday, 28 January 2021 at 19:39:41 UTC, sighoya wrote:On Thursday, 28 January 2021 at 18:47:27 UTC, Max Haughton wrote:From now on, whenever this topic comes up, I'm just going to post this link: http://joeduffyblog.com/2016/02/07/the-error-model/#bugs-arent-recoverable-errorsI often think of it in the same context as one would in formal verification i.e if this is wrong something catastrophic has happened.Catastrophic in which sense? To the whole program? As mentioned by Adam, logical errors rarely justify whole program abortion. Downstream code doesn't necessarily require computations to succeed on the whole line if it can deal with partial results or provide alternate ways to retrieve missing information.
Jan 28 2021
On Thursday, 28 January 2021 at 19:42:54 UTC, Paul Backus wrote:From now on, whenever this topic comes up, I'm just going to post this link: http://joeduffyblog.com/2016/02/07/the-error-model/#bugs-arent-recoverable-errorsI haven't consumed the whole page, but the examples of both sections (bugs vs recoverable errors) seems to overlap to some extent which justifies the statements I made. It is sometimes very hard to distinguish between bugs and recoverable errors (which mostly aren't recoverable anyway, i.e. the term is confusing). A bug is even misleading here because it doesn't relate to error handling only, the majority of bugs doesn't cause errors just silently change the expected result. A bug is just the mismatch of specification and implementation. It makes sense to model them in language with formal verification requiring the compiler to reject your program if the specification doesn't match the implementation. Given range indexing as an example, we would certainly think of index violations as bugs. That may be true. However, the code following after the random access wouldn't be executed anyway and the caller may or may not depend hard on the result of the code fragment. A better take to go would definitely exclude pessimistically out-of-range-errors and bubble up possible errors on a higher level of understanding but that's even hard to do with (path) dependent typing. The cost is simply too high to support and more overly to adapt such fine-grained modeling. And introducing errors/bugs in addition to exceptions bifurcates your world again in two parts. I know that errors exist in Java productive development or just no one cares about them as their classification as errors is generally debatable.
Jan 28 2021
On Thu, Jan 28, 2021 at 11:41:44PM +0000, sighoya via Digitalmars-d wrote:On Thursday, 28 January 2021 at 19:42:54 UTC, Paul Backus wrote:[...]From now on, whenever this topic comes up, I'm just going to post this link: http://joeduffyblog.com/2016/02/07/the-error-model/#bugs-arent-recoverable-errorsGiven range indexing as an example, we would certainly think of index violations as bugs. That may be true. However, the code following after the random access wouldn't be executed anyway and the caller may or may not depend hard on the result of the code fragment.[...] Actually, in the absence of a range check (in C, or D with -release), code following the access *will* be executed, with undefined behaviour. Also known by the more familiar name "buffer overflow exploit". T -- Why did the mathematician reinvent the square wheel? Because he wanted to drive smoothly over an inverted catenary road.
Jan 28 2021
On Thursday, 28 January 2021 at 23:41:44 UTC, sighoya wrote:Given range indexing as an example, we would certainly think of index violations as bugs. That may be true. However, the code following after the random access wouldn't be executed anyway and the caller may or may not depend hard on the result of the code fragment.If out-of-bounds array access is defined by the language spec as an unrecoverable error, an optimizing compiler is allowed to assume that no program ever recovers from it, and potentially re-order code based on that assumption. So you cannot actually be sure that "the code following after the random access wouldn't be executed." Of course, the key phrase here is "defined by the language spec." As a language designer, you are free to define out-of-bounds indexing as either recoverable or unrecoverable. But as a programmer, once the decision has been made and the spec has been written, you do not get a choice--either you play by the rules, or your code is wrong. I suspect a lot of the confusion on this issue comes from people mixing up the programmer's perspective and the language designer's perspective.
Jan 28 2021
On Friday, 29 January 2021 at 00:39:08 UTC, Paul Backus wrote:If out-of-bounds array access is defined by the language spec as an unrecoverable error, an optimizing compiler is allowed to assume that no program ever recovers from it, and potentially re-order code based on that assumption. So you cannot actually be sure that "the code following after the random access wouldn't be executed."Okay, if out-of-bound exceptions cause UB, then we can neither abort the program entirely because UB now belongs to our semantic or the compiler have to completely reject any way of UB at compile time. I'm a fan of banning any occurrence of UB in a language, rather I prefer things to be implementation defined which is sometimes just not possible because of OS mystery. On the other side, it isn't anyway possible to assure the implementation satisfies the needs of the frontend, e.g. malloc may not allocate memory at all just print a smiley to console. From this point we could define any operation as UB, but it doesn't make that sense...
Jan 29 2021
On Friday, 29 January 2021 at 14:19:02 UTC, sighoya wrote:On Friday, 29 January 2021 at 00:39:08 UTC, Paul Backus wrote:"Unrecoverable error" does not mean the same thing as UB.If out-of-bounds array access is defined by the language spec as an unrecoverable error, an optimizing compiler is allowed to assume that no program ever recovers from it, and potentially re-order code based on that assumption. So you cannot actually be sure that "the code following after the random access wouldn't be executed."Okay, if out-of-bound exceptions cause UB, then we can neither abort the program entirely because UB now belongs to our semantic or the compiler have to completely reject any way of UB at compile time.
Jan 29 2021
On 29.01.21 15:23, Paul Backus wrote:On Friday, 29 January 2021 at 14:19:02 UTC, sighoya wrote:Why is that an useful thing to mandate on the language level? I can always choose to terminate the process if I actually think nothing useful remains to be done after hitting some condition. Even if the error is not recoverable, I might have something to say about how I want the program to not recover. The problem that needs to be solved is that you can catch errors and errors can be thrown from nothrow functions, and Walter does not want to allow exceptional control flow out of nothrow functions, as that defeats one of the reasons why that feature exists in the first place.On Friday, 29 January 2021 at 00:39:08 UTC, Paul Backus wrote:"Unrecoverable error" does not mean the same thing as UB.If out-of-bounds array access is defined by the language spec as an unrecoverable error, an optimizing compiler is allowed to assume that no program ever recovers from it, and potentially re-order code based on that assumption. So you cannot actually be sure that "the code following after the random access wouldn't be executed."Okay, if out-of-bound exceptions cause UB, then we can neither abort the program entirely because UB now belongs to our semantic or the compiler have to completely reject any way of UB at compile time.
Jan 29 2021
On 29.01.21 01:39, Paul Backus wrote:Of course, the key phrase here is "defined by the language spec." As a language designer, you are free to define out-of-bounds indexing as either recoverable or unrecoverable. But as a programmer, once the decision has been made and the spec has been written, you do not get a choice--either you play by the rules, or your code is wrong.What you seem to ignore here is that it's the language's job to accommodate the programmer's use cases, not the other way around and that this is a forum where we discuss changes to the language specification.
Jan 29 2021
On 28.01.21 18:59, Max Haughton wrote:It has been discussed in a different thread (Making throwing an error an instant failure, catching Error etc.) I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler,Ideally, yes. The handler should not be allowed to return and it would be useful if there was some way to allow stack unwinding in code compiled using a special compiler flag. (This requires some support from the compiler, basically the backend has to ignore nothrow in such builds.)druntime,I guess that's the same as the first option, just a bit harder to access.c etc.?I don't think the behavior should be hard-coded into the compiler.The rationale makes perfect sense (Errors should indicate something has gone wrong, the program is in an invalid state - by definition you cannot recover),You may be able to recover if the failure is contained in a nonessential component. Process separation is sometimes a good way to do that, but it may be overkill for some projects.but the exact behaviour must be specified.If the program were truly in an invalid state the behavior would be undefined and immediate termination would by definition be impossible to ensure. That's not always useful though, there's plenty of circumstances where immediately killing the program is not what you want, e.g. if the program was recording a sequence of user inputs that will allow you to reproduce the error. I think the immediate elevation of every bug into an issue that completely undermines the state of the abstract machine is not right for every use case. Those are at different levels of abstraction. Your abstract machine state is still okay even if some access fails a bounds check and if it happens in a nothrow function, there is no way to resume execution after the handler.
Jan 28 2021
On Thursday, 28 January 2021 at 17:59:41 UTC, Max Haughton wrote:It has been discussed in a different thread (Making throwing an error an instant failure, catching Error etc.) I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler, druntime, c etc.? The rationale makes perfect sense (Errors should indicate something has gone wrong, the program is in an invalid state - by definition you cannot recover), but the exact behaviour must be specified.What would be the effect of this change on the unit test runners we have (d-unit, silly, unit-threaded)? This might break their functionality, as they might catch Errors (unit tests calling assert). Kind regards Andre
Jan 28 2021
On Friday, 29 January 2021 at 06:03:08 UTC, Andre Pany wrote:On Thursday, 28 January 2021 at 17:59:41 UTC, Max Haughton wrote:It would need to be a flag, I doubt this will ever be the default - however consider that Phobos at least already doesn't throw asserterrors if you test with release - if we wanted it as a option to be widely used it would just be a part of the test suite like any other feature.It has been discussed in a different thread (Making throwing an error an instant failure, catching Error etc.) I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler, druntime, c etc.? The rationale makes perfect sense (Errors should indicate something has gone wrong, the program is in an invalid state - by definition you cannot recover), but the exact behaviour must be specified.What would be the effect of this change on the unit test runners we have (d-unit, silly, unit-threaded)? This might break their functionality, as they might catch Errors (unit tests calling assert). Kind regards Andre
Jan 29 2021
On 29.01.21 07:03, Andre Pany wrote:On Thursday, 28 January 2021 at 17:59:41 UTC, Max Haughton wrote:Even the language itself catches AssertError to implement in contract inheritance.It has been discussed in a different thread (Making throwing an error an instant failure, catching Error etc.) I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler, druntime, c etc.? The rationale makes perfect sense (Errors should indicate something has gone wrong, the program is in an invalid state - by definition you cannot recover), but the exact behaviour must be specified.What would be the effect of this change on the unit test runners we have (d-unit, silly, unit-threaded)? This might break their functionality, as they might catch Errors (unit tests calling assert).
Jan 29 2021
On Friday, 29 January 2021 at 06:03:08 UTC, Andre Pany wrote:On Thursday, 28 January 2021 at 17:59:41 UTC, Max Haughton wrote:Depends on the usage. The reason that unit-threaded catches errors is to support unit tests written with asserts, since those might even have been written before unit-threaded itself was. The idea is to use the custom assertions. My own projects wouldn't be affected in the slightest, for instance.It has been discussed in a different thread (Making throwing an error an instant failure, catching Error etc.) I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler, druntime, c etc.? The rationale makes perfect sense (Errors should indicate something has gone wrong, the program is in an invalid state - by definition you cannot recover), but the exact behaviour must be specified.What would be the effect of this change on the unit test runners we have (d-unit, silly, unit-threaded)? This might break their functionality, as they might catch Errors (unit tests calling assert). Kind regards Andre
Jan 29 2021
On Thursday, 28 January 2021 at 17:59:41 UTC, Max Haughton wrote:It has been discussed in a different thread (Making throwing an error an instant failure, catching Error etc.) I am starting to put together a patch to try out this behaviour, what do we actually want it to do - should it call a user specified handler, druntime, c etc.?I think there are two things that need to take into consideration: * Currently druntime catches all uncaught exceptions, that is `Throwable`, to be able to print the exception message and a stack trace. * When running unit tests there needs to be safe way to catch whatever `assert` is throwing to be able to continue running other unit tests. druntime relies on this. -- /Jacob Carlborg
Jan 29 2021