Fog Creek Software
Discussion Board




Exceptions necessary but should never be thrown

In my opinion a finished program will never throw an exception unless the error is caused by uncontrollable factors (like a network failure or the hard-disk filling up).

My code throws exceptions but only for things that should have been managed properly through the interface design.  For example: a time period's start time being after its end time.

A well designed interface (Joel's favourite topic) should make it so the error is impossible to create.  But having it there allows an oversight to be managed gracefully.

I used to use the C++ assert statement to handle possible errors but found that if something was missed in the testing phase the program would ship without assumptions being tested.

The downside is that the finished product will always run the if statement to check assumptions so I'm careful to keep them outside of loops.

Rob Wade
Thursday, October 16, 2003

A start time being after an end time implies a programming error (in most cases), so assert should be used for that.  Exceptions should be for, as you said, things beyond the programmer's control like network errors and such.

Ken
Thursday, October 16, 2003

You're right Ken, it is a programming error and an assert seems logical but when your compile your release version calls to assert don't do any checking.

If something is missed during the testing phase I don't want the program to do something untested.  Turning the assert checking off does exactly that.

Leaving the assert on and failing a test will close the program immediately whereas throwing an error can stop the execution at the problem point and allow the try{}catch{} around the program's message loop to handle the problem and continue execution.

It's still a bug but at least it doesn't close the program without warning.

Rob Wade
Thursday, October 16, 2003

The argument for turning off asserts in shipped code is that it boosts performance in code that has been assumed to run perfectly.  Asserts aren't always simple boolean/math expressions; they may involve time-consuming operations (searches, sorts, etc.) that can slow a program down unacceptably.

Personally, I take more of a proof approach in these cases.  If an assert is in a location where it could slow down an app significantly, it may be worthwhile to find all entry points to that assert, and prove that it will always succeed.  If the assert could fail on something uncontrollable, such as network failure or invalid user input, it probably shouldn't be an assert, but rather a part of the code itself.

Asserts as a rule should never be required in shipped code.  They're most valuable as an easy method for maintaining correctness.

Paul Brinkley
Friday, October 17, 2003

Whoops.  I meant to add, if an assert is in a low-traffic part of the code, then yes, it can be nice to just leave it in and ship it.  That way it's not hurting performance appreciably, and if the code breaks you have some nice post mortem data on it.  This is a bit of a low-budget solution, though, as an assertion failure can be very jarring to users.  At this point you're playing odds, risking the potential loss of users' confidence in the code against the effort and cost of ironing out all those failure points.

Paul Brinkley
Friday, October 17, 2003

*  Recent Topics

*  Fog Creek Home