[OT] - C++ exceptions are becoming more and more problematic

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Feb 25 00:30:49 UTC 2022


On Thu, Feb 24, 2022 at 11:59:56PM +0000, meta via Digitalmars-d wrote:
[...]
> Nobody said to verbatim copy what C does, I personally explicitly said
> to take that idea and evolve it, just like the newer modern languages
> are properly doing (Go, Zig, Rust, Odin)

Go, Zig, Rust, and Odin all require explicit checking for error returns.
This makes them suffer from exactly the same problem as my C example:
after every single function call you must explicitly check for error
conditions.  It doesn't matter what the implementation mechanism is,
whether it's an int return, or a sum type, or a discriminated union, or
a second return value. The point is that you have to check this error
code *explicitly*, on *every single function call*.

This kind of error handling approach is fundamentally flawed because it
incentivizes programmers to do the absolute minimum they can to shove
the error under the carpet so that they can get on with making progress
in the problem domain. Like ignore the error return value if they can,
write generic "if error ignore it" boilerplate around their code.  Or
just suffer from .unwrap hell.  It clutters code with error-handling
paraphrenalia, making it needlessly verbose, and less composable.

For example, if you have function f that calls g and h, and g and h have
their own set of possible error enums, then what should f return?  You
either create yet another enum that subsumes both (and the caller then
has the hairy task of making sense of which error codes comes from where
and what to do with it), or, if you have to do this for all 65,535
functions in your entire codebase, just give up and go to a global
binary {ok, fail} enum. Or, to harken back to my C example, OK and
INTERNAL_ERR, which is where all return-code-based error handling
inevitably gravitates towards. Which is about as useful as a BSOD every
time the program encounters the slightest difficulty.

A thrown exception allows most code to eliminate all error-handling
paraphrenalia, making code more readable and maintainable, and at the
same time any actual errors are not ignored by default, you have to
handle them somewhere up the call stack. And the exception contains
specific information about the problem, not just the equivalent of
INTERNAL_ERR (or worse, that stinky antipattern of storing an error
message in a global variable that you then have to call some API
function to extract).


> Tagged Unions, Multiple return type, enum/type inference, constructs
> to bubble up things etc.. we must move forward!

I've yet to see a convincing example of error handling based on tagged
unions / multiple returns / etc., that doesn't suffer from the explicit
handling problem I describe above.  If you have one, please enlighten
me.


> I suspect in the near future, exception handling will be seen as very
> bad practice, if not already, we must prepare..

I've always been a skeptic of reacting to hypothetical futures that have
not be proven is inevitable.


> We no longer live in an era with single cores!

Nobody has yet answered my initial question about whether D's exception
throwing mechanism holds a global lock, which is the primary issue
identified in the OP's linked article.  Until this question is answered,
all this talk about exceptions being bad for multi cores is just beating
a strawman.  It's tantamount to saying, since the global lock in C++
exceptions causes performance problems, exceptions must therefore be bad
(even when no global lock exists).  It's a non sequitur.  The problem
observed in the article is caused by the global lock, not by exceptions
per se.  (And whether exceptions in and of themselves necessitate a
global lock has not yet been established.)


T

-- 
May you live all the days of your life. -- Jonathan Swift


More information about the Digitalmars-d mailing list