The Scourge of Error Handling
CowboyRobot writes "Dr. Dobb's has an editorial on the problem of using return values and exceptions to handle errors. Quoting: 'But return values, even in the refined form found in Go, have a drawback that we've become so used to we tend to see past it: Code is cluttered with error-checking routines. Exceptions here provide greater readability: Within a single try block, I can see the various steps clearly, and skip over the various exception remedies in the catch statements. The error-handling clutter is in part moved to the end of the code thread. But even in exception-based languages there is still a lot of code that tests returned values to determine whether to carry on or go down some error-handling path. In this regard, I have long felt that language designers have been remarkably unimaginative. How can it be that after 60+ years of language development, errors are handled by only two comparatively verbose and crude options, return values or exceptions? I've long felt we needed a third option.'"
Visual Basic had:
On Error Resume Next
I last typed that when I was about 13...
The documentation shows a couple of valid uses for it.
How can it be that after 60+ years of language development, errors are handled by only two comparatively verbose and crude options, return values or exceptions?
Of course, it could be that this just means that your own language horizons are too narrow. Prolog and icon come to mind.
Lacking <sarcasm> tags,
Sounds to me like you actually hate abusive exception handling. Exceptions that are in relevant places and handle the errors in meaningful ways are good. I've seen lots of code that actually handles the error, but then I work with competent people (and yes, that is a lovely thing).
Exception handling can make code cleaner. I'd much rather see a nice exception than return value checking as I can instantly see what kind of error is expected and what should happen if it occurs.
Please don't dismiss a step forward from return value checking just because you're unfortunate enough to have never worked with anyone who uses it properly.
There is at least one other method, which is available natively in Common Lisp. It's known as conditions, and involves registering a condition handler which, unlike an exception handler, runs in the context where the error occurs. The handler has access to zero or more dynamically-scoped restarts, which allow the computation to be resumed at well-defined points without unwinding the entire stack up to where the condition handler was established. The default condition handler is an interactive debugger, which allows the user to examine the state of the program and choose one of the available restarts.
Beyond Exception Handling: Conditions and Restarts
"The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
This is plainly false. C++ exception is near-zero-overhead, but only for success scenarios - i.e. when no exception is thrown. Actually throwing an exception is quite expensive in most C++ implementations. Java and .NET are similar - no-exception path is very fast, near-zero-overhead, but throwing is expensive.
Generally, that's exactly the trade-off you make. You can do exceptions cheap if you basically implement them the same as hand-checked error codes, but then you have the overhead of checking for the error code on every single function call - and those do add up. If you don't want that overhead, then you need some form of stack unwinding, where frames that need to inspect thrown exceptions, or to cleanup during unwinding, can register their handlers (and those that don't need either don't do anything at all - it's literally zero overhead for them). But then the exception throwing code has to walk through those handlers and invoke them, which is more costly then just return ERROR_CODE.