Comment by Mikhail_Edoshin
5 years ago
An "operation" is not something inherent to the code. If we look at a function that may get what we call an error, we'll see that in either case it completes and returns control to the caller. We label one such result 'success' and another 'failure' because we also have an idea of purpose of the function, but the purpose does not exist at the code level. Maybe this is why we struggle with errors.
Once you give a function a name, it has an operation that's inherent to it.
If you have a function called `Add` that takes 2 parameters and returns the sum of those two numbers. That's the operation. If the web service that you call to perform the sum is down, it cannot return that sum, so that's an failure.
The code that calls this function needs that sum to continue it's operation. If it cannot get that result it cannot produce it's own result and that error needs to be propagated. Maybe the entire program has a purpose that it cannot now be completed and should be aborted.
If you give a name to a mountain, it doesn't affect the mountain, it affects you :)
Joking aside, consider the following case. A function needs to print a series of reports and opens Print Setup. The user changes his mind and presses "Cancel". Now the function cannot continue and needs to stop the planned operations, undo what it has done so far, and return control to the user.
The internal mechanism you're going to use for this will be most likely the same mechanism you use to handle errors. But what you're handling is not an error, at least in the common usage of the word, because nothing erroneous is happening! Everything goes exactly as should and according to the general purpose of the application.
My point is that the current dichotomy of success and failure does not help us to solve the seemingly simple problem of errors.
> The internal mechanism you're going to use for this will be most likely the same mechanism you use to handle errors.
Which is exactly how exceptions work. If you're using RAII or similar pattern in your language there is no separate path for cleaning up errors than from the normal cleanup. That's the point actually. If the user presses cancel or an exception is raised the eventual stack unwinding will undo everything.
If you have a bunch of conditional statements for every possible error, you're actually creating more situations that are unique for errors. You have all these paths to test for. With exceptions there is only the happy path both in the operation and the cleanup.
That's a neat observation. If you're writing a function as "How do I get from A to B?", that's more error-prone than "What are all the possible outcomes of trying to get from A to B?"
I disagree; programming languages and code are built explicitly and exclusively to perform a function. Operations and purpose are more inherent to the code than their mathematical/logical nature.
Yes, everything is built for a purpose. But the raw materials used to make a thing do not change because of the purpose. They follow their own laws, it's us who ascribe the meaning to the resulting combination. Laws are something we cannot change, only use. But purpose is a concept. We do need concepts to create and operate things, but if we shouldn't mistake them for laws. Concepts are something much more pliable :)
It's all rather abstract, I guess, but yesterday I found an example while playing a game, "Opus Magnum". You are to solve puzzles by arranging mechanical arms to move marbles. Initially I mentally referred to actions of the arms as "taking a marble" and "placing a marble" and solved quite a few puzzles this way. In all solutions all my arms did exactly that: they took and placed marbles without doing any purposeless movements.
Yet yesterday the next puzzle looked too tiresome to built. I had an eureka moment once I realized that the arms do not take and place marbles, they merely close and open their grips and if there's a marble, it gets caught, but the arms themselves have no idea whether they're moving a marble or not. And once I allowed myself to let them do "purposeless" movements without marbles, I found a simple and elegant solution :)