Joe Armstrong distinguishes in his thesis between exceptions and errors: exceptions are when the runtime system doesn't know what to do, and errors are when the programmer doesn't know what to do.
Say your code divides by 0; the runtime system can't handle 1/0 but you the programmer may have anticipated this and know what to do. This is just someplace you write code right there to handle the case (catch an exception, pattern match the 0 case beforehand, whatever).
Your error, on the other hand, means something you expected to hold didn't; recovery inline from unknown unknowns is a fool's errand. Instead you give up and die, and the problem is now the exception you know how to handle "my child process died".
The distinction makes me think of Java's checked exceptions, which I think have gotten an unfairly bad reputation from a lot of slapdash programmers complaining that they didn't want to think about error-cases. (And, TBF, a little syntactic sugar could have gone a long way.)
In brief, a checked exception is part of a method signature, "function wash throws NoSoapException", and the compiler enforces that whoever writes code calling that signature must make some kind of overt decision about what they want to do when that exception comes up. That may mean recovery, wrapping it inside another exception more-suitable to their own module's level of abstraction, deliberately ignore/log it, or just throw a non-checked exception.
So in a sense checked exceptions suit those "error" cases where you do expect the programmer consuming your function to at least decide whether they can handle it, and if they don't you still get all those wonderful features like stack traces and caused-by chaining. In contrast, regular (unchecked) exceptions have the opposite expectation, that the caller probably won't be able to handle them anyway and must opt-in to capture them.
Indeed. OTOH, "focus your main code on the happy path, and put your error handling in the supervisor tree" is unfortunately a bit less pithy.
Shades of "boring technology"[0] which might better be described as "choose technology that is a good fit for the problem, proven, reliable and proportionate. Spend your innovation tokens sparingly and wisely".
I'm personally caught between my attachment to the "boring technology" philosophy and my desire to try Elixir, which seems like exactly the kind of obscure and exotic technology that it rejects.
I actually think elixir is the perfect boring technology now. The language is matured, and is not changing much. There will be a big addition at some point with the new type system, but other than that the language is pretty much done. Underneath elixir is erlang, which is extremely mature and highly boring in the good way. Live view might be the only exception, but even that is now becoming boring as it has gotten stable. If you are a believer in boring, you should definitely give elixir a try
Erlang is old, reliable tech that used to scare people once upon a very distant time for
- running on a VM (now boringly normal)
- using a pure-functional language with immutable terms (the pure-functional language fad has since then come and gone and this is now archaic and passé if anything)
But languages only get stereotyped once. At any rate, it's pretty boring and old.
Already said by two sibling comments in all the detail I would have, but I wanted third it: as a subscriber to boring technology myself and actually never been one to jump on new shiny tech, Elixir/Erlang is the epitome of "boring technology." Elixir does a lot on its own you can often cut out the need for a lot of other dependencies.