Date: Thu, 29 Apr 2021 10:05:40 +0100
On Thu, 29 Apr 2021 at 04:44, Jason McKesson via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Wed, Apr 28, 2021 at 3:23 PM Andrey Semashev via Std-Proposals
> > IMO, exceptions thrown by the standard library are close to useless. Not
> > in least part for the poor QoI of the standard libraries in this regard,
> > as many of them don't produce an informative error message with any
> > relevant information. Also because the standard library cannot provide
> > any context-specific details about the error (i.e. std::vector::at
> > cannot know what the vector is and where the index comes from, only the
> > caller knows that and can provide that information in the log). For this
> > reason, you should normally code so that you check the necessary
> > preconditions in your code before calling the standard library, and then
> > call standard library methods that don't throw.
>
> They are very useless... if you're using them for logging. If you're
> using them for *error handling*, then they're fine. `vector::at`
> doesn't need to know what the vector is or what the index means. The
> code catching the exception is the one who has that context.
>
> If the only people who catch exceptions are far away from the source
> and have no meaningful context to the source of that exception, then
> yes these exceptions are not particularly useful. But that's a matter
> of how you choose to use them.
>
> For example, let's say you're using some algorithm like
> `std::generate` to build some container from raw materials. And in the
> lambda that's generating values, you're accessing a vector. And you
> know that, if an index is out of bounds, then you want to terminate
> the building of the container. You *could* have the lambda set some
> flag on an out-of-bounds index and make dummy objects to fill out the
> rest of the container.
>
> Or you could just use `vector::at`, and have the code that invoked
> `std::generate` catch the exception. There's no loss of context or
> meaning; an exception was thrown and the receiver knows what to do
> with it.
>
Or, in other words, using exceptions as control flow. That's not how we use
exceptions (if early exit is desired, we won't use std::generate but will
instead break out of a for loop or return early from an iife), but fine, if
you really want to do that - though wouldn't it impair parallelisation?
If the exception bubbles out into an application author's catch block, I
hope you will recognize that a stacktrace now becomes essential, since the
fact that it was uncaught constitutes a bug; and since it was intended to
be caught and was not, it lacks any useful information for the application
author to debug with.
This situation only becomes a problem if you try to use exceptions
> outside of this local context. Like if the above code didn't catch the
> exception, but allowed it to bubble up to the outside process who has
> no idea that there's even a `vector` involved, let alone that an index
> was out of bounds.
>
> And indeed, this is one of the biggest arguments against making
> exceptions have stack traces. When you're using local exception
> handling like this, a stack trace is utterly useless. You're not using
> an exception to signal the failure of an entire operation (where the
> only resolution is to log the failure and move on to some other
> operation); you're using it to signal a failure of something tiny.
>
> So having a specific exception type specifically to mean "whole
> operation failure", and thereby include things like stack traces make
> sense.
>
That seems backwards; if an exception used for control flow bubbles out to
an application catch block it very definitely needs a stacktrace attached.
std-proposals_at_[hidden]> wrote:
> On Wed, Apr 28, 2021 at 3:23 PM Andrey Semashev via Std-Proposals
> > IMO, exceptions thrown by the standard library are close to useless. Not
> > in least part for the poor QoI of the standard libraries in this regard,
> > as many of them don't produce an informative error message with any
> > relevant information. Also because the standard library cannot provide
> > any context-specific details about the error (i.e. std::vector::at
> > cannot know what the vector is and where the index comes from, only the
> > caller knows that and can provide that information in the log). For this
> > reason, you should normally code so that you check the necessary
> > preconditions in your code before calling the standard library, and then
> > call standard library methods that don't throw.
>
> They are very useless... if you're using them for logging. If you're
> using them for *error handling*, then they're fine. `vector::at`
> doesn't need to know what the vector is or what the index means. The
> code catching the exception is the one who has that context.
>
> If the only people who catch exceptions are far away from the source
> and have no meaningful context to the source of that exception, then
> yes these exceptions are not particularly useful. But that's a matter
> of how you choose to use them.
>
> For example, let's say you're using some algorithm like
> `std::generate` to build some container from raw materials. And in the
> lambda that's generating values, you're accessing a vector. And you
> know that, if an index is out of bounds, then you want to terminate
> the building of the container. You *could* have the lambda set some
> flag on an out-of-bounds index and make dummy objects to fill out the
> rest of the container.
>
> Or you could just use `vector::at`, and have the code that invoked
> `std::generate` catch the exception. There's no loss of context or
> meaning; an exception was thrown and the receiver knows what to do
> with it.
>
Or, in other words, using exceptions as control flow. That's not how we use
exceptions (if early exit is desired, we won't use std::generate but will
instead break out of a for loop or return early from an iife), but fine, if
you really want to do that - though wouldn't it impair parallelisation?
If the exception bubbles out into an application author's catch block, I
hope you will recognize that a stacktrace now becomes essential, since the
fact that it was uncaught constitutes a bug; and since it was intended to
be caught and was not, it lacks any useful information for the application
author to debug with.
This situation only becomes a problem if you try to use exceptions
> outside of this local context. Like if the above code didn't catch the
> exception, but allowed it to bubble up to the outside process who has
> no idea that there's even a `vector` involved, let alone that an index
> was out of bounds.
>
> And indeed, this is one of the biggest arguments against making
> exceptions have stack traces. When you're using local exception
> handling like this, a stack trace is utterly useless. You're not using
> an exception to signal the failure of an entire operation (where the
> only resolution is to log the failure and move on to some other
> operation); you're using it to signal a failure of something tiny.
>
> So having a specific exception type specifically to mean "whole
> operation failure", and thereby include things like stack traces make
> sense.
>
That seems backwards; if an exception used for control flow bubbles out to
an application catch block it very definitely needs a stacktrace attached.
Received on 2021-04-29 04:05:53