The solution to "Error handling"...
Dennis
dkorpel at gmail.com
Fri Jul 3 23:08:26 UTC 2026
...is testing your software. 😉
There's no shortage of interesting discussions about Error vs.
Exception, throwing vs returning, floating point NaN, UTF
replacement chars, or the 'correct' error handling mechanism in
general.
The CPU doesn't care about any of this, it just executes
instructions to move memory around. The user doesn't care about
any of this either, they just want a program that gets the job
done. Your task as a programmer is to generate the CPU
instructions that do the job the user wants as best as you can.
If you find an abstraction that helps handling errors, then use
it by all means. But beware that premature abstractions always
get things wrong. It's easier to write straightforward code first
and see which repetitive patterns naturally emerge from that.
The other day my X11 desktop application failed to create a
graphics context, and as a result it printed a crappy error
message and crashed. But wait, I thought I was meticulously
checking the return values of al my `glx` calls and returning
gracefully? Turns out that before returning the `null` context,
X11 calls a default error callback that prints something to the
console and aborts. To fix the bad UX, I set `XSetErrorHandler`
to my own callback and printed a better error message instead.
AHA! X11 has a C interface, so this is all the fault of C's lack
of good error handling language features. If only they used
Exceptions, right? Well, the browser version of my app (running
on top of Javascript APIs) also likes to randomly error, for
example when the CDN provides and old cached .wasm module instead
of the new one. The result: a flooded browser console (which is
hidden by default), while the page stays blank and unresponsive.
If you catch an Exception and simply show the message in a GUI,
the error is usually unhelpful. A recent one I got from Phobos
was "Positive Conversion Overflow". Without attaching more
information to Exceptions in intermediate catch blocks, the error
is devoid of context. (Unless you print the stack trace but it's
not like a regular user can make any sense of that)
But wait, I heard Exceptions are also considered bad these days,
the current trendy thing is returning `Result<Value, Error>`
types, like Rust does. I don't have that much Rust experience,
but I have seen code full of `result.expect("quick message")`
(which panics and aborts the program on error) to satisfy the
compiler's type checks, with the idea "it's a quick script, I
can't be bothered to do proper error handling for this". So you
get extra boilerplate in the code, but the UX is no better than a
C library with an error callback that prints and aborts, like X11.
My personal takeaway is that regardless of what language features
you use for error handling, you rarely get it right first try.
You have to *test your software* by triggering error conditions
and observing what the UX of that is. Then it becomes immediately
obvious where the error should have been handled and what
information should be attached. With concrete feedback, fixing
your code becomes so much easier.
Of course, when you have hundreds of error conditions, this
becomes rather tedious. This is where [Walter is completely
right](https://forum.dlang.org/post/10utksm$1h2t$1@digitalmars.com) that the best 'error handling' is *no handling*.
In [The Easiest Way To Handle Errors Is To Not Have
Them](https://www.dgtlgrove.com/p/the-easiest-way-to-handle-errors), Ryan Fleury gives concrete C examples, but the principles apply to other languages as well. I haven't read Walter's book recommendation "A Philosophy of Software Design" yet, and if you haven't either, maybe that post is more accessible.
More information about the Digitalmars-d
mailing list