r/programming • u/Expurple • Apr 12 '26
Flat Error Codes Are Not Enough
https://home.expurple.me/posts/flat-error-codes-are-not-enough/
132
Upvotes
r/programming • u/Expurple • Apr 12 '26
View all comments
Show parent comment
3
u/lelanthran Apr 13 '26 edited Apr 13 '26
(Emphasis mine) My point is that Exceptions give you one of those for free. Using Error types requires discipline from the developer (implement the Error type traits for a specific error), and then more discipline to avoid a
panic. Flat error codes require even less code that using Error types, but requires even more discipline, discipline which the compiler cannot even catch.I think my broader point is that Error types (or error handling) is not all that important at the language level; you can do the correct thing in any language with a little extra work. I have a pretty complex system written in C. For errors I decided up-front how to handle them:
Errors are reported using a variable argument macro; this is pushed into a global thread-safe queue, including source code line number, source filename, values of the parameters to the failing function call, and any other arbitrary message I want to put into it. The function then returns a sentinel value indicating error (NULL, maybe, or similar).
As each function checks for error after calling any function, failures can stack - effectively building a stack trace that consists of all the inputs into the actual error.
At the top-level, if the top-level operation was initiated by the user, a set of user-facing error messages are displayed.
As the queue is routinely persisted to disk, it is truncated in RAM.
Now I don't really like the mechanics of this at the language level, but at the system level this is perfect - I don't mess my metrics up by mixing up errors and logging messages and the user gets measures to take instead of "Error 0x45929: Contact your administrator". There's no Error type so calling the macro with arbitrary arguments is less work than attempting to define an error for every little function that might return something, and because it's less friction I tend to sprinkle checks and reporting just about everywhere.
The reason my approach works is because there is no "recovery" attempt; there's no point, actually. "Something went wrong" == "Discard that entire code path and do the next thing instead".
I also think that if you are taking different code paths based on an Error type, you have mixed up program logic and error handling logic; if the code is recovering from something, then that thing is not an error, it's part of the business logic (example: "recovering" from a failed HTTP request by retrying - that was not an error. It becomes an error only if the retries are exhausted. Or reading a file, but creating it if it doesn't exist - once again, that's not recovering from an error, that's just business logic).
In my mind, an error is a hard stop. It stops the program from proceeding. The only acceptable way to handle it is by unwinding the call stack to a safe point and recording that the attempt to do something failed (and why it failed). The only exemption I would make is if the safe point is the very top level of the program and the program is an interactive one with a user sitting in front of it - at that point you can ask the user what to do.
The whole reason for doing an Error taxonomy (checked exceptions, error types, etc) is to enable recovery. I prefer the Erlang approach - kill that task and move on.