Wednesday, February 16, 2005

Fragile programming

There was a time when I practiced defensive programming. The theory was that code should be able to handle anything thrown at it.

What a bad idea!

If you're writing a square root function and someone hands you a negative number, DON"T fix it for them. Abort, throw an exception, trigger an assert, whatever! Just be sure that they know as soon as possible that they've done you wrong. (A compile-time error would be ideal.)

This rant was triggered by code throughout ACE and TAO that looks like:

if (do_some_function () != 0)
return -1; // this should not happen

(Yes, the comments are really there in the code.)

Adding an ACE_ASSERT (and the missing brackets which should have been there in the first place) to one instance of this "idiom" revealed a longstanding design error in ACE's handling of Thread Specific Storage.

I'd rather work with fragile code than helpful code!

Just to be thorough, the code should be:

if (do_some_function () != 0)
{
ACE_ASSERT(false);
return -1;
}

not:

ACE_ASSERT (do_some_function () == 0);

1 comment:

Brian Gilstrap said...

Indeed. What you call 'fragile code' and early detection is also frequently referred to as 'fast-fail'. The code does not attempt to recover from being handed garbage and trys to detect garbage as quickly as possible.

For example, in Java, it is not uncommon to have a setter method that sets a reference to some other object. Programmers frequently fail to check whether the passed value is null, even though correct behavior later requires an actual object to use. My constructors and setters frequently look like this:

/**
* Set the Foo object I'll use later.
*/
public void setFoo( Foo aFoo ) {
    aFoo.getClass(); // detect null quickly and easily
    theFoo = aFoo;
}