Live data from Hacker News

Why I Prefer Exceptions to Error Values

cedardb.com

1–10 of 22 posts

Re: Why I Prefer Exceptions to Error Values

#4
After exceptions comes acceptance of: https://fsharpforfunandprofit.com/rop/

of errorcases as normal program flow and wondering how you could ever accept those expensive packins and callbacks as normal behavior.

https://vimeo.com/113707214

C# is pretty far along wben it comes to allowing this style of programming, that actually should be in every language core.

Re: Why I Prefer Exceptions to Error Values

#5
I originally only wanted to point out that the cited benchmark doesn't actually run the same thing for both cases (`do_fib_throws(...) + do_fib_throws(...)` has no defined call order), but then looked at the assembly and noticed that they are very differently structured. It turned out that GCC only recognized `do_fib_throws` to be eligible for tail calls and did some more inlining, and putting `noinline` and `optimize("no-optimize-sibling-calls")` attributes reduced the gap to a more believable level (~50%). As tail calls are highly sensitive to the exact call sequence, this benchmark is not suitable for the claim without detailed analyses.

Yes, result types may result in a worse branch prediction among others. But that is rarely the primary performance issue caused by them, as you would expect the "unexpected" branch to be rarely taken anyway. The actual performance issue simply comes from the fact that it uses a more complex code in the typical path, so it may confuse the less sophisticated optimizer and prevent potential optimizations possible just like above.

Re: Why I Prefer Exceptions to Error Values

#6
This article feels like someone trying to find arguments and justifications in favour of an existing opinion/bias.

> Compare this to functional-style errors, where error handling is manual and super tedious. You have to explicitly check if the return value is an error and propagate it.

No, you don't. You can easily convert a functional style error into an exception on the call site explicitly (e.g. `std::optional::value` in C++, or `.unwrap()` in Rust), propagate via language features (e.g. `?` in Rust) or library abstractions such as monadic operations.

The fact that you explicitly have to check the return value is a massive win in readability and ensuring that the "error case" was considered by the caller. That is paramount for the robustness of any codebase.

> But there’s much more: Allocations can fail, the stack can overflow, and arithmetic operations can overflow. Without throwing exceptions, these failure modes are often simply hidden.

Turns out there is a good use case for exceptions: exceptional and rare errors that cannot be reasonably handled in the immediate vicinity of the call site.

Exceptions and error types can and should coexist nicely.

> The classic example is syscalls, which usually follow C conventions.

Yes, C error handling from decades ago sucks at providing information and context for the source of the errors. This is not an intrinsic issue with error return types, it's just another thing that sucks about C and is the way it is because it's old.

> We parse an int somewhere, and an `IntErrorKind::InvalidDigit` bubbles up at the user.

How is that a bad thing? Either the user provided the string that should have been parsed, therefore it's useful information for them to know why it failed to parse, or they don't care much, and they can explicitly decide to convert the error into an exception and propagate it upwards.

Again, it forces the user to think about the error case, which is excellent!

> The following examples use C++ code, which allows us to compare both versions like for like: [...]

Now show a benchmark where the error rate is 50% or more.

Re: Why I Prefer Exceptions to Error Values

#7
I think exceptions are bad not because of the principle but because code is written by humans.

We use Go in our company and every intern learning it complains about the error handling at first.

Then they write a bunch of programs and those basically never crash. I had and intern write a somewhat complex service mangling large amounts of Geodata which was his first go service ever. That thing ran for years without crashing once (it died due to an hardware problem).

The reason is simple: Golangs stupidly verbose error handling forces you to constantly think about the unhappy paths. Every function is littered with error handling and it makes you aware of possible problems and rigorously forces you to not forget them.

Exceptions are the opposite: people do whatever and have someone else deal with the fallout later. This leads to people not thinking about errors and then someone using catch(all)-> doNothing kind of "solutions".

On top of that exception based error handling is what i call transparent (like in invisible). So you can write a function using some other function without being aware the there could be exceptions thrown (unless your Language uses checked exceptions like Java).

One can not possibly know every detail and remember the constantly. So if something goes wrong, you end up with super deep stack traces at unexpected places. This is unlike Go code where the error usually is handled at the earliest point possible with (hopefully) reason and contingency.

Re: Why I Prefer Exceptions to Error Values

#8

This article feels like someone trying to find arguments and justifications in favour of an existing opinion/bias. > Compare this to functional-style errors, where error handling is manual and super tedious. You have to explicitly check if the return value is an error and propagate it. No, you don't. You can easily convert a functional style error into an exception on the call site explicitly (e.g. `std::optional ::v…

If the invalid int came from the network it could be confusing to tell the user

Re: Why I Prefer Exceptions to Error Values

#9

This article feels like someone trying to find arguments and justifications in favour of an existing opinion/bias. > Compare this to functional-style errors, where error handling is manual and super tedious. You have to explicitly check if the return value is an error and propagate it. No, you don't. You can easily convert a functional style error into an exception on the call site explicitly (e.g. `std::optional ::v…

> C++ code ... Now show a benchmark where the error rate is 50% or more.

C++'s policy of "exceptions should be exceptional" isn't a good answer to this either, and it introduces a lot of ugly edge cases when writing code. For instance, you have to make the judgment call of whether to handle commonly-expected errors as return values or exceptions (eg. checking if something exists, and returning it if it does).

In many cases it is impossible to make the right call. For instance, a "file not found" exception is no big deal when your library is being used in a GUI app where user actions are relatively infrequent, but if your library is used in a high-traffic server or for batch processing, suddenly all those "file not found" exceptions are eating a lot of CPU.

In general, you simply can't predict when users of your C++ code might find a case where a code path spams exceptions, tanking performance.

This problem also exists in other exception-using languages like Python and C#[0], but these languages tend to be used for less performance-intensive purposes (especially Python) so it doesn't come up as much, and generally exceptions are used even for expected errors.

[0] https://stackoverflow.com/questions/891217/how-expensive-are... (C# exceptions are 30,000 times slower than return codes)

Post reply on HN