July 08, 2018
On Saturday, 7 July 2018 at 01:18:21 UTC, wjoe wrote:
> But that's not how D works. It throws an Error which can be caught.
>
> If people are allowed to do something they assume it's legitimate.
>
> It should be a compile time error to catch an Error, but it doesn't even emit a warning and it seems to work well which is probably proof enough for people to assume it's good.

I got myself so tangled up in knots with the equivalent in Ruby.... You can "rescue" the base Exception class... which initially I did everywhere to try give better error messages...

Which more often than not would result in everything going weird and insane instead of useful.

Eventually I replaced _every_ "rescue Exception" with "rescue StandardError" and life improved majorly.

Seriously folks, trying to "catch and handle" a programming bug leads to the very dark side of life.

Especially in a 'C/C++/D" like language where the exception is concrete evidence that the system is _already_ in an undefined and unreliable state.
July 08, 2018
On Sunday, 8 July 2018 14:55:15 MDT John Carter via Digitalmars-d wrote:
> On Saturday, 7 July 2018 at 01:18:21 UTC, wjoe wrote:
> > But that's not how D works. It throws an Error which can be caught.
> >
> > If people are allowed to do something they assume it's legitimate.
> >
> > It should be a compile time error to catch an Error, but it doesn't even emit a warning and it seems to work well which is probably proof enough for people to assume it's good.
>
> I got myself so tangled up in knots with the equivalent in Ruby.... You can "rescue" the base Exception class... which initially I did everywhere to try give better error messages...
>
> Which more often than not would result in everything going weird and insane instead of useful.
>
> Eventually I replaced _every_ "rescue Exception" with "rescue StandardError" and life improved majorly.
>
> Seriously folks, trying to "catch and handle" a programming bug leads to the very dark side of life.
>
> Especially in a 'C/C++/D" like language where the exception is concrete evidence that the system is _already_ in an undefined and unreliable state.

I agree, though I'm increasingly of the opinion that we would have been better off just printing out the debug information at the call site and then killing the program with a HLT (or whatever the appropriate instruction would be) so that a core dump gets generated right there. It makes the program far more debuggable in situations where the problem is not easily reproduced, and it avoids the entire issue of whether it's okay to catch Error or Throwable. What we have instead is a situation where someone can catch something that they shouldn't be catching (thus putting their program in an even more invalid state), and when the program exits, we've lost the program state from the point of the failure.

- Jonathan M Davis



July 09, 2018
On 2018-07-08 22:55, John Carter wrote:
> On Saturday, 7 July 2018 at 01:18:21 UTC, wjoe wrote:
>> But that's not how D works. It throws an Error which can be caught.
>>
>> If people are allowed to do something they assume it's legitimate.
>>
>> It should be a compile time error to catch an Error, but it doesn't even emit a warning and it seems to work well which is probably proof enough for people to assume it's good.
> 
> I got myself so tangled up in knots with the equivalent in Ruby.... You can "rescue" the base Exception class... which initially I did everywhere to try give better error messages...
> 
> Which more often than not would result in everything going weird and insane instead of useful.
> 
> Eventually I replaced _every_ "rescue Exception" with "rescue StandardError" and life improved majorly.

There's even a SyntaxError exception class (inheriting from Exception), which you do not want to catch.

