nothrow by default

Gregor Mückl gregormueckl at gmx.de
Sun Jan 5 12:27:11 UTC 2020


On Sunday, 5 January 2020 at 10:32:23 UTC, Johannes Pfau wrote:
>    The benefits now are simple: Implementation code / memory 
> overhead is
>    almost zero, no TypeInfo required, trivial to implement on 
> embedded
>    systems, .... At the same time, exceptions bubble up 
> properly so they
>    can't be accidentially unhandled. The runtime overhead in 
> the success
>    case is obviously higher than for some exception systems, 
> but it's
>    only a simple conditional jump. It is cheaper than manual 
> error codes,
>    as we reuse the same registers for return value and error 
> code,
>    benefitting register allocation. Error propagation also uses 
> the same
>    registers in all functions and is therefore very efficient.
>

Consulting Agner Fox's microarchitecture manual, current Intel 
CPUs still take a performance hit when encountering code with a 
high density of conditional branches. They are sensitive to the 
number of branch instructions per cache line. I've seen GCC pad 
code with NOPs for that reason. AMD's branch predictor, on the 
other hand, is described as perceptron that fares better with 
repeated patterns of branches and isn't tied to the cache. Branch 
mispredictions still hurt a lot (~20 cycles). All 
microcontrollers I'm familiar stall their pipeline on every 
branch if they're pipelined at all.

Moving error handling overhead back into the common/fast code 
path is a step backwards in those cases where performance 
matters. Desktops and servers can absolutely afford to have the 
data overhead associated with exceptions and they benefit the 
most from out of band error handling.

It would be nice to have choice here.

> 2) (Optional): Herb arguest that because of throw ... it is 
> easy to spot
>    where an exception originates, but it's more difficult to 
> find where
>    an exception was propagated. As a solution,
>    whenever calling a throws function, the calls should be 
> preceeded by
>    throw:
>    auto value = throw myThrowingFunction();
>    Here throw does essentially this: If myThrowingFunction 
> threw, rethrow
>    the exception. Otherwise return the return value.
>

I hope that this doesn't require code to have a throw keyword in 
every other line. Imagine outer functions of some algorithm where 
the inner functions have a lot of opportunity to fail:

auto result1 = throw step1();
auto result2 = throw step2(result1);
// etc...

The value of the keyword decreases rapidly with the number of 
occurrences.

> 3) (C++ specific): Error codes instead of exceptions, "Type 
> based Errors":
>    I don't really know what is meant by this "Type-Based Errors"
>    terminology, seems to be a C++ marketing thing ("we do 
> everything with
>    types now")... The important takeaway is to not allocate 
> complex
>     exception objects. Use the error code and context value. If 
> really
>    more context than one word is necessary, it's still possible 
> to stuff
>    a pointer into context.
>

There's recently been a talk about error types in C++ and their 
evolution:

https://www.youtube.com/watch?v=coBz_CQ1tJ8&

As with everything in C++, there's a lot of complexity.

>
> Caveats:
> * I have not thought about how exception chaining fits into all 
> this.

This would require an exception to be allocated that starts the 
chain. The error return value could then turn into a pointer to 
that value. That's similar to how the C++ proposals return 
exceptions in error value returning functions.

> * These exceptions do not naturally propagate through foreign 
> language
>   interfaces, although I think we don't guarantee this in D 
> right now
>   either.

D exceptions and C++ exception implementations are currently 
quite incompatible, but the documentation still states that that 
is an eventual goal of D:

https://dlang.org/spec/cpp_interface.html#exception-handling



More information about the Digitalmars-d mailing list