Hacker News new | ask | show | jobs
by Animats 427 days ago
Most of these proposals miss the point. Errors need a useful taxonomy, based on what to do about them. The question is what do you do with an error after you caught it. A breakdown like this is needed:

- Program is broken. Probably need to abort program. Example: subscript out of range.

- Data from an external source is corrupted. Probably need to unwind transaction but program can continue. Example: bad UTF-8 string from input.

- Connection to external device or network reports a problem.

-- Retryable. Wait and try again a few times. Example: HTTP 5xx errors.

-- Non-retryable. Give up now. Example: HTTP 4xx errors.

Python 2 came close to that, but the hierarchy for Python 3 was worse. They tried; all errors are subclasses of a standard error hierarchy, but it doesn't break down well into what's retryable and what isn't.

Rust never got this right, even with Anyhow.

4 comments

Severity in majority of library functions is undecidable, it’s decidable at the call site instead. That’s why language should be providing sugar to pick behaviour - exceptions (propagate as is, optionally decorate/wrap), refute (error value, result type), mute/predicate-like (use zero value, ie undefined in js/ts).
> optionally decorate/wrap

If you are using exceptional handlers for transmitting errors instead of exceptions (i.e. what should have been a compiler error but wasn't detected until runtime), wrapping should be mandatory, else you'll invariably leak implementation details, which is a horrid place to end up. Especially if you don't have something like checked exceptions to warn you that the implementation has changed.

There's no universal taxonomy of "this error is retryable, this one non-recoverable"; it's context dependent.

As a boring example, I might write something that detects when a resource gets hosted, e.g. goes from 404 -> 200.

The best I imagine you can do is be able to easily group each error and handle them appropriately.

Well you don't usually want double retry loops, and sometimes that subscript error is because the subscript came from input.

What to do with an error depends on who catches it. That's probably why Python got it wrong and then Rust said worse is better

An interesting development in this direction is Clojure’s anomalies taxonomy: nine outcomes (two retriable, two maybe-retriable, five non-retriable; nine respective ways to fix)

See table here: https://github.com/cognitect-labs/anomalies