Wednesday 21 December 2005 — This is 20 years old. Be careful.
A debate about asserts flared up in the fall, and I only just now caught up with it. Len Holgate started it with Asserts are Evil. His complaints center mostly around how asserts are traditionally implemented (only in debug builds, and they exit the program if failed).
B (?) mostly agreed: Assertions are still evil. It’s in the comments on that thread that the defining phrase was coined: Len Holgate described asserts as “exploding comments”.
Noel Llopis came to assert’s defense with Asserting Oneself.
I’ve written about asserts before, and I’m all for them. Programmers need every tool they can get to help nail down the often slippery semantics of the complex beasts they are building. Even if they are only exploding comments, isn’t that better than just plain-old comments?
The biggest misconception about asserts (and I think the heart of Len’s complaints about them) is the confusion of the caller’s semantics with the implementation details. The main thing I learned while writing my Asserts essay was the detailed semantic of an ASSERT statement:
ASSERT(expr)Asserts that an expression is true. The expression may or may not be evaluated.
- If the expression is true, execution continues normally.
- If the expression is false, what happens is undefined.
That last word is the most important: if the expression is false, what happens is undefined. Note that nothing is said about debug vs. release builds. Nothing is said about exiting the process. So when Len complains,
assertions are often hard to test for; try and write a unit test that proves that a “traditional” assert works... It’s complicated because assert ends the program...
how does he know the failed assert will end the program? Who said? He’s assuming a detail about the implementation of the assert. It sounds like he’s living with too-simple an implementation.
In the assert framework I built at work, a failed assert could do one of a number of things:
- Log a big red error message with a stack trace,
- Throw an exception,
- Display a dialog box,
- Run an external program,
- Debug the process,
- Abort the process,
- Nothing (ignore the failed assert),
- or a complex combination of the above.
The decision about what to do is mostly controlled by defaults based on product (clients display a dialog, servers throw an exception), but could be affected by registry settings, or by the user’s choice if a dialog comes up.
The anti-assert people assert (!) that unit testing is a much better way to guarantee the correctness of an implementation. I’m all for unit tests, but have found it very difficult to build them for complex systems being built on tight deadlines. But unit tests depend on asserts, so I’m not even sure it’s an either/or situation. In many unit test frameworks, it is specifically failed asserts that signal the test failure to the test runner, which continues on to the next test.
I say asserts are good. I’ve found them very useful for building self-diagnosing code that can raise the alarm when it hasn’t adapted to changing requirements fast enough.