in reply to Defensive Programming

Why not just plain old last if $count == 10;? Is it ever possible for $count to be greater than ten without first being equal to ten? No. ... It's costless to replace == with >=, so I do it.

Trade-off time.

One problem with substituting >= for == is that you can mask catastrophic failures.

Murphy being omnipresent, it is possible for an otherwise incremented-by-one variable to suddenly take on an outrageous value. This happens more often by errant maintenance changes or some obscure code path than by cosmic rays. If that happens, you probably want to halt the program, rather than quietly ignoring the problem and going on.

This begs the question of whether it is worth adding extra sanity checking code before every reference to a variable. Maybe so, usually not. Some kinds of catestrophic failures are so catestrophic that you're going to blow up in short order anyway. And the extra code overhead can be a hit on performance.

In some languages, this kind of defensive programming is done a conditionally compiled ASSERT mechanism, which can be turned off during deployment. Writing

ASSERT(0 < $count && $count <= 10); last if $count == 10;
covers both the case of a normal fuse burning down and the abnormal event of the fuse suddenly going out of range.

I often do this when writing complicated logic in classes, where an object's instance variables (or Perl equivalent) can possibly be side-effected by an intervening method call. (Someone once thanked me for being defensive two years after I left a company. They'd being doing maintenace work to extend some stuff I'd done, and ASSERT code kept them out of trouble.)

In Perl, I'll sometimes add asserts during development, then comment them out when the code is stable. E.g.,   #die "assert" unless @{$p->{'children'}} > 0; This doubles a "real" comment.

Replies are listed 'Best First'.
Re: Re: Defensive Programming
by clintp (Curate) on Jan 15, 2002 at 03:20 UTC
    On the subject of catastrophic failures: I've written a lot of code that's in front of a lot of people. Little things like >= instead of == have made situations "manageable" where they might not otherwise have been. The appearance of being a little sloppy in a critical situation is far better than causing a disaster.

    You can never test enough. You can never design enough. The OP gave a trivial example. Wish he'd have had something better up his sleeve.

    Lemme give some examples (yes, these have actually occured):

    1. Old-time reporting system keeps line-counts to know when to issue a form-feed character. Change made to the footer of a report by a sloppy programmer caused the == condition to miss by one and the form-feed routine goes nuts and spews paper everywhere. This is not funny on a high-speed chain-printer with access to a 50lb box of paper. Or on a check printer where each check skipped costs money.

      Fixed the bug, changed the condition to >= and when a subsequent programmer caused a similar bug we got a few pages that printed with "widow" lines -- a far, far better problem.

    2. Medical records system contained a hash-and-sequential-search feature for finding individual records. Large installations notice a (o)n time for finding records when it should have been constant time plus a small hit for the sequential search. When a doctor is trying to find your drug allergies in a hurry, this isn't funny either.

      Turns out a programmer didn't notice that certain overflow conditions (hash collisions) near the end of the file caused a sequential search to wrap to the beginning of the file again without returning the failure. Small bug fixed, and a == changed to a >= ensured that if it ever cropped up again at most one additional sector of records would be read. (And it did, sector drops from the disk caused it to skip a sector and only a >= would catch it...)

    3. Countless small C and ASM programs I've seen where a "hang" problem has been introduced by an unforseen increment and a == missing slightly. This always happens in a demo or at a customer site. (Hi Murphy!) The "hang" eventually clears itself up after you wrap around a short, int, or long. If you've got an index variable with many friends in a block of code, defensive is always good.
    I'm gonna get --'d by the purists sure, but in my head as I'm writing these things I always thing "what if this loop gets away..." and imagine the worst (sometimes it's not that bad, or not possible). Murphy's an old friend of mine. He's not to be poo-poo'd with blanket statements of "better engineering". Sometimes this is better engineering.