Jump to page: 1 28  
Page
Thread overview
Comparing Exceptions and Errors
Jun 04, 2022
Ali Çehreli
Jun 04, 2022
Ali Çehreli
Jun 04, 2022
Sebastiaan Koppe
Jun 04, 2022
Sebastiaan Koppe
Jun 05, 2022
Adam Ruppe
Jun 05, 2022
Adam D Ruppe
Jun 05, 2022
Ali Çehreli
Jun 05, 2022
Sebastiaan Koppe
Jun 05, 2022
Ali Çehreli
Jun 05, 2022
kdevel
Jun 05, 2022
matheus
Jun 05, 2022
Ali Çehreli
Jun 05, 2022
kdevel
Jun 05, 2022
Ali Çehreli
Jun 05, 2022
kdevel
Jun 05, 2022
kdevel
Jun 05, 2022
Ali Çehreli
Jun 04, 2022
Sebastiaan Koppe
Jun 04, 2022
kdevel
Jun 04, 2022
Paul Backus
Jun 04, 2022
kdevel
Jun 05, 2022
Paul Backus
Jun 05, 2022
kdevel
Jun 04, 2022
kdevel
Jun 05, 2022
kdevel
Jun 05, 2022
kdevel
Re: Comparing Exceptions and Errorsj
Jun 06, 2022
Sebastiaan Koppe
Jun 12, 2022
kdevel
Jun 07, 2022
frame
Jun 07, 2022
frame
Jun 07, 2022
Ali Çehreli
Jun 12, 2022
kdevel
Jun 14, 2022
kdevel
Jun 15, 2022
kdevel
Jun 16, 2022
kdevel
Jun 16, 2022
bauss
Jun 16, 2022
kdevel
Jun 16, 2022
bauss
Jun 16, 2022
kdevel
June 03, 2022

During the last beerconf, I wrote a short blog post about how Error and Exception are different, and why you should never continue after catching Errors.

Feedback welcome, I didn't announce here when I wrote it because it's kind of small/insignificant, but maybe it can help newcomers to the language: https://www.schveiguy.com/blog/2022/05/comparing-exceptions-and-errors-in-d/

-Steve

June 03, 2022
On 6/3/22 16:40, Steven Schveighoffer wrote:

> https://www.schveiguy.com/blog/2022/05/comparing-exceptions-and-errors-in-d/ 

Cool! I didn't know catching Errors behaves specially in unittest blocks and contracts.

One feedback I have is about non-main threads. Although everybody agrees that Errors should not be caught, the main thread does so and prints the useful output that you show in the article.

If the main thread is allowed to do that, we should do as much (or less) in non-main threads as well. Otherwise, threads disappear without a trace.

If we are paranoid and want to do as little as possible, at least we should attempt to copy a string literal to stderr. Something like "Thread exiting with Error." And exit(1) right after that.

But all of that is wishful programming because if the program is in an illegal state, should we attempt to report it? If we should not, shouldn't the main thread should not either? (Sorry, non-native Inglish speaker here. :p)

Ali
June 03, 2022

On 6/3/22 8:44 PM, Ali Çehreli wrote:

>

One feedback I have is about non-main threads. Although everybody agrees that Errors should not be caught, the main thread does so and prints the useful output that you show in the article.

Yes, the one exception to the no-catch error rule is to print/log diagnostic information. But you should never continue executing after that.

>

If the main thread is allowed to do that, we should do as much (or less) in non-main threads as well. Otherwise, threads disappear without a trace.

If a thread does not catch an error and end the program, that's a defect in druntime I think. If it tries to rethrow the exception in the main thread (oh, man I have to check... Yeah, this is what it does), then it's entirely possible that the main thread will never even get to the Error!

>

If we are paranoid and want to do as little as possible, at least we should attempt to copy a string literal to stderr. Something like "Thread exiting with Error." And exit(1) right after that.

Yes, that is what it should do.

>

But all of that is wishful programming because if the program is in an illegal state, should we attempt to report it? If we should not, shouldn't the main thread should not either? (Sorry, non-native Inglish speaker here. :p)

It's useful to do something, so it's not just an empty log file with no idea where the error occurred.

