Error codes vs exceptions: critical code vs typical code

Error codes or exceptions - which is better? Here's my answer:

  1. They have the same worst case - a human error can lead to a complete disaster.
  2. Exceptions are far safer for most code.
  3. Error codes are far safer for well-reviewed, critical code.

(As you can see from 2 and 3, I believe that most code is not critical and/or poorly reviewed; I think most people will agree on that one.)

Worst case: disaster

Here's a disaster with error codes (based on an example from a critique of Go's error handling):

seal_presidential_bunker()
trigger_doomsday_device()

If we fail to seal_presidential_bunker, we still trigger_doomsday_device, because the programmer forgot to check the error code. Human error has lead to a disaster.

(The original article doesn't specify exactly what the disaster is. One problem is that the presidential staff is not safe. Another problem is that the doomsday device got triggered - which wouldn't happen if an exception were thrown and left uncaught. Which of the two problems is the bigger part of the disaster depends on your worldview.)

Here's a disaster with exceptions.

open_the_gate()
wait_for_our_men_to_come_in()
close_the_gate()

If wait_for_our_men_to_come_in throws an exception, then we'll never close_the_gate, and the enemy will sneak in. Again - human error, disaster.

So in theory, exceptions and error codes are equally bad.

Exceptions are safer for most code

Most code doesn't trigger doomsday devices, nor deals with lethal enemies at the gates. When most code messes up, garbage appears on the screen or in log files, and a programmer shows up to debug the problem.

With exceptions, it's easier for the programmer to figure out why this garbage appeared, because the failure occurs closer to the point of the error.

f=open_users_file()
print_users_list(f)

If open_users_file() throws an exception, then the programmer will see a "No such file or directory" with a call stack and think, "why couldn't this idiot [possibly, me] bother to check if the file is there?" Then he fixes the bug and all is well again.

If open_users_file() returns an invalid file object (similarly to, for example, C++'s ifstream), then print_users_list (which doesn't check errors, either) might print an empty user list. The error might then become "No such user", or "Permission denied", etc. The program will fail further from the point of error - the file opening code - and you'll need to go back and figure out where the error is.

For production code, failing early isn't necessarily better. Failing early is what leaves the gate open for the enemies in the above example. Failing early due to a floating point error - instead of trying further just in case - was reportedly the root cause of the explosion of Ariane 5, costing $.5G.

But for most code, which:

  • doesn't lead to such large damages
  • is written rather hastily
  • is expected to have bugs
  • has programmers constantly attending to it and fixing those bugs

…for most code, failing early is better simply because it always makes debugging easier - even if it doesn't make the impact of the error smaller.

Error codes have another horrible anti-debugging quality: loss of information. Even if the program fails early with error codes, you usually only get the code of the topmost layer without all the details from below.

With an exception, you get a call stack, and an error string from the bottom layer. With a perror(), you get just an error string from the bottom layer ("No such file or directory" - which file? Who wants it?). With error codes, you get something like "User list management error" - the fact that it was a file opening error gets "swallowed" by layers of code converting low-level error codes to high-level ones.

It's possible to collect an "error code call stack" with all the information, but it's almost never done. Whereas an exception does it automatically for the laziest of programmers. Another win for whoever gets to debug the code.

Error codes are safer for well-reviewed code

Code reviews are generally easier with error codes than exceptions. Error codes mean that you must carefully look at function calls to see if the programmer handled the possible errors. Exceptions mean that you must imagine what happens if an exception is thrown anywhere in the flow.

