Contract programming in D includes a set of language constructs that allow increasing the code quality by implementing sanity checks that make sure that the code base behaves as intended. Contracts are compiled and executed when the software is built for testing or debugging. In release builds (enabled by the -release switch for DMD) they are completely omitted by the compiler, therefore they shouldn't be used to validate user input or as an alternative to using exceptions.
assertThe simplest form of contract programming in D is
the assert(...) expression that checks that a certain
condition is met - and aborts the program with
an AssertionError otherwise.
assert(sqrt(4) == 2);
// optional custom assertion error message
assert(sqrt(16) == 4, "sqrt is broken!");
in and out allow contracts to be formalized for input
parameters and the return values of functions.
long square_root(long x)
in {
assert(x >= 0);
} out (result) {
assert((result * result) <= x
&& (result+1) * (result+1) > x);
} do {
return cast(long)std.math.sqrt(cast(real)x);
}
The content in the in block could also be expressed
within the function's body but the intent is much clearer
this way. In the out block the function's return
value can be captured with out(result) and
verified accordingly.
invariant() is a special member function of struct
and class types that allows sanity checking an object's
state during its whole lifetime:
invariant() is called after exiting a member
function.
As all contracts will be removed in the release build, user input should not
be checked using contracts. Moreover asserts can still be used in
nothrow functions, because they throw fatal Errors.
The runtime analog to assert is std.exception.enforce,
which will throw catchable Exceptions.