Введение

В компьютерном программировании, утверждение – это концепция, заключающаяся в том, что предикат всегда истинен в определенной точке выполнения кода. В компьютерном программировании, особенно при использовании императивного подхода, утверждение представляет собой предикат (булевозначную функцию, зависящую от пространства состояний и обычно выраженную в виде логического утверждения с использованием переменных программы), привязанный к конкретной точке программы, который должен всегда возвращать истину в этой точке выполнения. Утверждения могут помочь программисту понять код, компилятору – скомпилировать его, а программе – выявить собственные ошибки. Для этого некоторые программы проверяют утверждения, вычисляя предикат непосредственно во время работы. Если предикат оказывается ложным – происходит сбой утверждения – программа считает себя неисправной и обычно намеренно завершается аварийно или генерирует исключение об ошибке утверждения.

Использование

В языках, таких как Eiffel, утверждения являются частью процесса разработки; в других языках, таких как C и Java, они используются только для проверки допущений во время выполнения. В обоих случаях их можно проверять на корректность во время выполнения, но обычно их также можно отключать.

Заявления о конструкции в договоре

Утверждения могут служить формой документации: они могут описывать состояние, в котором код должен находиться перед началом выполнения (его предусловия), и состояние, в котором код должен перейти после завершения выполнения (посткондиции); они также могут задавать инварианты класса. Eiffel интегрирует такие утверждения непосредственно в язык и автоматически извлекает их для документирования класса. Это важная часть методологии разработки по контракту. Этот подход полезен и в языках, которые не поддерживают его явно: преимущество использования операторов утверждений вместо утверждений в комментариях заключается в том, что программа может проверять утверждения при каждом запуске; если утверждение перестает быть истинным, сообщается об ошибке. Это предотвращает расхождение кода с утверждениями.

Утверждения в течение цикла разработки

В течение цикла разработки программист обычно запускает программу с включенными проверками (утверждениями). Когда проверка (утверждение) не проходит, программист немедленно уведомляется о проблеме. Многие реализации проверок (утверждений) также останавливают выполнение программы: это полезно, поскольку если программа продолжит работу после нарушения проверки (утверждения), она может повредить свое состояние и затруднить определение причины проблемы. Используя информацию, предоставляемую сообщением о неудачной проверке (утверждении) – например, местоположение ошибки и, возможно, трассировку стека, или даже полное состояние программы, если среда поддерживает дампы памяти или если программа выполняется в отладчике – программист обычно может исправить ошибку. Таким образом, проверки (утверждения) предоставляют очень мощный инструмент для отладки.

Утверждения в производственной среде

Когда программа развертывается в рабочей среде, проверки обычно отключаются, чтобы избежать каких-либо накладных расходов или побочных эффектов, которые они могут вызывать. В некоторых случаях проверки полностью отсутствуют в развернутом коде, например, проверки в C/C++, реализованные через макросы. В других случаях, таких как Java, проверки присутствуют в развернутом коде и могут быть включены непосредственно в рабочей среде для отладки. Проверки также могут использоваться для гарантии компилятору, что определенная пограничная ситуация недостижима, тем самым позволяя проводить определенные оптимизации, которые иначе были бы невозможны. В этом случае отключение проверок может фактически снизить производительность.

Недействительные утверждения

Большинство языков программирования позволяют включать или отключать проверки утверждений глобально, а иногда и независимо друг от друга. Проверки утверждений обычно включаются в процессе разработки и отключаются на финальном этапе тестирования и при выпуске продукта пользователям. Отключение проверки утверждений позволяет избежать затрат на их вычисление, при этом (если утверждения не имеют побочных эффектов) сохраняя тот же результат в нормальных условиях. В нештатных ситуациях отключение проверки утверждений может привести к продолжению работы программы, которая в противном случае была бы прервана. Иногда это может быть желательным поведением. Некоторые языки, такие как C, YASS и C++, позволяют полностью исключить проверки утверждений на этапе компиляции с помощью препроцессора. Аналогично, запуск интерпретатора Python с флагом "O" (обозначающим "оптимизация") приведет к тому, что генератор кода Python не будет генерировать байт-код для операторов `assert`. В Java для включения проверок утверждений требуется передать специальную опцию в среду выполнения. Если эта опция не указана, проверки утверждений игнорируются, но остаются в коде, если только не будут оптимизированы JIT-компилятором во время выполнения или явно исключены программистом путем заключения каждого утверждения в условный оператор `if (false)`. Программисты могут реализовывать собственные проверки в коде, которые всегда активны, обходя или изменяя стандартные механизмы проверки утверждений языка.

История

В докладах фон Неймана и Голдстайна 1947 года, посвященных разработке машины IAS, они описали алгоритмы, использующие раннюю версию блок-схем, в которых включали утверждения: "Вероятно, верно, что всякий раз, когда C фактически достигает определенной точки на блок-схеме, одна или несколько связанных переменных обязательно будут иметь определенные значения, обладать определенными свойствами или удовлетворять определенным взаимосвязям. Более того, в этой точке мы можем указать на обоснованность этих ограничений. Поэтому мы будем обозначать каждую область, в которой обоснованность таких ограничений утверждается, специальным блоком, который мы называем блоком утверждения". Алан Тьюринг поддерживал утвердительный метод доказательства корректности программ. В докладе "Проверка большой программы" в Кембридже 24 июня 1949 года Тьюринг предложил: "Как можно проверить большую программу, чтобы убедиться в ее правильности? Чтобы задача проверки не была слишком сложной, программист должен сделать ряд четких утверждений, которые можно проверить по отдельности, и из которых легко вытекает корректность всей программы".