Making sure that the opening of every gate is exception-safe - that the gate gets closed when an exception is thrown - is hard. C++ has RAII for the gate-closing (and Python has with and C# has using), and Java has checked exceptions for the exception-hunting.

But even if you have both and then some, it still seems hard. A program has a lot of intermediate states, and some of them don't make sense. An exception can leave you in this intermediate state. And it's not easy to wrap every entrance into an intermediate state using whatever exception-safety-wrapper your language gives you.

So I think it makes sense for Go - a language for writing critical production code - to shun exceptions. We use C++ with -fno-exceptions for serious production code and I think it's equally sensible.

It just doesn't make sense to write most of your code that way. In most of my code, I want to always fail early to make debugging easier, seeing the full context of the error, and I want that to happen without putting much thought into error handling.

And this is why I think exceptions should be embraced by all lazy programmers writing low-quality code like myself.

50 comments ↓

#1 Alex on 09.24.12 at 2:58 am

finally, anyone?

open_the_gate()
try
wait_for_our_men_to_come_in()
finally
close_the_gate()
end try

#2 Onne on 09.24.12 at 3:18 am

Or defers or on(exit) you can call them (see D language); so:

open_the_gate()
on(exit): close_the_gate()
wait_for_our_men_to_come_in()

#3 Beryoza on 09.24.12 at 3:19 am

Also found this blogpost and it's comments a good read about error-based vs exception-based programming:

http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx

#4 Entity on 09.24.12 at 3:36 am

"Exceptions mean that you must imagine what happens if an exception is thrown anywhere in the flow."

You mostly summed up in your own words why error codes are more preferred than exceptions. How can you have reliable systems when at any point during the programs well defined execution may or may not throw a exception.

Granted this depend heavely on the language. Though I still consider it a red herring because the whole exception vs error codes debates just simply comes down to returning more than one value from (memeber) functions/functions/methods.

#5 Uli on 09.24.12 at 3:42 am

Interesting article.

I'm always swinging back-and-forth on the issue. Mostly I'm coming away with the realization that exceptions cause terrible code-bloat (lots and lots of specialized exception classes) when one takes things like internationalization into consideration.

You can't just throw a formatted string (e.g. with the file name in it), because you can't show that to the user.

It almost feels like exceptions with an error code might be a way out ;-)

#6 Ivan Tikhonov on 09.24.12 at 4:24 am

Making it more declarative places problem into a somewhat orthogonal plane.

control_gates() {

if(are_our_man_approaching()) open_the_gate();
else close_the_gate();

}

#7 Oliver on 09.24.12 at 5:18 am

Well, I allways thought that the whole "exception handling"-thing was invented by CS professors because they were unable to teach their students how to write real-world error handling. Fact is: Exceptions are the worst thing that can happen in a (productive) application, for the simple reason that the resulting intermediate states are harder to handle then the proper passing of error codes from lower (file-io) to the upper layer (GUI) of the software.

#8 Steve on 09.24.12 at 6:03 am

Working on backend systems, I like exceptions. The happy path is straightforward, and the sad path is always the same: log a stack trace and terminate the request, process, job, etc. Error codes would just be a more complicated way of accomplishing the same thing for 95% of my code, where a thrown exception means programmer error. Now that I think about it, though, exceptions do have weaknesses when dealing with non-fatal error conditions. What I've been (unconsciously) doing is dividing work into setup->execute phases and paying very close attention to what can be thrown during a setup phase. Exceptions there don't necessarily mean a bug and my code ends up with catch blocks instead of return code checks.

#9 hacksoncode on 09.24.12 at 6:04 am

@Alex: the possible catastrophe in that code is that the gate could close on one of our men who was half way through when an exception occurred.

#10 JS on 09.24.12 at 6:14 am

I am also not decided on the issue, but you should note that there is third, often forgotten, option - error handlers. They are non-local just like exceptions, but they won't unwind the stack. So you may decide error strategy in the error handler, but handle the error at the place it occurred (for example by retrying).

