Comment by wvenable
5 years ago
I completely disagree. A program or function is designed to perform an operation. If that operation requires the contents of the file, then the program cannot continue unless it successfully reads the contents of the file. There is already a natural asymmetry. If you cannot open the file, there isn't any more to do.
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.
1 reply →
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 :)
> I completely disagree.
Disagreeing is alright, but here you don't really do, do you? I can translate the paragraph you have written into pseudocode:
> If that operation requires the contents of the file, then the program cannot continue unless it successfully reads the contents of the file. (...) If you cannot open the file, there isn't any more to do.
This is just a regular "if-else" that can be done with any programming language. The behavior of your program when the file cannot be opened is part of the specification; just as its behavior when it can be opened. I agree with you on that, and I add that the desired behavior can always be implemented using regular control flow constructions. You do not need a specific language construct for "errors", as you have proven by the algorithm that you have described in your text.
> stop doing things
This is what we call raising an exception.
> I add that the desired behavior can always be implemented using regular control flow constructions.
I agree. But that's not a very interesting observation. We added language specific constructs for errors not for the computer but for the human. These constructs make reading and writing code easier and safer.
A code with if-else constructs for every possible error condition is really hard to follow and very brittle. If the result of every error condition is the same (stop doing things) we have developed constructs to make that path easy.
The problem with errors is that understanding and resolving them is often non-local. If a network call fails the code where that fail happens doesn't have enough information to resolve it. If the solution is re-try the entire operation 3 times and then give up, the handling of this error must happen back where the operation starts not some random place in the middle where it actually occurred. Maintaining all the if/else necessary to move that information up through potentially dozens if not hundreds of calls is extremely difficult. And, it turns out, completely unnecessary and easily automated.