====== Контракт ====== **Контракт** - правило, обеспечивающее соблюдение программой формальных требований. Является центральным понятием контрактного программирования. Основная идея контрактного программирования - заменить неформальные соглашения в коде формальными. Например, в языках без поддержки контрактов автор некой функции может указать в документации условия для входных данных этой функции - такой подход не дает гарантии, что пользователь прочитает документацию и будет использовать функцию правильно. И наоборот - программист может давать неформальные гарантии о поведении функции или о ее результатах, но де-факто нарушать их вследствие ошибки. Контрактное программирование позволяет уменьшить риск подобных недоразумений путем введения формальных спецификаций для компонентов программы непосредственно в коде. Использование контрактов позволяет сделать программу более надежной без необходимости постоянного регрессионного тестирования - иными словами, избежать ошибок, когда после внесения изменений в программу перестает работать то, что работало ранее. В этом смысле контрактное программирование является альтернативой разработке через тестирование (test-driven development), но ничто не мешает использовать обе парадигмы одновременно - в некоторых языках (например, в D) они дополняют друг друга. Однако некоторые виды контрактов позволяют верифицировать то, что невозможно верифицировать при помощи тестов. В основе парадигмы контрактного программирования лежит логика Хоара - способ формального доказательства корректности алгоритма. Она оперирует такими понятиями, как предусловие, постусловие и инвариант. ===== Виды контрактов ===== * **Предусловие** (precondition) - контракт, который должен быть исполнен перед выполнением функции. Применяется к параметрам функции * **Постусловие** (postcondition) - контракт, который должен быть исполнен после завершения функции. Применяется к возвращаемому значению функции * **Инвариант** (invariant) - контракт, который должен быть исполнен после изменения некоего состояния. Используется для проверки соответствия состояния условию. К контрактам также можно отнести следующие языковые конструкции: * **Утверждение корректности** (assertion) - условие, которое должно быть выполнено до перехода к следующему утверждению в потоке * **Интерфейс** (interface) - контракт, гарантирующий доступ к определенным методам класса * **Атрибуты** (attributes) - правила семантического анализатора, гарантирующие соблюдение определенных условий на этапе компиляции. Например, в языке D есть следующие атрибуты: * **pure** - чистая функция. Такие функции не имеют доступа к внешнему контексту и внешним функциям и могут вызывать только другие чистые функции, что гарантирует отсутствие побочных эффектов. Возвращаемое значение чистой функции зависит только от ее параметров * **nothrow** - функция, которая не выбрасывает исключение * **@safe** - безопасная функция. Безопасные функции обязаны соблюдать ряд требований: например, в них не разрешается приведение и арифметика указателей, использование системных вызовов, приведение неизменяемого типа к изменяемому и др. * **@trusted** - доверенная функция. Является функцией, которая может быть вызвана из безопасной функции, но безопасность которой не проверяется компилятором. Атрибут служит своеобразным компромиссом между формальным и неформальным контрактом * **@nogc** - функция, не использующая сборщик мусора. В таких функциях запрещены некоторые операции языка, связанные с динамическим выделением памяти * **const** - атрибут-спецификатор типа, обеспечивающий доступ к данным только для чтения * **immutable** - атрибут-спецификатор типа, обеспечивающий неизменяемость данных.