4 ms·
This is not exactly the most earth-shattering revelation, but man: handling and communicating errors always seems to be a source of a vast amount of inelegance
by jchw 2y ago
This is not exactly the most earth-shattering revelation, but man: handling and communicating errors always seems to be a source of a vast amount of inelegance in software.
I'd argue we haven't really "solved" the optimal way to do error handling in programming: Using union types remains one of the best options, but even that has its downsides. Consider the ergonomics of forwarding an error type multiple layers in a Rust program: you can remove some of the boilerplate by strapping macros on top, but I'd argue that's more of a bandage than a fix. Most other programming languages are either using exceptions, which I don't like as they complicate control flow behavior significantly, or simply ignore error handling entirely (like C and Go; Both of them provide some standard facilities for dealing with error values, but handling it is completely manual. I do like this, since it's very straightforward, but it nonetheless is just sidestepping the problem.) And even trying to keep it simple can create new problems, like of course the way pthreads has to contort errno into a thread-local, for reasons obvious.
And while stderr has created a somewhat unified channel for dumping errors into, once they've bubbled up to the point where the program needs to output it, there's an almost unlimited amount of opinions on exactly how error logging should work. Some software won't use stderr by default, others only uses stderr for specific types of errors. Some software dumps everything that isn't data output into stderr, including e.g. `--help` text, whereas some software uses stdout for anything that isn't explicitly an error (Which often leads to me needing to pipe --help to less twice: once without, and once with 2>&1.) Categorization of error logging is also somewhat contentious: should there be a "warning" severity? should you split errors into modules? Formatting, too: what should be in a log line? Should logs be structured into a machine-readable format such as JSON?
It was probably a bad omen that even very old versions of UNIX ran into problems dealing with error logging and wound up needing to bifurcate things. Few programs feel as 'lazy' as UNIX; if UNIX couldn't ignore the problem, god knows the rest of the software was doomed.
- euroderf 2y agoHandling errors in a processing pipeline in Go is a big fat PITA. In other languages too ?
- w10-1 2y agoI think Swift is close to optimal for now. It does have the union type Result<normal, error>, but most people throw/catch Error. In Swift, error is a simple value (without a stack frame) and thus is as cheap as a return value, but can be handled/caught anywhere in the call chain like an exception. Error is a protocol that tags any type, so it can carry any details you like, and your catch can switch on the type. But it's only now (10 years on) that they're declaring error types in the function signature. In this world, it turns out that not throwing is the same as throws(Never). It took this long because it's unclear (but possible) that per-type error handling helps, mainly with libraries. Serializing/tracking the originating (thread) context and avoiding merge conflicts in error streams seems like the unsolved problem. Both Java and Swift have structured concurrency with parent/child relations with derived cancellation/termination. Perhaps later that can include errors.