Assertions As Defensive Programming

Opinions differ on whether assertions are DefensiveProgramming. Discussion follows.


DP is a DoubleEdgedSword. One ought to clarify whether one means the Good kind or the Bad kind. The following assertion is the bad kind.

Assertions are not an example, even with DesignByContract. Assertions are about documenting and verifying a specification. Adding code to handle failed cases is. Some people write:

    void test( int *p ) {
        assert( p != 0 );
        if (p == 0)
            return;
        // use p.
    }

This is defensive programming. It also suggests the coder has a split personality. Can p be 0 or not? -- DaveHarris

Your statement is too strong. Assertions are useful in verifying a spec, I agree. But invariants and assertions are necessary for programming defensively, IMO. If DefensiveProgramming doesn't believe this, I would have to believe that the definition is hopelessly broken.

I disagree, assertions and contracts can be disabled. Even in Eiffel. Also assertions cause failure if a constraint is violated, they don't protect from a constraint being violated.

Ok, but if you remove your assertions you are no longer being defensive... If a (true) invariant is violated, there is no possible local recovery. Your only valid responses are to die (e.g. c 'assert.h', rather extreme) or return failure in such a way that the caller can trap and retry. My point, I think, was that calling something Defensive'Programming without enforcing local sanity checks is silly.

Anyone recall the source of the quote to the effect that removing assertions is a bit like wearing a life-jacket to practice in the harbour, but then leaving the life-jackets behind when your ship leaves for open ocean.

The exact quote is: "What would we think of a sailing enthusiast who wears his lifejacket when training on dry land, but takes it off as soon as he goes to sea?", in C. A. R. Hoare, "Hints on programming langauge design", Stanford Artificial Intelligence Laboratory memo AIM-24, Stanford University technical report no. STAN-CS-73-403, 1973.


I don't know who said it but it is wrong. Assertions (at least as they are used in C++ and Java) are for catching programming errors during development. If you are going to leave them in production builds, then you shouldn't be using assertions at all and just replace them with errors and/or exceptions with handlers. For example, what good does this do a user:

   assert( n < MAX_PATH );

It just fails with a cryptic message. This assertion should only be in code for development because (a) you haven't had time to add the exception logic i.e. lazy or (b) it can only fail if your code is wrong and cannot happen dynamically. If you this assertion in a retail build you are just being lazy. Contrast the assertion to the following:

   if ( n >= MAX_PATH )
      throw overflow_error( "File name is too large" );

This is almost as bad given a single outer (or main-based) catch clause. Even better is something like:

   while ( retries-- > 0 && file.size() == 0 )
   {
       try
       {
           file.get_from_user( file );
       }
       catch ( const overflow_error& e )
       {
           message_box( e ).show();
       }
   }

Or some such. This is defensive programming because it attempts to handle error conditions while an assertion left in retail code is simply pretending to be defensive. -- RobertDiFalco

you are assuming that 'Assertion' == c style assert(). This is not the case. There is no reason that an assertion can't throw an exception, for example. The use of "Assertion" and "Invariant", etc. in code (production or otherwise) makes the intent very clear.


Yes I am. I tried to make it clear I am referring to assertions in C-style languages such as C++ or Java. FWIW, even Eiffel allows you to turn off calls to check And if you look at the previous post, it was a C/C++ style assert that was being used.

There is no reason that an assertion can't throw an exception, for example.

Actually, there is a big reason. Code should say what it does, it shouldn't have hidden exceptions being raised. Most people use exception checking or exception handling when referring to throwing or catching exceptions rather than calling these asserts. We can interpret the word assertion to mean anything we'd like but that just makes communicating more ambiguous. At least traditionally, most programmers think of assertions as checks for programming errors and not for generalized exception handling for dynamic situations. Otherwise, why would the language allow you to disable them? If we mean exception handling, why not just say exception handling? For me, wrapping exception handling in something called assert does nothing but make your code less clear and harder to maintain. I would suggest if you really want a one-line constraint checker that throws an exception when if fails that you call it something other than assert:

   raise_if( n >= MAX_PATH, overflow_error, "file name too long" );

