Is the Contract Programming of D broken?
In my previous post I mentioned that I wasn’t sure of how the D Contract Programming feature works in an override scenario. Wekempf inspired me to delve deeper into the matter. Here is what I found.
Contract Programming states that preconditions may be weakened by a deriving class, but never hardened. For postconditions the reverse is true: they may be hardened but never weakened.
The D Programming Language specification states:
“If a function in a derived class overrides a function in its super class, then only one of the in contracts of the function and its base functions must be satisfied.”
In my experience this isn’t the case. Consider the following code:
class A { void f(int a) in { assert(a > 0); } out {} body {} } class B: A { void f(int a) in { assert(a > 1); } out {} body {} }
Method B.f overrides the corresponding method in A. If B.f is invoked with an argument of 1, the in-clause of B.f should fail and A.f succeed. According to the specification only one of the two needs to be satisfied. Let’s see if that’s true.
A o = new B; o.f(1);
The program halts with a contract failure in B.f. The preconditions of the base class is never even checked.
What happens if I add a call to the base class method?
class B: A { void f(int a) in { assert(a > 1); } out {} body { super.f(a);} }
It turns out that the super-call triggers the in-clause of the base class A (and only that one). It seems like the semantics differs from the statement in the specification. The current behavior opens up for abuse of the general principles of Contract Programming by allowing preconditions to be hardened and postconditions to be loosened.
I don’t care all that much though. To me it seems difficult to have the language enforce those rules anyway, at least while keeping the contracts flexible. And, the current behavior is what I’d expect if I wasn’t aware of the Design by Contract principles.
Update: It turned out that this feature is currently not implemented in the DMD compiler.