-- 
/Jacob Carlborg
July 09, 2018
On Tuesday, 3 July 2018 at 04:54:46 UTC, Walter Bright wrote:
> On 7/2/2018 7:53 PM, John Carter wrote:
>>> Step 2 is to (gradually) migrate std:: standard library precondition violations in particular from exceptions (or error codes) to contracts. The programming world now broadly recognizes that programming bugs (e.g., out-of-bounds access, null dereference, and in general all pre/post/assert-condition violations) cause a corrupted state that cannot be recovered from programmatically, and so they should never be reported to the calling code as exceptions or error codes that code could somehow handle.
>> 
>> Ah, that's a really nice statement.
>
> So, I have finally convinced the C++ world about that! Now if I can only convince the D world :-)
>
> (I'm referring to the repeated and endless threads here where people argue that yes, they can recover from programming bugs!)

If this is the case then why do we need a reboot switch? Never say never!

If you really believe this then why do you print out minimal debug information when an error occurs? If programming bugs were essentially fatal, then wouldn't be important to give as much information when they occur so they can easily be fixed so they do not happen again?

Having too much information is a good thing!

July 10, 2018
On Monday, 9 July 2018 at 22:50:07 UTC, Mr.Bingo wrote:
> On Tuesday, 3 July 2018 at 04:54:46 UTC, Walter Bright wrote:
>> On 7/2/2018 7:53 PM, John Carter wrote:
>>>> Step 2 is to (gradually) migrate std:: standard library precondition violations in particular from exceptions (or error codes) to contracts. The programming world now broadly recognizes that programming bugs (e.g., out-of-bounds access, null dereference, and in general all pre/post/assert-condition violations) cause a corrupted state that cannot be recovered from programmatically, and so they should never be reported to the calling code as exceptions or error codes that code could somehow handle.
>>> 
>>> Ah, that's a really nice statement.
>>
>> So, I have finally convinced the C++ world about that! Now if I can only convince the D world :-)
>>
>> (I'm referring to the repeated and endless threads here where people argue that yes, they can recover from programming bugs!)
>
> If this is the case then why do we need a reboot switch? Never say never!
>
> If you really believe this then why do you print out minimal debug information when an error occurs? If programming bugs were essentially fatal, then wouldn't be important to give as much information when they occur so they can easily be fixed so they do not happen again?
>
> Having too much information is a good thing!

I have learnt some very hard and painful lessons over the last few years of working on an embedded device without an MMU.

The chief one is that relying on corrupted services, which are in an undefined state, are a startling Bad Thing to use to extract and record information.

It's a toss up as to whether the information extraction routine will crash or loop or produce garbage, and whether the routine that records the crash information crashes, or loops or records garbage.

The solution is to extract and stash only that information using services you can verify line by line.

ie. If it is possible it may be corrupted (eg. heap, RTOS services) don't use it.

Then reboot to put it into a defined state, and then persist the information.

With an MMU life is easier... you can rely on the kernel to take a coredump and persist that for you. But again, that is "outside" the run time of the program.

> Having too much information is a good thing!

Not if it is garbage, or crashes, or freezes the system because the services it uses are corrupt. Then its a Very Very Bad Thing.

The best approach I have found is to "crash early and often".

Seriously.

The earlier in the execution path you find the defect and fix it, the more robust your system will be.

Nothing creates flaky and unreliable systems more than allowing them to wobble on past the first point where you already know that things are wrong.
July 09, 2018
On 7/9/2018 6:50 PM, John Carter wrote:
> Nothing creates flaky and unreliable systems more than allowing them to wobble on past the first point where you already know that things are wrong.

Things got so bad with real mode DOS development that I rebooted the system every time my program crashed, making for rather painfully slow development.

Salvation came in the form of OS/2 (!). Although OS/2 was a tiny market, it was a godsend for me. I developed all the 16 bit code on OS/2, which had memory protection. Only the final step was recompiling it for real mode DOS.
July 10, 2018
On Sunday, 8 July 2018 at 20:55:15 UTC, John Carter wrote:
> On Saturday, 7 July 2018 at 01:18:21 UTC, wjoe wrote:
>> But that's not how D works. It throws an Error which can be caught.
>>
>> If people are allowed to do something they assume it's legitimate.
>>
>> It should be a compile time error to catch an Error, but it doesn't even emit a warning and it seems to work well which is probably proof enough for people to assume it's good.
>
> I got myself so tangled up in knots with the equivalent in Ruby.... You can "rescue" the base Exception class... which initially I did everywhere to try give better error messages...
>
> Which more often than not would result in everything going weird and insane instead of useful.
>
> Eventually I replaced _every_ "rescue Exception" with "rescue StandardError" and life improved majorly.
>
> Seriously folks, trying to "catch and handle" a programming bug leads to the very dark side of life.
>
> Especially in a 'C/C++/D" like language where the exception is concrete evidence that the system is _already_ in an undefined and unreliable state.

I'll keep that advice in mind.

In case of the program I made with std.concurrency, I did not catch Throwable to try to recover, but to be able to debug the cause because there was no stack trace printed out or any indication at all that something went wrong. And because the debugger wouldn't break on anything either and a catch block at least allowed for setting a breakpoint there it seemed like an idea.
A catch all Exception didn't trigger and the thread still just vanished. So I just gave it a shot and broadened that to Throwable to rule out this case, too, and sure enough an Error was caught.

Would have been a lot easier to debug if that Error brought down the whole thing with it and then there wouldn't have been a reason to catch Throwable in the first place.

Except, a D program which is terminated by the D runtime via Error mechanism, at least on Linux, prints an Error with a stack trace and then exits with code 1. That's a normal exit since positive exit codes are supposed to be handled by the caller something akin to success, or file not found.
In my opinion this behavior is a defect in the D runtime. It should abort abnormally and indicate that fact with an exit code of -6, or the OS equivalent of SIGABRT.

It is really annoying if you run the program in a debugger, too, which simply tells you the program exited normally and you can't walk the stack trace, print variables, etc.

The behavior on segfault is identical to a C program (exit code -11, SIGSEGV), but this is probably because the OS terminates the program before the runtime gets any opportunity to throw an Error. Meaning you don't get a stack trace, however a debugger breaks exactly at the offending line in the source code.

Before Jonathan's explanation on how the Error mechanism works I had considered abusing the Error mechanism to do some cleanup of secrets in memory (cached passwords or some such) in case of an abnormal termination, etc. - the reasoning being it's possible and if it can reliably print a stack trace, why couldn't it do some zeroing of RAM prior to that, right?
But thinking about it some more, all the things I would have considered doing in a catch Error block can be solved without catching.
If catch *Error{} would be a compile time error, I would have just accepted the fact and came up with alternatives all the same. Saving him a lot of nerves in the process. So, thanks again, Jonathan, for bearing with me :) Much appreciated!