However, this is still harder to read than simply programming what you mean, like so:

   if ( n >= MAX_PATH )
       throw new OverflowException( "file name too long" );

To me, this looks like exception handling rather than what most programmers think of as assertions. No one needs to wonder if there is a secret exception being thrown that they might want to handle, or in C-language vernacular, put a try...catch around.

-- RobertDiFalco

I wasn't suggesting it should be secret. Assertions (being language agnostic here) mean, simply, that you are asserting that a condition must be true. And so on for invariants, etc. Although c++ is not my primary language, it seems to me that this may be done in c++ using the exception idiom. In fact I seem to recall that Stroustrup discusses it in C++ Programming Language.

Anyways, my contention is that:

Assert<OverflowException>(n>=MAX_PATH);

is clearer than your example. Nothing is hidden, it is clear to the programmer that this throws an exception. It is also clear that the logic is there as an assertion.


Why is this clearer? It obfuscates the fact that an exception is being thrown, for what reason? Just so you don't have to type throw? I think, in general, people tend to think of assertions as binary -- the condition is true or false. This is the case even for languages like Eiffel. There are only two outcomes, success or failure. I don't often associate assertion checking with the flow of execution, throwing exceptions (other than assertion_error), or exception handling. For a different perspective, which is your primary language and how is the term used there?


Replying to:

you are assuming that 'Assertion' == c style assert(). This is not the case. There is no reason that an assertion can't throw an exception, for example. The use of "Assertion" and "Invariant", etc. in code (production or otherwise) makes the intent very clear.

The best argument against this is when in Rome, do as the Romans, as not to confuse new Romans who just arrived in Rome to work on your project. In C++, asserts mean taking down the process. Also specifically, assert means "turned on in debug mode only and won't make it to customers". If you want such a construct in release code, invent your own ala release_assert or something from BoostLibraries.

Then we devolve into the questions as to whether asserts should throw. This is a frequent question on comp.lang.c++.moderated. What I have gleamed from this IMO is that there are several things developers use asserts for. Traditionally, assert is there as a sanity check and a bug check. You know the class has this invariant, so you assert the invariant is true. If it triggers, the assert should be nice enough to dump core or open a debugger so you can see what's going on and fix it. It was intended as a development tool, not something to make it to customers.

Now, if such a sanity check on a class invariant makes it to customers, you generally want to stop the process right then and there. You don't want to throw an exception or return an error code. It might be from memory corruption, etc. Your sanity check failed, this could not be caused by bad input, so you do not know the state of the system, so doing anything else but gracefully stopping (dying with an error message usually, or possibly going to a debuggable state) risks corruption of data as the process continues.

Most such counterarguments argue from the standpoint that assert means something other than a sanity check. assert should not be used for validating user input, or input from untrusted sources (see GatedCommunity). assert is fine for asserting input within such a gated community.

Finally, the last argument is that it's TheSimplestThingThatCouldPossiblyWork. In this case, you could just die right there, or you could add complex error handling code. Suddenly everything can return an error if an invariant is violated. It quickly and greatly complicates your code for minimal gains, adding code which is (almost) never exercised, making it (near) impossible to test, which is just asking for pain. This applies doubly so for Java assertions which throw when they fail. Such codepaths, the thrown exceptions, are impossible to test for assets which are never hit. I try to avoid the built-in Java assertion for sanity checks at all costs. (Arguably because of the way Java is, a failed sanity check when hit can be isolated to a single component, so throwing an exception is not quite so heinous as it is in C++, where a failed sanity check means the entire process health is in question (read: buffer overruns, bad pointer accesses, memory corruption, etc.).)


CategoryDefensiveProgramming CategoryAssertions


EditText of this page (last edited April 3, 2013) or FindPage with title or text search