I\'ve read plenty of articles (and a couple of other similar questions that were posted on StackOverflow) about how and when to use assertions, and I understood the
Though I agree that your reasoning is plausible -- that is, if an assertion is violated unexpectedly, it makes sense to halt execution by throwing -- I personally would not use exceptions in the place of assertions. Here's why:
As others have said, assertions should document situations that are impossible, in such a manner that if the allegedly impossible situation comes to pass, the developer is informed. Exceptions, by contrast, provide a control flow mechanism for exceptional, unlikely, or erroneous situations, but not impossible situations. For me, the key difference is this:
It should ALWAYS be possible to produce a test case which exercises a given throw statement. If it is not possible to produce such a test case then you have a code path in your program which never executes, and it should be removed as dead code.
It should NEVER be possible to produce a test case which causes an assertion to fire. If an assertion fires, either the code is wrong or the assertion is wrong; either way, something needs to change in the code.
That's why I would not replace an assertion with an exception. If the assertion cannot actually fire, then replacing it with an exception means you have an untestable code path in your program. I dislike untestable code paths.
Assertions are used to check the programmer's understanding of the world. An assertion should fail only if the programmer has done something wrong. For example, never use an assertion to check user input.
Asserts test for conditions that "cannot happen". Exceptions are for conditions that "should not happen but do".
Assertions are useful because at build time (or even run time) you can change their behavior. For example, often in release builds, the asserts aren't even checked, because they introduce unneeded overhead. This is also something to be wary of: your tests may not even be executed.
If you use exceptions instead of asserts, you lose some value:
The code is more verbose, since testing and throwing an exception is at least two lines, while an assert is only one.
Your test and throw code will always run, while asserts can be compiled away.
You lose some communication with other developers, because asserts have a different meaning than product code that checks and throws. If you are really testing a programming assertion, use an assert.
More here: http://nedbatchelder.com/text/assert.html
Suppose you are a member of a fairly large team and there are several people all working on the same general code base, including overlapping on classes. You may create a method that is called by several other methods, and to avoid lock contention you do not add a separate lock to it, but rather "assume" it was previously locked by the calling method with a specific lock. Such as, Debug.Assert(RepositoryLock.IsReadLockHeld || RepositoryLock.IsWriteLockHeld); The other developers might overlook a comment that says the calling method must use the lock, but they cannot ignore this.
Use assertions for things which ARE possible but should not happen (if it were impossible, why would you put an assertion?).
Doesn't that sound like a case to use an Exception
? Why would you use an assertion instead of an Exception
?
Because there should be code that gets called before your assertion that would stop the assertion's parameter being false.
Usually there is no code before your Exception
that guarantees that it won't be thrown.
Why is it good that Debug.Assert()
is compiled away in prod? If you want to know about it in debug, wouldn't you want to know about it in prod?
You want it only during development, because once you find Debug.Assert(false)
situations, you then write code to guarantee that Debug.Assert(false)
doesn't happen again.
Once development is done, assuming you've found the Debug.Assert(false)
situations and fixed them, the Debug.Assert()
can be safely compiled away as they are now redundant.
Another nugget from Code Complete:
"An assertion is a function or macro that complains loudly if an assumption isn't true. Use assertions to document assumptions made in code and to flush out unexpected conditions. ...
"During development, assertions flush out contradictory assumptions, unexpected conditions, bad values passed to routines, and so on."
He goes on to add some guidelines on what should and should not be asserted.
On the other hand, exceptions:
"Use exception handling to draw attention to unexpected cases. Exceptional cases should be handled in a way that makes them obvious during development and recoverable when production code is running."
If you don't have this book you should buy it.
Debug.Assert by default will only work in debug builds, so if you want to catch any sort of bad unexpected behavior in your release builds you'll need to use exceptions or turn the debug constant on in your project properties (which is considered in general not to be a good idea).