3 ms·
I wonder how many commenters clicked on this link because this really has nothing to do with "exceptions" (as in the things you raise or throw) at all. So it's
by cletus 7y ago
I wonder how many commenters clicked on this link because this really has nothing to do with "exceptions" (as in the things you raise or throw) at all. So it's a fairly terrible title that is really arguing against a catch-all Error case.
The one parallel to (actual) exceptions is the author is arguing for a constrained subset of error states rather than a catch all Error type. This isn't a new idea. Java essentially does this with checked exceptions. C++ does this where you can declare what exceptions can be thrown (which you should basically never do).
So I did Java for years. Java had several Grand Experiments, one of which was checked exceptions. Despite it still having some fans I think the general consensus now is that checked exceptions were a Huge Mistake [tm] for many reasons (eg leaking implementation details, cluttering your API the whole way up).
One anti-pattern I see with exceptions is people using them for control flow. For example, dealing with a ParseException in Java when parsing numbers [1].
This of course falls into a religious argument about what an exception actually is.
For a few years at Google I wrote Google's flavor of C++, which I actually grew to really like. It is pervasive that any method in Google C++ returns a util::Status. This is much like Go error handling but (IMHO) better.
For one thing, it's a compiler error to ignore the result of a util::status (you can call .IgnoreResult() if you really want to ignore it). I think this is a much nicer and safer default.
You return things with a util::StatusOr templated union type that has the same semantics. There are even macros (that were somewhat controversial) to reduce boilerplate to do things like call a function that returns a StatusOr, assign the result to a variable if it's OK or return the error if it's not.
There are of course utility methods for adding context to a Status(Or) you're returning.
So all this came about because Google C++ strictly prohibits exceptions. This is a historic decision that's probably impossible to unwind at this point and honestly I don't think there's a strong motivation to change it.
IMHO exceptions are a false economy.
This is one of many things I like about Rust. Rust's enums are kind of the next evolutionary step for this. It's a compiler error not to deal with all options, there are constructs to reduce boilerplate and you can pass values.
[1]: https://stackoverflow.com/questions/8286678/parse-string-into-number https://stackoverflow.com/questions/8286678/parse-string-int...
- mytherin 7y agoI think Java's flavor of exceptions are especially horrible, as you mentioned a string->int parse failing is typically not exceptional at all but rather expected. However, I do think there is a place for exceptions: exceptional situations. Status(Or) is nice for certain types of errors, but now if you want to correctly deal with out-of-memory errors that means every single function that allocates anything on the heap now needs to return a Status(Or) in case the allocation fails. That error message then needs to be propagated through your entire library back to wherever it is that you can handle memory errors, which is likely somewhere at the root of the library. That now means that every single function in your entire library needs to return a Status(Or) and propagate it, which significantly bloats your codebase. The macros you describe likely help with that somewhat, but then those macros are basically manual exceptions in that they just unroll the stack to where you don't call the macros anymore, but they require a bunch of extra manual effort and obfuscate your code somewhat. They are also slower in the common case (no memory errors), as you are now performing an extra check on every single function call in your entire library. Meanwhile using exceptions together with smart pointers and smart locks basically makes it so that you can handle memory errors "for free" without having to bloat your codebase. When a memory error pops up, throw an exception and unroll back to where you can properly handle the memory error. The smart pointers/smart locks/destructors will take care of cleaning up everything. No need for any extra checks all over the code base for such a rare error.