(no title)
natefinch | 7 years ago
Rob Pike's example code is bad and I would not allow it through a code review. Why? It makes the code lie. It appears as though the writes cannot fail, but in fact they can, and later writes become no-ops. On top of that, it means that you lose the context of which write failed. Did you fail writing the header, the body, or the footer? You can't know anymore.
This is like
try {
doThing()
doThing2()
doThing3()
catch (Exception ex) {
// handle
}
You can't tell what failed. You can't tell what is possible to fail. The handler can't differentiate.
syrrim|7 years ago
>Did you fail writing the header, the body, or the footer? You can't know anymore.
You are writing to the same stream in both cases. The error wouldn't be caused by the header or footer data, but by some property of the stream, like it being closed, or the disk running out of space. Knowing whether the failure occurred while you were writing to the header or footer is unnecessary information, and therefore obfuscatory.
ereyes01|7 years ago
"The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise." - Edsger Djikstra
Or said another way, a good abstraction automates a precise set of tasks instead of adding ambiguity.
jstimpfle|7 years ago
So are you making a general case for exceptions or are you just asserting that there exist cases where we don't care where errors happened? There are absolutely such cases. When writing quick and dirty scripts I absolutely value that they crash when they couldn't find a file or similar.
But for more complex systems, I've never found a good use for abstractions. In a complex system, you need to see what happens. Out of sight, out of mind. There is no way building a complex system on top of exceptions and having a good understanding over its failure modes.
I would go further and state that it's extremely uncommon to be able to handle an exception in an appropriate way. The most common use of them is to either 1) handle the error immediately (for example FileNotFound), in which case the exception handling adds just unnecessary syntactical variety. Or 2) just let the program die. Coincidentally, golang has that too.
There may be rare situations where you can handle a series of statements with a single exception handler, like several write-file statements in a row or such, and that might seem cleaner than repeating the error handling. But actually these cases are just a code smell. You could rewrite them using a for loop and factor the repetitions as actual data, adding the error handling only once (inside or after the for loop). In other words, exception handling is just a way to paper over that code smell. It makes hiding bad code easier, so leads to bad code.
crimsonalucard|7 years ago