Back in the early 90’s I went to work for a small, progressive company that was creating and selling C++ class libraries. At this time Object-Oriented programming was still quite new and the developers at the company were a talented group of people who approached programming with a balance of academic rigor and humble pragmatism. Selling code other programmers used in their applications meant that the code we sold had to as error free as humanly possible. This meant large, exhaustive tests suites, and copious use of what we called pre-conditions and post-conditions.
Pre-conditions and Post-conditions
Frequently, before a function begins executing we require certain conditions to be true for the function to successfully complete. These conditions may be upon the functions arguments, like a reference not being null, or an integer being non-negative or, if the function is a member function on a class, we may require the class instance to be in a particular state. For example, many collection iterators do not reference a collection element when first constructed, you must first call the next method before invoking a dereference method. Doing otherwise will cause an error. In this case the iterators’ dereference method has a pre-condition that the given instance must be actually looking at a valid collection element location. Similarly, after a function has completed we frequently expect certain post-conditions to be true. If the function computes a return value, we expect it to a valid one. In addition, if the function is a class member function, we may require its invocation to have changed the state of the instance it was invoked upon and a post-condition is a check on the validity of that final state.
In the Old Days…
The pre and post condition code we used took the form of C/C++ macros taking a Boolean parameter and were placed at the beginning and end of a functions body. Unless a “debug” preprocessor symbol was defined in the compile, the macros expanded to nothing. Thus, not using the condition macros for fear of impacting performance sensitive code with overly obsessive error checking was not a valid excuse. I really liked the idea of pre and post conditions and used them frequently. Sure, invalid input or state will cause an error, hopefully an exception, to occur anyway, so why bother with the extra code? Here are a few reasons:
- The error that occurs when a pre-condition for a function is not met may be triggered several function calls later, and it may not be obvious that the error occurred from something like invalid input to a function several levels up in the call stack. This is also true for function post-conditions. If, say, invalid input is returned, it may cause an error far removed from the point of infraction. It’s best to identify these problems as close as possible to the source.
- It saves time. Checking for things like valid input arguments is something most programmers do anyway with an if-then-throw statement. Some kind of condition checking code can make this check a one-liner.
- It makes code more readable. A function with pre and post conditions makes it explicit to the reader exactly what assumptions are necessary for the function body to execute and what constitutes a successful execution.
Pre and post conditions are especially useful for numeric programming. Many mathematical functions have restricted domains, like square root, and log, and linear algebra operations involving matrices and vectors usually require those objects to have consummate dimensions. Many times these errors do not occur immediately upon a function invocation or return, but are removed from those execution points.
Back to the Future
As I moved on to work with other companies, I did not encounter any other explicit pre and post condition checking practiced by the programmers. And, I must admit, I didn’t ever overcome the inertia of having to roll my own, though I did think about doing it more than once. Now the .NET platform has now provided me with pre and post condition checking code! The project goes by the shorter – but just as descriptive – moniker of “Code Contracts” and promises to be much more robust than the old C/C++ macros I had used in the distant past. I won’t go into detail about Code Contracts here, because there is lot of information available on line and because we have not yet started using them in our code so I don’t know a lot about them. However, I look forward to taking .NET Code Contracts for a test drive.