I've thought in the past that throwing an error really should not throw, but log the error (including the call stack), and then exit without even attempting to unwind the stack. But code at least expects an attempt to throw the Error up the stack, so code that is expecting to catch it would break.

-Steve

June 03, 2022
On 6/3/22 18:17, Steven Schveighoffer wrote:

> If a thread does not catch an error and end the program

No, the thread dies and the main thread doesn't know anything about it. Unless if std.concurrency is being used and the main thread looks for and receives a LinkTerminated message. (If spawnLinked was used to start the thread.)

But still, there is no trace of the Error. So I do the following in my thread functions:

void myThread() {
  try {

  } catch (Exception exc) {
     // ...

  } catch (Error exc) {
    // Report on stderr
    exit(1); // Yes, takes down the main thread.
             // Could choose to do otherwise...
  }
}

Ali

June 04, 2022

On Friday, 3 June 2022 at 23:40:50 UTC, Steven Schveighoffer wrote:

>

During the last beerconf, I wrote a short blog post about how Error and Exception are different, and why you should never continue after catching Errors.

Feedback welcome, I didn't announce here when I wrote it because it's kind of small/insignificant, but maybe it can help newcomers to the language: https://www.schveiguy.com/blog/2022/05/comparing-exceptions-and-errors-in-d/

-Steve

Here my feedback:

  1. What if div is called with x = -2147483648 and y = -1? Isn't code
    which allows a divisor == 0 to propagate to the CPU an error? Must
    the code thus not throw an object instantiated from a subclass of Error?

    What if I have that function div used in code which is called from say
    controller code of a CGI binary. Or likewise from a vibe.d-thread servicing
    a web request? How do I isolate that fault? Do I have to spawn a subprocess
    as Walter suggested in the case of memory corruption [1]?

    [This is of course all rhetorical!]

  2. Since 2017 or so I have written some 10 KLOC of D, maybe about two dozen
    classes deriving from Exception. But I did not annotate any of my methods or
    function with "nothrow" nor did I author any class deriving from Error.

    What does that mean? Am I Error blind?

  3. Can you provide some piece of code which must throw Error and cannot
    throw an appropriate Exception?

[1] http://forum.dlang.org/post/t6ef8c$1cu5$1@digitalmars.com
Re: Why is D unpopular?

June 04, 2022

On Saturday, 4 June 2022 at 11:57:32 UTC, kdevel wrote:

>
  1. Since 2017 or so I have written some 10 KLOC of D, maybe about two dozen
    classes deriving from Exception. But I did not annotate any of my methods or
    function with "nothrow" nor did I author any class deriving from Error.

    What does that mean? Am I Error blind?

Generally you do not need to subclass Error yourself. The most common way of throwing an Error in user code is to use assert, which (with default compiler flags) throws an AssertError on failure. Function contracts and struct/class invariants work the same way.

>
  1. Can you provide some piece of code which must throw Error and cannot
    throw an appropriate Exception?

This is entirely a question of API design. If it should be the caller's responsibility to check for some condition before calling the function, then you can throw an Error when that condition does not hold (or more likely, use an assert or an in contract to check for it). If it should be the callee's responsibility to check, you should throw an Exception (or use enforce).

June 04, 2022

On Saturday, 4 June 2022 at 01:17:28 UTC, Steven Schveighoffer wrote:

>

I've thought in the past that throwing an error really should not throw, but log the error (including the call stack), and then exit without even attempting to unwind the stack. But code at least expects an attempt to throw the Error up the stack, so code that is expecting to catch it would break.

This is too harsh for a service that is read-only, meaning a service that only read from a database and never writes to it. All running threads have to be given a chance to exit gracefully, at the very minimum.

What is the source for these errors anyway? A filesystem not responding? A crashed device driver? A race condition? A deadlock? Starvation? Many sources for errors can be recovered from by rescheduling in a different order at a different time.

What I'd like to see is a fault tolerant 100% @safe actor pattern with local per-actor GC. By fault tolerant I mean that the actor is killed and then a new actor is rescheduled (could be an alternative "reference" implementation or the same after a time delay).

Also, what it is the purpose of @safe if you have to kill all threads? Such rigidity will just make Go look all the more attractive for service providers!

June 04, 2022

