Comment by mjw1007

4 hours ago

It's common that if you extract a function or a module with a well defined interface, that function or module can't tell whether a "bad" input indicates an expected or an unexpected error.

For example division by zero often indicates an "unexpected" error, but it wouldn't if you were implementing a spreadsheet.

So to me the approach of using different forms of error reporting for the two kinds of error doesn't seem promising: if you imagine you had to implement division yourself, which kind of error should it report? Should you have two variants of every fallible function so the caller can choose?

That's a deficit of most programming languages. One solution is to pass every error value up and let the caller decide. Rust does this to some extent. This leads to verbose code however.

For modules inside your application, designing a good interface involves exposing the right errors and crashing for the rest. This creates some coupling of course (shared assumptions of which errors need to be handled across modules). Trying to avoid that probably just leads into the circle of hell where you have more abstract beancounting than useful code.

In the end, this is another reason why overreliance on external libraries leads to mediocre, buggy software.