Контрактное программирование в 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() - специальная функция-член структур
и классов, позволяющая контролировать состояние
объекта всё время его жизни:
Поскольку все контракты удаляются в релизной сборке, пользовательский ввод
нельзя проверять с помощью контрактов. assert'ы можно использовать
в nothrow-функциях, поскольку они вызывают "фатальные" ошибки (Error).
Аналог времени исполнения для assert - std.exception.enforce,
вызывающий исключения (Exceptions), которые разрешено ловить.