That is, in many (all?) imperative lists of steps for how to accomplish something, I often do not want to acknowledge that every step could fail. Rather, I would like for a failure to be something I can touch and reason with. Possibly restart from.
Why did I not take that turn? Because I need gas. Or the kids need to use the bathroom. Doesn't matter, too much. I'm the user. Give me my options at this point. (And as a real user of maps, also give me the option of "piss off for 10 minutes.")
(Yes, I like the condition/restart system of common lisp...)
I think that's a really poor and simplistic comparison. You're content not considering every possible outcome of trying to go shopping because in the face of changes to your circumstances, you can easily come up with a new strategy and adjust your goals on the fly.
> I often do not want* to acknowledge that every step could fail.*
That's what you want, but I have often found that the demands of quality software are different. I've seen too much software end up in strange and unconsidered failure modes because it threw up at the wrong time.
So, for the function, I want to be able to say the happy path. I would also like to be able to say what could go wrong, with advice to the user on how to proceed.
That's kind of the problem though. Exceptions are flow control.
...for exceptional events.
That means those events that are very far from the happy path and need to be recovered by unwinding down multiple function calls until a safe point to recover gracefully is reached. These are events such as failing to allocate memory.
Result<T, ErrorT> is used in place of exceptions, much nicer IMHO.
However, Maybe can be implemented without tagging, see[0] for example.
I'm pretty sure the cost of checking this in a static language where the tag enums range is known at compile-time is:
- 100x cheaper than cache-miss on a memory access
- and 10000x cheaper than IO which is often where those errors/results/maybe/exceptions issues arise.
I.e. irrelevant in most cases.