> >Returning error result more than one level is an anti-pattern. It means that you really need exceptions in this case, since you're starting to emulate them.
> Or maybe exceptions are the anti-pattern, and returning error codes is a more structured—i.e. refactorable—way of coping with such conditions.
Well implemented exception systems allow you to transparently handle exceptions up in the stack, not only in the local context that generated them. Instead, if you want to pass up error codes, you will have to manually make sure that every error code is passed as the error code of the current routine and the flow is stopped as soon as an error is detected.
Using error codes also makes it difficult to generate clear and details backtraces, unless your error-reporting routines have a way to write down where the error originally happened and how it has been propagated up in the stack. If you have such facilities then you have implemented an exception systems.
Posted Mar 30, 2012 10:40 UTC (Fri) by dgm (subscriber, #49227)
[Link]
> Well implemented exception systems allow you to transparently handle exceptions up in the stack
If by "transparently" you mean that the code can automatically unwind the stack frames of several unsuspecting functions, you're right. _All_ exceptions systems I know of do this. This is also usually pointed out as one of the weakness in exceptions, because an implicit flow of control is introduced, and you have to always be aware of it. Much like what happens when you write multi-threaded applications.
> if you want to pass up error codes, you will have to manually make sure that every error code is passed as the error code of the current routine and the flow is stopped as soon as an error is detected.
No you don't have to. You can have a global error object (à la errno) and pass up the error _condition_ (that is, that there has been an error). This can even been in the error object, you don't even need to return an special value. What you have to do is check explicitly after each call if there has been an error or not. This is a bug or a feature, depending who you ask. I personally find both useful sometimes, but I have been seen cursing both from time to time. Exceptions are tempting, for the same reason that garbage collection is: it helps you being lazy. But you have to be aware of the price you pay, and that it may come back to bite you later. My personal opinion is that anybody saying one or the other is The Right Thing(TM) is just a moron.
> Using error codes also makes it difficult to generate clear and details backtraces
This is simply not true. There's nothing preventing you from generating backtraces and what not if the language and/or the libraries provide you with the tools (I have done this in Python and Delphi, for instance).
> If you have such facilities then you have implemented an exception systems.
No, because the implicit flow of control that characterizes exceptions is missing.
Exceptions vs Error Codes
Posted Mar 30, 2012 11:56 UTC (Fri) by mgedmin (subscriber, #34497)
[Link]
> You can have a global error object (à la errno) and pass up the error _condition_ (that is, that there has been an error).
This pattern is the reason why the Internet is full of screenshots of those "Error: success" dialogs.
Exceptions vs Error Codes
Posted Mar 30, 2012 15:51 UTC (Fri) by khim (subscriber, #9252)
[Link]
True. But think about it: just why all these pictures are copied from one resource to another? Because they are rare and thus funny.
On the other hand uncaught exception dumped on the unsuspected user are so common nobody ever tries to ridicule them: it's not funny, it's just sad.
IMNSHO this shows that usually exceptions are not needed and dangerous (just like usually full GC is unneeded and problematic), but some help is welcome. Multiple return values in Go looks like goo 99% compromise. Just as scoped_ptr plus occasional shared_ptr are good compromise WRT GC - to bad Go advocates full GC...
Exceptions vs Error Codes
Posted Mar 30, 2012 18:26 UTC (Fri) by dgm (subscriber, #49227)
[Link]
Rather, it's more likely that the cause is using an special code to mean "no error".
Exceptions vs Error Codes
Posted Mar 30, 2012 16:14 UTC (Fri) by nybble41 (subscriber, #55106)
[Link]
> If by "transparently" you mean that the code can automatically unwind the stack frames of several unsuspecting functions, you're right. _All_ exceptions systems I know of do this.
IIRC, in Java you have to declare which exceptions a method can raise, including any which might be raised by lower-level functions, unless they are handled internally. So there are no "unsuspecting functions"; the only stack frames which an exception will unwind are those which declared that exception in the prototype. C++ has a similar feature, but it's optional, so it doesn't provide the same guarantees.
Of course, any language which supports non-local returns--including captured continuations and C's setjmp()/longjmp() routines--potentially has the same issue. Exceptions fall somewhere in between, since unlike setjmp() they allow for cleanup in the intermediate stack frames, but unlike continuations they are not (typically) flexible enough to implement arbitrary flow control.
Exceptions vs Error Codes
Posted Mar 30, 2012 16:22 UTC (Fri) by khim (subscriber, #9252)
[Link]
So there are no "unsuspecting functions"; the only stack frames which an exception will unwind are those which declared that exception in the prototype.
That's why huge amount of Java code includes empty catch statements. And still RuntimeExceptions blow up programs regularly. I'm not sure if it's even possible to sanely use exceptions, but C#/Java exception handling is disaster.
In my experience exceptions are useless in most cases: sometimes you really want to compartmentalize your program, but fork(2) works fine in such cases. If your task is not large enough to use fork(2) then it's probably not large enough to warrant complex exception-based schemes.
Exceptions vs Error Codes
Posted Mar 30, 2012 19:24 UTC (Fri) by dgm (subscriber, #49227)
[Link]
On the other hand, exceptions tend to work nice when you have to repeatedly call library functions that almost always work as intended (that is, errors are really exceptional). In that case you can save a lot of error checking and write simpler code.
Working with exceptions is tricky, but if you know (and follow) the rules it's not more difficult than treads or pointers (:-P)
I will not pretend to know all the rules, but those have served me well:
1. Never, EVER add exceptions to code written without them in mind (this applies basically to C/C++). If you want to use exceptions, do so from day one, or rewrite unaware code.
2. Never, EVER let an uncaught exception escape a callback or event handler. NEVER. And conversely, ALWAYS catch all exceptions when calling back external code or firing events.
3. DON'T use exceptions for common cases or conditions that are easily recoverable. They are best for situations that are truly exceptional and hard to recover from.
4. Program defensively, specially when holding resources (open files, locks, connections, memory). Expect unexpected exceptions everywhere. Your code will probably have a longer and more interesting live than you expect.
5. Handle exceptions ONLY where they make sense. Handling each and every exception everywhere just makes code complex, defeating their purpose. If (when) you find yourself in a mess of try...catches stop and reconsider the exceptions you're using. Do not discard avoiding exceptions altogether.
Ah, just one more thing: don't feed them after midnight. Just don't do it.
Exceptions vs Error Codes
Posted Mar 30, 2012 22:01 UTC (Fri) by khim (subscriber, #9252)
[Link]
On the other hand, exceptions tend to work nice when you have to repeatedly call library functions that almost always work as intended (that is, errors are really exceptional). In that case you can save a lot of error checking and write simpler code.
Yup. And as added bonus it'll guarantee your future employment when you'll find and fix dozens of security bugs and DOS cases.
4. Program defensively, specially when holding resources (open files, locks, connections, memory). Expect unexpected exceptions everywhere. Your code will probably have a longer and more interesting live than you expect.
This is what makes exceptions pointless. It's hard enough to find programmers which can correctly programs the common case. Someone who can correctly program all the exceptional codepaths will be usually too expensive. And will still miss some cases.
This is where fork(2) solution saves your beacon: sure, you still need to somehow handle cases where some shared resources (such as pipe or shared memory) misbehaves because other process died but most of the heavy lifting will be done by OS without your direct involvement: sockets will be freed, files will be closed and removed (you do remove temporary files right after open(2) call, because you need to handle poweroff case, right?), etc.
Go is trying to create something like this in a single process - but I'm not 100% sure how well it'll work.
Exceptions vs Error Codes
Posted Mar 30, 2012 23:13 UTC (Fri) by Cyberax (✭ supporter ✭, #52523)
[Link]
>This is what makes exceptions pointless. It's hard enough to find programmers which can correctly programs the common case. Someone who can correctly program all the exceptional codepaths will be usually too expensive. And will still miss some cases.
Nope. It's easy in C++ - just wrap everything in RAII-based holders. If you need a cleanup action then wrap it in ON_SCOPE_EXIT macro or make it a lambda function (C++11 is great!). Pretty easy once you get used to it.
On the other hand, meticulously handling return codes just doesn't happen if you don't force it through code reviews.
Exceptions vs Error Codes
Posted Apr 2, 2012 8:02 UTC (Mon) by jezuch (subscriber, #52988)
[Link]
> That's why huge amount of Java code includes empty catch statements. And still RuntimeExceptions blow up programs regularly. I'm not sure if it's even possible to sanely use exceptions, but C#/Java exception handling is disaster.
Nope. The reason for this is huge amounts of lazy and clueless programmers. And Java's exceptions are far from being a disaster. I actually love them, despite some wrinkles. There was a time when I submitted to this "exceptions are evil, declare everything as throwing Throwable" movement and I regretted this ever since. I'm also reminded of this every time I have to code something in C and error handling becomes a chore and pain even worse than manual memory management ;)