Ddoc $(SPEC_S Contract Programming, Contracts are a breakthrough technique to reduce the programming effort for large projects. Contracts are the concept of preconditions, postconditions, errors, and invariants. Contracts can be done in C++ without modification to the language, but the result is clumsy and inconsistent.
Building contract support into the language makes for: $(OL $(LI a consistent look and feel for the contracts) $(LI tool support) $(LI it's possible the compiler can generate better code using information gathered from the contracts) $(LI easier management and enforcement of contracts) $(LI handling of contract inheritance) ) The idea of a contract is simple - it's just an expression that must evaluate to true. If it does not, the contract is broken, and by definition, the program has a bug in it. Contracts form part of the specification for a program, moving it from the documentation to the code itself. And as every programmer knows, documentation tends to be incomplete, out of date, wrong, or non-existent. Moving the contracts into the code makes them verifiable against the program.
assert
in function bodies
works by throwing an AssertError
,
which can be caught and handled. Catching the contract violation is useful
when the code must deal with errant uses by other code, when it must be
failure proof, and as a useful tool for debugging.
Either the in
or the out
clause can be omitted.
If the out
clause is for a function
body, the variable result
is declared and assigned the return
value of the function.
For example, let's implement a square root function:
------
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 assert's in the in and out bodies are called contracts.
Any other D
statement or expression is allowed in the bodies, but it is important
to ensure that the
code has no side effects, and that the release version of the code
will not depend on any effects of the code.
For a release build of the code, the in and out code is not
inserted.
If the function returns a void, there is no result, and so there can be no result declaration in the out clause. In that case, use: ------ void func() out { ...contracts... } body { ... } ------ In an out statement, $(I result) is initialized and set to the return value of the function.