Контрактне програмування D включає у себе набір мовних конструкцій, які дозволяють підвищити якість коду шляхом впровадження перевірок програми на відсутність очевидних помилок, що дає змогу переконатися, що код поводить себе, як передбачалося. Контракти доступні тільки у режимах відлагодження чи тестування та не будуть працювати у режимі релізу. Саме тому вони не повинні використовуватися для перевірки введених користувачем даних або як альтернативу обробки винятків.
assertНайпростіша форма контрактного програмування у D - це вираз assert(...),
який перевіряє, чи певна умова виконана, а також перериває програму за
допомогою AssertionError, якщо умова не вірна.
assert(sqrt(4) == 2);
// опціонально можна вказати власну помилку для користувача
assert(sqrt(16) == 4, "sqrt не працює!");
in та out дозволяють оформити контракти для перевірки вхідних
параметрів і результату функцій.
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);
}
Зміст блоку in також можна перенести у тіло функції, але втрачається
очевидність. У блоці out повернення значення функції можна перехопити
за допомогою out(result) і перевірити коректність результату.
invariant() - це спеціальна функція struct та class, що дозволяє
контролювати стан об'єкта напротязі всього часу його життя:
invariant() викликається після завершення функції-члена.
Оскільки усі контракти будуть видалені у релізній збірці, дані, введені
користувачем, не повинні перевірятися за допомогою контрактів. При цьому,
assert-и можуть бути використані у nothrow-функціях, тому що
вони породжують фатальні помилки (Error).
Аналогом часу виконання для assert-ів є std.exception.enforce,
який буде видавати виключення (Exception), які дозволяється перехоплювати.