Programming by Contract

A paradigm which was first introduced by Bertrand Meyer, the creator of Eiffel. Although Eiffel has support for programming by contract built into the language, most of the concepts can be used in any language. Programming by contract has reduced my time in the debugger by 90% or more - thus my belief in it. It also greatly reduces the need for error checking within your code since you "know" that a calling routine will have valid values coming into the routine. It also provides valuable user documentation which can be extracted by automated tools (such as the short tool found in Eiffel implementations.

Basically programming by contract creates a contract between the software developer and software user - in Meyer's terms the supplier and the consumer. Every feature, or method, starts with a precondition that must be satisfied by the consumer of the routine. And each feature ends with postconditions which the supplier guarantees to be true (if and only if the preconditions were met). Also, each class has an invariant which must be satisfied after any changes to the object represented by the class. In the other words, the invariant guarantees the object is in a valid state.

As an example, you might have a routine which expects an incoming paramater to be a non-NULL class pointer and guarantees to return the class with some new data stuffed in it. A C++ routine might look like:

   SomeClass::someFunction ( AnotherClass *fillMeWithData )
      // check any preconditions here
      preCondition ( fillMeWithData );   // non-NULL check

      // do your stuff to add the functionality here

      // check post conditions
      postCondition ( fillMeWithData->hasData() );  -- did we do what we said

      postCondition ( checkInvariant() );  -- class invariant check required 
                                           -- because of lack of lang support

The class invariant would check that the class is in a valid state after the call to someFunction. Note that in C or C++, a very simple definition of pre and post condition constructs is simply:

    #define  preCondition(c)     assert(c)
    #define  postCondition(c)    assert(c)

A better definition would allow compile time options to turn these conditions on or off individually (you might turn them off for performance before shipping a release, for instance). Better yet might be to have assert() used as a default but allow the developer to override assert() with an exception handling mechanism as well having the compile time options.

However, there is still a giant limitation in each of these implementations: they do not follow through inheritance. That is, if I create a new class derived from SomeClass above and someFunction was a virtual function which I am now redefining, I lose my contractual agreement for the new method. I must remember to manually insert the same pre/postconditions in this new method plus any alternative conditions for this particular method. Most likely this means you must have access to the C++ class implementation source code. And proper class invariant support is even trickier than pre/postconditions. BTW, if anyone has nice implementations for pre/postconditions and invariants in C++ that they'd like to share, I'd like to check them out as I have struggled unsuccessfully to find a solution that I am happy with. (On the other hand all of this technology is built into the Eiffel language.)

Still I think adding assertion technology (pre and post conditions) to C++ implementations is generally a good thing. Still not sold? Give it a try it on your next project and see if it helps.