4 ms·
Don't forget, failure modes pierce abstraction boundaries. An abstraction that fully specifies failure modes leaks its implementation. This is why I think chec
by barrkel 11mo ago
Don't forget, failure modes pierce abstraction boundaries. An abstraction that fully specifies failure modes leaks its implementation.
This is why I think checked exceptions are a dreadful idea; that, and the misguided idea that you should catch exceptions.
Only code close to the exception, where it can see through the abstraction, and code far away from the exception, like a dispatch loop or request handler, where the failure mode is largely irrelevant beyond 4xx vs 5xx, should catch exceptions.
Annotating all the exceptions on the call graph in between is not only pointless, it breaks encapsulation.
- binary132 11mo agoThis is a better way of expressing what I had been thinking about putting exception details behind an interface, except that in my mind encapsulating errors is just good design rather than implementation hiding, since the programmer might want to express a public error API, for example to tell the user whether a given fopen failed due to not finding the file or due to a filesystem fault.
- rerdavies 11mo agoe.what() Just include the file name in the error message. And all of this is predicated on logging errors, which is not at all user-friendly, and not remotely acceptable in GUI applications.
- binary132 11mo agoI was talking about catching different classes, not about logging. Even if you’re just implementing a string description, there’s nothing stopping you from designing that string for use in a UI element, or implementing a structured message that can specify more details usable for defining UI elements, similarly to how many REST HTTP-driven web UIs work. I don’t think I’m quite following your criticism.
- 1718627440 11mo agoIf your error codes leak the implementation details through the whole call stack you are doing it wrong. Each error code describes what fails in terms of it's function call semantics. A layer isn't supposed to just return this upwards, that wouldn't make sense, but to use it to choose it's own error return code, which is in the abstraction domain of it's function interface.
- barrkel 11mo agoSo you want to gradually reduce the fidelity of the error message as it makes its way up the stack. That means that the top level handler can at best log a vague message. That in turn means you must log along the way where you have more precise information about the failure, or you risk not having enough information to fix issues. And that in turn means you must have lots of redundant logging, since each point in the stack doesn't know whether the abstraction it's invoking has already logged or not, or encapsulation would be violated.
- 1718627440 11mo ago> That in turn means you must log along the way where you have more precise information about the failure Yes, that's the idea. You split the information into a diagnostic with stuff you deal with now and data that the upper layer will handle. The intersection between the data in these two things should be empty. > And that in turn means you must have lots of redundant logging, since each point in the stack doesn't know whether the abstraction it's invoking has already logged or not, or encapsulation would be violated. No. You print a diagnostic, about what exactly THIS layer was trying to do, you don't speculate what the upper layer was trying to do and try to log that. Every layer knows the lower layer has already logged the primary error, because an error object exists, and it also knows that the upper layer will print a diagnostic about what was the intention, so it only prints exactly what the error was in this layer. > doesn't know whether the abstraction it's invoking has already logged or not, or encapsulation would be violated. It knows that the lower layer has logged all stuff that that layer considered to be important, and that none of the data that is available to this layer was logged, since that is the responsibility of the caller. An example: Document rendering incomplete, skipped publishing step. Thumbnail #39 missing. Failed to fetch image: Connection refused. [Discarded malformed packet with SYN flag. Invalid data in src/network/tcp.c:894 parse_tcp_packet_quirks_mode] Depending on the log level, you wouldn't show the later diagnostics. If there is a debug flag set, you can also add the function/line information to every step, not just to the last. If you are outtputing to stuff like syslog, you would put each diagnostic on its own line.