No. In the same way that my directions to the mall don't include "maybe take this turn" at all turns.
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...)
> No. In the same way that my directions to the mall don't include "maybe take this turn" at all turns.
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.
I should say that my want there is local to the directions. For the trip, I definitely want them handled.
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.
I don't think options really serve the same purpose as exceptions. If you have are just passing up None or whatever up the call stack over and over again, you probably should just be using an exception. If not, then options are fine. I use options for normal behavior (a missing file, for example) that perhaps can be corrected or handled in a different way. I throw an exception if I want to just crash the program. I rarely ever try catching exceptions, except in maybe some top level driver function. Oh and to all the programmers out there who wrote the code I'm currently dealing with: please don't use exceptions for flow control, it's a terrible terrible idea.
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.
I think those are awful to deal with errors. You have one part of the code that handles one concept and could error something. However the result of that code is then handled to some other part of the code which might deal with a local error but now you really don’t know if the error was local or occurred in the other part of the code. The second part of the code is now dealing with an error situation which it shouldn’t and you’d need to write weird code to stop it from doing that. Also you introduce behavior caused by two different context but merged due to the language “features” which, I think is much worse, because it’s not obvious that it just happened. Using exceptions otoh fixes this and parts of the code can still be completely oblivious that errors can occour.
Which is why Result and Error types exist. With those you get both the context of the error as well as making it clear that the code you are entering needs error handling to be safe. Much less of an issue than calling code that unexpectedly raises exceptions.
And they do have their uses but they are not good enough by their own. Having both exceptions, result types and maybes is a lot better to have and to use appropriately than only have one or the other.
I heard related issues called boolean blindness. You drop every bit of useful error information and leave only result/no result or true/false. Want to load a file and it fails? Access rights? Parsing Error? File doesn't exist? User interrupt? Can all be summed up as an empty Optional, completely useless for any kind of automated or manual recovery or even to decide if recovery is necessary (user interrupt).
and in those langs its trivial and very common to make even more elaborate return/result types containing a very precise representation of all possible result categories.