On 6/4/22 7:57 AM, kdevel wrote:

>

On Friday, 3 June 2022 at 23:40:50 UTC, Steven Schveighoffer wrote:

>

During the last beerconf, I wrote a short blog post about how Error and Exception are different, and why you should never continue after catching Errors.

Feedback welcome, I didn't announce here when I wrote it because it's kind of small/insignificant, but maybe it can help newcomers to the language: https://www.schveiguy.com/blog/2022/05/comparing-exceptions-and-errors-in-d/

Here my feedback:

  1. What if div is called with x = -2147483648 and y = -1? Isn't code
       which allows a divisor == 0 to propagate to the CPU an error? Must
       the code thus not throw an object instantiated from a subclass of Error?

Well, that is just a toy example to show code that might use an Error. It's not intended to be a fully-fleshed-out function. I recommend simply using the divide operator in real code.

The point of an Error is that your code can assume it cannot happen. If it does happen, the code is invalid. This is reflected in the fact that the compiler will omit cleanup code if an Error is thrown (it can assume that it will never happen). The point of using Error is for a last resort check for program correctness (because you failed to validate the input before getting to that point).

>

   What if I have that function div used in code which is called from say
   controller code of a CGI binary. Or likewise from a vibe.d-thread servicing
   a web request? How do I isolate that fault? Do I have to spawn a subprocess
   as Walter suggested in the case of memory corruption [1]?

   [This is of course all rhetorical!]

vibe should exit the process if an Error is thrown. There is a version you can specify to have it catch Error, but it would only be for debugging. https://vibed.org/docs#compile-time-configuration (see VibeDebugCatchAll)

One thing that always bugs me in my vibe code is out of bounds errors for arrays. I actually replaced some arrays with an Exception throwing wrapper because I didn't want to crash the whole server for certain cases, and I didn't want to continuously validate array indexes.

>
  1. Since 2017 or so I have written some 10 KLOC of D, maybe about two dozen
       classes deriving from Exception. But I did not annotate any of my methods or
       function with "nothrow" nor did I author any class deriving from Error.

   What does that mean? Am I Error blind?

As long as you aren't catching Throwable or Error, you should be fine. Simply not marking things nothrow doesn't mean that they won't be inferred nothrow. auto and template functions are inferred.

In practice, there are probably very very few places where this can bite you. Which also means, if it does bite, it's going to be really really hard to track down.

>
  1. Can you provide some piece of code which must throw Error and cannot
       throw an appropriate Exception?

As Paul said, this is up to your API. If you specify that you assume the inputs to the function are cleansed, then you can correctly throw an Error if they are out of spec.

A great example are range functions. Often times you see at the beginning of any popFront method the statement assert(!empty);. This is universally accepted, as you shouldn't be calling popFront if you haven't checked for empty.

-Steve

June 04, 2022

On Saturday, 4 June 2022 at 14:19:22 UTC, Ola Fosheim Grøstad wrote:

>

Also, what it is the purpose of @safe if you have to kill all threads? Such rigidity will just make Go look all the more attractive for service providers!

I agree with this, but given the current semantics there is nothing else to do but teardown everything upon first sight of Error.

The reasoning is simple: Error + nothrow will sidestep any RAII you may have. Since you cannot know what potentially wasn't destructed, the only safe course of action is to abandon ship.

Yes, in plenty of cases that is completely overkill.

Then again, programs should be written to not assert in the first place.

Considering most asserts I have seen are either due to a bad api or just laziness - and shouldn't have to exist in the first place - maybe it's not that bad.

June 04, 2022

On Saturday, 4 June 2022 at 01:17:28 UTC, Steven Schveighoffer wrote:

>

If a thread does not catch an error and end the program, that's a defect in druntime I think. If it tries to rethrow the exception in the main thread (oh, man I have to check... Yeah, this is what it does), then it's entirely possible that the main thread will never even get to the Error!

Yes, for that reason, and others, people should not use that api.

> >

If we are paranoid and want to do as little as possible, at least we should attempt to copy a string literal to stderr. Something like "Thread exiting with Error." And exit(1) right after that.

Yes, that is what it should do.

Probably yes.

« First   ‹ Prev
1 2 3 4 5 6 7 8