Contract Programming in D
If you are a defensive programmer like me, you make heavy use of assertions to guard assumption you make in your code. For example, a method for adding an order item to an order object could look something like this:
class Order
{
private List orders;
int addItem(OrderItem item)
{
assert(assigned(item));
item.order = this;
assert(assigned(items));
items.add(item);
assert(items.count > 0);
return items.count;
}
}
This style of programming adds some clutter to the code, but makes the program more robust and reliable over time.
The D Programming Language have built in support for contract programming and I have been curios to see if that can be an alternative to my defensive programming style. At first look it seems to be a close match. Both techniques allow you to make safe assumptions in business logic code. The difference is where you put your defensive code.
In contract programming, or Design by Contract as it was originally called, there are the concepts of pre- and postconditions, conditions that are expected to be met on the entrance to and on the exit from methods. Additionally you have the concept of class invariants, which asserts a certain state before and after (but not during) a method call.
So, a transformed contract programming version of my defensive style example above could look something like this:
class Order
{
private List orders;
invariant { assert(assigned(items); }
int addItem(OrderItem item)
in { assert(assigned(item)); }
out {assert(items.count > 0);}
body
{
item.order = this;
items.add(item);
return items.count;
}
}
This may not seem like less clutter but it does two important things: First it separates the defensive code from the business logic. Pre- and postconditions are neatly placed in in- and out-blocks, while business logic dwells in the body-block.
Secondly, general assertions that may need to be checked in every method of the object (like checking that the orders list in the above example is assigned), are handled in in place: the invariant block. Nice and DRY.
It seems like I could use Contract Programming for the same purposes as the normal defensive programming technique, but there are a couple of issues that keep me from taking the step:
- I’m not sure how preconditions and postconditions are affected in an override scenario. The language specification says that preconditions are OR’ed together, meaning that if one precondition passes the others are ignored. My own tests show a different behavior, but I need to take a closer look to be sure.
- Contract Programming and Normal Defensive programming are conceptually two very different things: Contract Programming, like the name suggests, are taking place in between the programming interfaces of objects, while the assertion defensive style is more general. You can say that Contract Programming defends the Program Design against abuse, while the defensive programming style defends the implementation against unexpected events.
- Contract Programming moves the defensive code away from the code that benefits from its protection. This could become a maintaining problem.
I currently feel that Contract Programming should be used only in the context for which it was created: big projects with many developers, where a massive (not agile) design phase precedes an equally massive phase of implementation. But, I’ll probably use class invariants to DRY up my general asserts where applicable.