4 ms·
> It is acceptable for code whose maintainers value readability and simplicity over everything else. Errors-as-return values are less readable than conditions,
by throw10920 5y ago
> It is acceptable for code whose maintainers value readability and simplicity over everything else.
Errors-as-return values are less readable than conditions, not more - there's literally more visual noise on the screen.
And if you want "simplicity", don't use a computer. Computers are intrinsically complex devices, users desire features with complex implementations, and our job as programmers is to manage complexity, not pretend that it doesn't exist. One of the article's main points is that Go does the latter in lieu of the former, and that's also what errors-as-return-values does.
----------------------------------
The formal name for a condition+restart system appears to be "algebraic effects"[1].
Conditions and restarts are similar to exceptions, with the following changes:
First, conditions are conceptually used for non-error conditions in some cases, like what Python does.
Second, throwing a condition doesn't cause the stack to unwind up to the handler, unlike exceptions.
Third, in addition to throwing conditions, you, uh, wrap ("establish" is the jargon used) code in what are called "restarts", similar to wrapping things in try/catch blocks (but distinct, because with conditions you still have condition handling blocks). Restarts can have names and are non-mutually-exclusive. Conceptually, restarts represent error-recovery strategies, while conditions represent the errors themselves.
Fourth, when a condition is thrown, it propagates upward until it hits either the toplevel (in which case the interactive debugger is launched), or it hits a condition handler - without unwinding the stack. Then, either the human looking at the debugger can pick which restart they want to use, or the logic at the condition handler can do so.
Why is this better than any alternative error-handling mechanism? Because every other error-handling mechanism (1) unwinds the stack (destroying all contextually useful information that isn't explicitly saved by the programmer, and preventing you from restarting a computation in the middle) (2) forces you into a single error-recovery strategy and (3) couples low-level code to high-level code as a result.
In general, low-level code has details about the specific kind of error, context around it, and access to data and control flow that would allow the error to be recovered from (e.g. for a log-processing program, reasonable restarts while parsing a log entry would be (1) skip it (2) retry (3) use an alternative parser and (4) return an empty entry), while high-level code has the application context about why the low-level operation is being performed in the first place and which error-recovery option should be picked.
Conversely, high-level code doesn't have details about what the low-level code was doing at the time of the error, and low-level code doesn't have the high-level context necessary to determine which error recovery strategy is appropriate in this use of the low-level code.
[1] https://en.wikipedia.org/wiki/Effect_system https://en.wikipedia.org/wiki/Effect_system
https://en.wikipedia.org/wiki/Exception_handling#Condition_systems https://en.wikipedia.org/wiki/Exception_handling#Condition_s...
- preseinger 5y ago> Errors-as-return values are less readable than conditions, not more - there's literally more visual noise on the screen. No. When you make a function call, and that call can fail, then the happy-path and the sad-path are both things that you need to manage as a caller. Happy-path and sad-path are two equivalent states that both need to be accommodated by the program logic. Error handling code is not "noise". It is equally important to success-path code.
- lanstin 5y agoMaybe this is the fundamental argument here. Plenty of cases I have written code where I am trying to do something over a big set of things, e.g. check a file for hard-coded paths, or send a message to a lot of people; it isn’t weird for those things to fail. Maybe I couldn’t open the file. Maybe the file lacked hard coded paths. Maybe the sender lacked rights to send to that receiver, or maybe the receiver is currently offline. But if most of your code is some complex calculation, say weather simulation?, maybe there is by default just one path.
- throw10920 5y ago> No. Yes. There is literally more visual noise on the screen. This is not up for debate - more pixels are lit on the monitor you are looking at. > When you make a function call, and that call can fail, then the happy-path and the sad-path are both things that you need to manage as a caller. False - the direct caller is not responsible for error-handling, in general - some transitive super-caller will be. Errors as return values needlessly generate this visual noise for every caller, when not needed, in addition to introducing aforementioned coupling. > Error handling code is not "noise". It is equally important to success-path code. You're misunderstanding my point. I never said that error-handling code is noise - it isn't. What is noise is forcing every single function call between the appropriate error-handling point and the error location to have extra useless junk. When there's an error, you should see exactly two things in your codebase: some stuff at the point where the error is thrown, and some stuff at the point where the error is handled - and, given that the place where the error should be handled is rarely the direct caller, you should see nothing in between.