What is better in my opinion:
exceptions > error codes (non-local error handling)
error handlers > exceptions (won't unwind stack)
error codes > error handlers (speed & simplicity)
That's the issue here.

#11 Yossi Kreinin on 09.24.12 at 7:10 am

@Alex, @Onne: of course the bug is trivial to fix, you just need to spot it or to not make it in the first place. The bug in the error codes example is equally trivial to fix - you just need to spot it or to not make it in the first place. The question isn't which option allows to write correct code - both do - but which option has worse consequences assuming human errors; my examples try to show that the worst case given human errors is the same.

#12 Yossi Kreinin on 09.24.12 at 7:14 am

@hacksoncode: that's a nice point! I didn't think of that… (I wonder if it proves my point that exceptions make critical code harder to write - or just that it's hard for me…)

#13 Yossi Kreinin on 09.24.12 at 7:17 am

@JS: error handlers are nice but there are many cases where they aren't an alternative to either exceptions or error codes but can at most complement them. That's because upon some of the errors, you need different control flow - as in, take a different exit path from a function - and an error handler can tell you to do that but then you must actually do that and for that you need exceptions, or execution conditioned on error codes, or something else - but something more than just the handler deciding the policy, something actually implementing that policy.

#14 Kat on 09.24.12 at 7:21 am

I don't understand your justification for #3. I agree that error codes has a *relative* advantage in this case, but not an absolute one, i.e., if you review your code carefully, exceptions lose a little bit of their advantage.

The two biggest problems I see with the reasoning here are that (1) it's rarely possible to isolate "critical" code completely (e.g., what if your close_the_gates() calls some string-handling function you wrote, which somebody goes and changes later to fix an unrelated bug? do you re-review every mission-critical section of code in the system after every code change?), and (2) virtually no code review ever catches every bug: you're only improving quality, not guaranteeing it.

Exceptions can respond to a problem by simply aborting, too. I can't recall a case of an exception leaving my system in an unstable intermediate state. Without an example of some code that would cause this, it seems like this is another scarecrow like "performance": a canard people cook up as an excuse to avoid exceptions.

#15 Yossi Kreinin on 09.24.12 at 7:21 am

@Entity: no, it comes down to what's done with the one of the (multiple) return values that indicates errors. The case for exceptions (at least for me) is that sometimes nothing is done, so you lose the error context, and sometimes what's done is to convert it to another error value but without preserving enough context information, so you lose some of the error context. In both cases, whoever debugs loses.

#16 Yossi Kreinin on 09.24.12 at 7:30 am

@Kat: first, exceptions, specifically, do have a cost - at the very least in space - and some types of storage are costly enough to make this cost prohibitive - and sometimes exceptions have serious runtime performance cost even if not thrown (you can blame the compiler but you can't blame the pragmatic, experienced developer for avoiding a feature because compilers repeatedly failed to implement it well.)

As to your point: I think exceptions are vastly harder to reason about than error codes. hacksoncode's example with closing the gate when one of our men tries to enter because of an exception thrown by wait_for_our_men and closing the gate in the finally statement is a nice illustration. I think that code reviews are thus vastly more likely to find error code-related problems than exception-related problems. I think of this as an example of an "explicit is better than implicit" motto - a Python's motto, ironically, Python being the exception-centric language that I use the most these days…

As to states exceptions leave my systems in… I wouldn't know I guess, because the programs that I do use exceptions in don't manage important state. If my compiler barfs and leaves a partially written out object file, it's a "logical disaster" because now the build system will think that the object file is available and barf later (say, at the linkage stage; an example how "failing early" eventually becomes "failing late"…) But it's not a "practical disaster" because there's a user seeing the error, and he asks for support or he just figures out that he should delete the object file because of the ICE and life goes on.

So this means that "unusable state" is a blurry thing; and to me this also means that you actually can separate critical and not-so-critical code rather well much of the time. My compiler is not safety-critical because you can always recompile and you can work around its bugs because there's a testing infrastructure looking for said bugs. The testing infrastructure also isn't critical in the sense that if it barfs, people will notice - what's important is that it doesn't silently report buggy code as correct. But code running in an aircraft or a vehicle is critical - in my case, code compiled with said compiler that runs in a vehicle is critical. Ergo, no exceptions. (Which has the big disadvantage of failing later, but a big advantage of being easier to review).

#17 Yossi Kreinin on 09.24.12 at 7:32 am

@Steve: I think the question is what's the worst thing your backend system could ever do, and whether it's possible to isolate the scary stuff (like dealing with someone's life or money).

#18 Eldar Insafutdinov on 09.24.12 at 7:42 am

I commented on HN with regard to exception handling in D programming language http://news.ycombinator.com/item?id=4565169 . With the scope guard statement you can avoid all of the problems and write exception safe code.

#19 Yossi Kreinin on 09.24.12 at 7:48 am

@Uli: why exception classes - why can't you use a format string table or some such to handle i18n, and how does the problem change with error codes? (With error codes formatting occurs further down the road, but either way, it does occur in some place, and in one place for every kind of error; so it looks like the amount of bloat would be about the same).

#20 Yossi Kreinin on 09.24.12 at 7:55 am

@Ivan Tikhonov: I think I understood your comment, even though I didn't quite understand from your pseudocode exactly when the gate is closed (I guess our men are "approaching" as long as they haven't "entirely entered"). So you say it'd work better if instead of a serial flow, we'd use something event-driven or a dataflow language or such? I think humans aren't very good at that - Verilog and make being two widespread systems of the kind and both being notoriously hard to debug; I think the problem is that this is inherently massively concurrent and there's a lot of ways a bug could bite you - you either get it right or you get it wrong, and debugging - hunting for bugs as opposed to just knowing what you did wrong - is really hard.

But that's another can of worms…

#21 Nathan on 09.24.12 at 7:55 am

How do you feel about D's exceptions? It's pretty easy to have a rule (applied at code review time) that all resource freeing must happen in a scope statement.

#22 Yossi Kreinin on 09.24.12 at 7:57 am

@Oliver: I think your example is, exceptions caught by a GUI event loop (and logged but without exiting the app or some such). That's really rather awful - especially the old Windows/MFC way of doing it where you catch (with __except or some such) things like memory access violations and just blithely keep running. The question is if it's equally awful if you do quit - compared to the case of just ignoring an error code and not quitting.

#23 Yossi Kreinin on 09.24.12 at 8:07 am

@Eldar, Nathan: is it that different from try/finally or RAII or with or using or… - in the sense that it's fine as long as you don't forget to use it? It's not just "resource acquisition" that matters - you could remove an item from a list and then put it on another list, and if an exception gets thrown midway, then your item isn't in any of the lists, forever. What should I do - have a scope guard putting the item back to the original list? That's wrong if I did manage to put the item into the second list. It's possible to get this right, I'm just saying that it's not easy and you have to pay attention to the option of exception getting thrown at every single spot and it's not just about end-of-scope resource cleanup, it's about having consistent state.

#24 JS on 09.24.12 at 9:03 am

@Yossi: Well, error handlers (and I really mean here something akin to Lisp restarts, which are unfortunately unavailable in most languages) simplify the error handling at the point, because you only need to handle the policy, and not the particular error types. Furthemore, they can implicitly unwind stack too if desired.

Interestingly, in low level programming, error handlers are much more commonly used.

#25 Yossi Kreinin on 09.24.12 at 9:11 am

@JS: restarts?! Now I see what you mean… But if they end up unwinding the stack - the ability where their extra power is compared to error callbacks - then I think "restart safety" is a lot like exception safety, that is, about equally hard to get right, not?

#26 JS on 09.24.12 at 9:18 am

@Yossi: I am not sure. If you change code that is being called, it can start throwing different exceptions, which means you need to change way you handle it in the caller. With restarts, you only have to modify the error handler itself (because the code responds to policy, not the error code).

#27 Yossi Kreinin on 09.24.12 at 9:23 am

@JS: I'm not sure I fully understood you; anyway, what I was referring to was the difficulty of dealing with the fact that the stack could be unwound anywhere in your code, thinking that it's about the same with stack-unwinding restarts.

#28 Yuval Greenfield on 09.25.12 at 3:40 am

When the languages are turing complete, everything is technically equivalent. Exceptions and error codes are no exception.

Another problem with error codes is they can give a false sense of confidence. I don't know a language which doesn't have some form of crisis management for runtime errors which circumvent error return values. Corrupt memory, broken hardware, etc. Exceptions are the only fit for crisis management of **unexpected/undocumented** error types.

E.g. in Go

open_the_gate()
wait_for_our_men_to_come_in()
close_the_gate()

You may expect the gate to always close while in fact a panic() can be thrown in extreme cases of wait_for_our_men_to_come_in, and bam, your gates are left open.

#29 Yossi Kreinin on 09.25.12 at 6:10 am

@Yuval: I didn't mean "equivalent in expressive power", but "equivalent in potential to create disaster through human error in the worst case"; I think it's somewhat orthogonal to expressiveness/Turning-completeness/etc.

As to a false sense of confidence - it's true that some errors blow up, but it's a closed set of errors a reviewer can look for throughout the code. Exceptions are an open set. I can say, "I've reviewed this code and nowhere does it corrupt memory so that's not a problem" (of course nobody has to believe me…). I cannot say a similar thing about user-triggered exceptions, because obviously there are some in correct code; so now it's a question of who calls who.

So that's my counter-argument about things like bounds errors for thoroughly reviewed code; I don't have a similar counter-argument for panic(), except that panics are a bit like asserts (that Go shuns…) in the sense that a panic says, "hey, this program is just busted - if I move forward I'd just do more damage". Of course it's not true that the busted program can judge the extent of damage due to proceeding vs not proceeding… Here you can have atexit handlers or some such, attempting to close gates or something…

Let's say that I vastly prefer to code with exceptions and I think I made it rather clear…

(OT: it looks like maybe we might meet in person soon, if I get to visit UW or NYR who AFAIK work with you these days.)

#30 Darren on 09.25.12 at 7:05 am

Eiffel's exceptions can exit in one of two ways: you retry the function that failed from the start, or you pass the exception up to the caller. There's no way to use them for normal processing, and no way to catch one and keep going. So you use them only for programmer errors, which you can't fix by using error codes anyway. In Eiffel, programmer errors include not checking for error codes, so you're good there.

Failing early due to not retrying was not the cause of the Ariane crash. They put code into the vehicle from an earlier vehicle that would not work with work with the new vehicle. It didn't matter whether it was exception, error code checking, or none of the above. If it threw an exception, it would have shut down the hardware. If it didn't throw an exception, it would calculate values out of range of the storage they were in, which would just as surely crash the vehicle. The range controller blew up the space craft because it had a fatal error in the code, and that was the last-ditch exception/error handler. All they needed to do to fix it was to have tried actually using the old code in the new environment before they actually set it on top of thousands of tons of explosives.

If you use exceptions for programmer errors and error codes for things you expect will "fail" even in a correctly-written program (such as trying to open a file), you get easy to write and easy to read code.

#31 Yuval Greenfield on 09.25.12 at 8:29 am

@Yossi, yes, I believe we might meet indeed.

#32 Ed Smits on 09.25.12 at 10:58 pm

Good points made, great examples! Best understood when you have faced some disasters yourself ;-) My point: someone without experience will probably not comprehend the truth of this article. Ed Smits

#33 j5c on 09.26.12 at 1:15 am

Exceptions and error codes should be two different animals. Error codes are best as responses from lower level code that you have failed a constraint (e.g. that the file you are opening actually exists) and that you can cater for as normal execution. Exceptions should be reserved for complete failures that are unrelated to normal constraints. e.g.

err = f.openfile( filename )
if err == OK then
// Normal processing
elseif err == filenotexist then
// …
elseif err == accessnotallowed then
// …
else // Something we do not cater for
throw exception

#34 Peter Laman on 09.26.12 at 3:39 am

I'd say, we'd better take the word "exception" literally and reserve exceptions for exceptional situations that are not part of the normal program flow. For example, IMHO, a general file_open function should not throw an exception, if the file doesn't exist. It may not even be an error in a given situation. At least, it's quite a common condition. One thing to avoid is "flow by exception", because it easily leads to code that's hard to follow and exceptions do have a performance penalty. Exceptions tempt people to handle errors, as if they're detecting mines in a mine field, by simply setting their foot and see if anything explodes. I've seen many times that exceptions are thrown an caught 20 steps down the call stack and of course that leads to almost unpredictable software.

#35 Stefan on 09.26.12 at 3:40 am

I haven't checked if this is mentioned in the comments, but there is one distinct advantage of exceptions, that no amount of error code programming can emulate: Your application will never silently die on you!

Simple example: If you fail to check a pointer (in C/C++) that is result of a function and dereference it without testing, your application might crash and will be gone, without any chance of reporting a problem, or saving the current state. With exceptions it's trivial to catch all errors at the topmost level and at least dump the current state for later recovery.

More importantly, if you constantly write all the user actions to a log file (quite useful for emulating certain error conditions), catching an exception at the top level allows you to flush the most recent output and close the file properly. But if the application silently dies, your buffer might swallow the most recent events, which are usually the most informative pieces of information.

#36 Lawrence Knowlton on 09.26.12 at 7:59 am

My feeling is that exceptions should only be used for handling programming errors and not flow of the application. If user input is causing your code to fail, your code obviously has flaws, regardless of the user error. We use an application where I work that won't even let you type in the file type for a report's output file. Unless you use the drop down menu to trigger the onselectedindexchange or similar event, you get an error message stating it can't find/determine the file type. It's very frustrating useabilty wise, but I'm sure it saves time to lock down the interface and not deal with having to check a user's manual input. On the one hand, I think it's the coders being lazy, but on the other hand the application is huge and doesn't need bloat.

#37 diddle on 09.26.12 at 9:28 am

I think there are individuals who have posted here that don't fully understand exception based vs non exception based languages. For example, C# is an exception based language. it uses exceptions because returning error codes would make the calling code dependent on the called method (object). That creates a object to object dependency, which breaks the rule of encapsulation. While working in a non exception based language like C, error codes are perfectly acceptable. If you find that while using exceptions your code gets run down with them and bloated by exception based classes you, once again, don't fully understand exceptions and how to use them. Refer to these articles.
1. http://codebetter.com/karlseguin/2006/04/05/understanding-and-using-exceptions/
2. http://www.artima.com/intv/handcuffs.html
3. http://russellallen.info/post/2011/03/11/C-net-Exception-Handling-Best-Practice-As-Easy-as-1-2-3.aspx

#38 Yossi Kreinin on 09.26.12 at 10:36 am

@Darren: I read a claim by Kahan somewhere that if no exception were raised and the program just pushed forward, it'd be OK, perhaps, because it was the dumping of a core snapshot that clogged a communication channel or such; if I'm wildly off track here I should find that bit again and re-read it.

As to "exceptions for programmer errors, error codes for legitimate runtime errors" - first, I think the line is a bit blurred (say, sometimes you open a file that your own code wrote and if the file isn't there, it's actually a programmer error that this bit of code got called at all; of course you can check the error code and raise an exception…); and second, do you think this separation makes it easier to spot human errors related to handling exceptions/error codes incorrectly?

@j5c, @Peter Laman: I think your claim is a bit similar to Darren's; again - why, in that scenario, are programmers likely to properly handle all error codes, including the propagation of the error up a potentially large call chain, and the collection of context information needed for debugging?

@Stefan: actually, in C or C++, at least on some systems or after some work on your behalf to make your system support it, you can dump core and send it as the error report, and it's way more detailed than an exception call stack; I wish all languages and systems had that. In fact one disadvantage of C++ exceptions is that they unwind the call stack - I'd much prefer an uncaught C++ exception to dump core without unwinding the call stack. (It's possible to use C++ exception classes that record a stack trace before being thrown using some platform-specific hack, but I don't know of a way to get them to figure out that they're not going to be caught by any handler and dump core on the spot without destroying the local variables of said call stack).

#39 Yossi Kreinin on 09.26.12 at 10:41 am

@Lawrence Knowlton: my question to you as well as Darren and a few others is, why do you think programmers are likely to properly handle error codes - a rather hard job that usually isn't needed to get a first version of anything out the door? The reason I like exceptions is that such a poorly written first version tells more than nothing about its problems when it encounters problems in the wild.

@diddle: I think someone opposing exceptions won't be comforted by knowing that he got to use an "exception-based language", nor will someone who dislikes error codes be happy with C or Go just because they're "not exception-based"…

#40 kk on 09.26.12 at 8:28 pm

all wrong

#41 McZ on 09.29.12 at 3:48 am

That gate-opening code is not much different to connection-opening-code. I wonder, how many C#-developers are out there not not wrapping the Connection into a using-clause enforcing the call to IDisposable.Dispose!?

As for throwing exception on non-existing files. It's a programming error on the coders behalf and qualifies for the 'most code' definition here. A proper program would either check existance of the file or would open a file with the assumption, that it should be created if it doesn't exist.

An example on how to not use exceptions is the firing of an EndOfStreamException at the end of a stream which you are forced to catch if using when network-streams (as length throws a NotSupportedException). It would be much better to iterate Streams through IEnumerable. Btw, the NotSupportedException is clearly an example, too. If the Length-property would be delivered through a perceived ILength-contract instead of being on the Stream-class, it would be much cleaner and would not enable developers to invoke methods not implemented.

#42 Stupe on 10.01.12 at 1:18 am

In C++, I'll just throw out with no intent to defend it that exceptions are ALWAYS potentially a BIG problem.

In Java they are fine in their implementation but it just doesn't work in a low-level language.

But the ultimate solution has to be testing. Any code that throws errors is easy to test, just provide the cases to cause them and see if it handles them properly.

I don't dislike exceptions themselves as it's a quick, easy way to catch dumb errors in development but they do nothing at all to help with program correctness and error codes don't do much either.

#43 Yossi Kreinin on 10.01.12 at 7:16 am

Testing error handling is very hard though - in particular, if you haven't thought of some of the possible error conditions, you're unlikely to cover it in your tests.

#44 nanasisan on 10.01.12 at 7:33 am

> An exception can leave you in this intermediate state.

How can an error code avoid that?

I've seen many C codes that leave FILE open (or leaking allocated memory, etc) on one or more error paths. I think intermediate states comes from existence of errors. The way to handle errors doesn't matter. There are different review points for each way.

Exceptions have a rather new review points for intermediate states some people just don't know; check use of RAII, "with" statement, etc.

For me, checking use of RAII seems easier than checking every explicit code paths for intermediate states.

#45 Yossi Kreinin on 10.01.12 at 7:47 am

@nanasisan: with error codes you see the error paths, with exceptions you don't (how do you tell where an exception can/cannot be thrown through the code by looking at that code and without checking the definitions of everything it uses)?

The problem with RAII, with statements, etc. is that you need to wrap things like moving something from one list to another. It's easy to see if file objects are wrapped but it's less easy to spot all the one-time logical operations that actually would need to be undone upon stack unwinding, and it's not necessarily convenient to wrap them all.

#46 nanasisan on 10.01.12 at 8:29 am

@Yossi With exceptions, you don't have to see every error paths if the intermediate state is properly guarded with an appropriate tool. Actual paths are not review points.

And an analogy again; how do you tell that an absence of explicit branch after a function call means that no error code cannot be returned, or that the programmer forgot the check, by looking at that code and without checking the definitions of the function? I know there are some modern techniques, like multiple return values, can be a solution. But most existing code I've seen doesn't take such solution. Thus, I have to know or guess about errors on both ways to handle errors, not only on exceptions.

For "one-time logical operations", a try block with catch-all or finally (or scope statement in D, at best) seems appropriate to guard such a state, and seems not worse than explicit branches.

#47 Jussi Santti on 10.01.12 at 9:09 am

@Darren
>exceptions for programmer errors only
@Peter Loman
>avoid "flow by exception"
@j5c
>Exceptions should be reserved for complete failures

Are all on target. A fourth and quite common way of saying it is "failures are no program flow cotrol structures". Subroutine call, if and loop are the only control structures (in imperative langiages).

#48 Jussi Santti on 10.01.12 at 9:13 am

"EXCEPTIONS are no program flow cotrol structures".

#49 Uri W on 10.02.12 at 3:42 am

I failed to understand why the text is not gender neutral ?
"Then he fixes the bug and all is well again" ….
Nothing is well - you sexist

#50 Yossi Kreinin on 10.02.12 at 4:12 am

@Uri W: I am very willing to have you as a guest author on a technical topic of your choice so that you can expose us all to a higher standard of thought and expression.

Leave a Comment