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 only available in debug mode and won't be run in release mode. Therefore they shouldn't be used to validate user input.
assert
The 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 to formalize contracts for input
parameters and return values of functions.
long square_root(long x)
in {
assert(x >= 0);
} out (result) {
assert((result * result) <= x
&& (result+1) * (result+1) > x);
} body {
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 assert
s can still be used be in
nothrow
functions, because they throw fatal Errors
.
The runtime analog to assert
is std.exception.enforce
,
which will throw catchable Exceptions
.