Menu

Контрактное программирование

Контрактное программирование в 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), которые разрешено ловить.

Подробнее

rdmd playground.d