Considering the implications, it really baffles me that there isn't so much as a warning when the compiler encounters: catch *Error...
July 10, 2018
On Mon, Jul 09, 2018 at 11:37:59PM -0700, Walter Bright via Digitalmars-d wrote:
> On 7/9/2018 6:50 PM, John Carter wrote:
> > Nothing creates flaky and unreliable systems more than allowing them to wobble on past the first point where you already know that things are wrong.
> 
> Things got so bad with real mode DOS development that I rebooted the system every time my program crashed, making for rather painfully slow development.
[...]

The saving grace to real mode DOS was that rebooting was so fast.  Sad to say, modern OSes are horribly slow and inefficient at booting up.  So much for progress.


T

-- 
No! I'm not in denial!
July 10, 2018
On 03.07.2018 06:54, Walter Bright wrote:
> ...
> 
> (I'm referring to the repeated and endless threads here where people argue that yes, they can recover from programming bugs!)

Which threads are those?
July 10, 2018
On Tuesday, 10 July 2018 13:21:28 MDT Timon Gehr via Digitalmars-d wrote:
> On 03.07.2018 06:54, Walter Bright wrote:
> > ...
> >
> > (I'm referring to the repeated and endless threads here where people argue that yes, they can recover from programming bugs!)
>
> Which threads are those?

Pretty much any thread arguing for having clean-up done when an Error is thrown instead of terminating ASAP. Usually, folks don't try to claim that trying to fully continue the program in spite of the Error is a good idea, but even that gets suggested sometimes (e.g. trying to catch and recover from a RangeError comes up periodically).

- Jonathan M Davis