Правило языка
Правило Утверждений Переобъявления, так как оно сформулировано, является концептуальным руководством. Как преобразовать его в безопасное и проверяемое правило языка?
В принципе, чтобы убедиться в том, что старые предусловия влекут новые, а новые постусловия - старые, следует провести логический анализ тех и других утверждений. К сожалению, это требует наличия сложного механизма доказательства теорем (несмотря на десятилетия исследований в области искусственного интеллекта). Его применение в компиляторе пока не реально.
К счастью, возможно простое техническое решение. Нужное нам правило можно сформулировать через простое лингвистическое соглашение, основанное на том наблюдении, что для любых утверждений a и b :
[x]. влечет
or γ независимо от значения γ ;
[x]. β and
влечет β независимо от значения
.
Итак, гарантируется, что новое предусловие слабее исходного либо равно ему, если оно имеет вид
or γ . Гарантируется, что новое постусловие сильнее исходного β либо равно ему, если оно имеет вид β and
. Отсюда следует искомое языковое правило:
Правило (2) Утверждения Переобъявления
При повторном объявлении подпрограммы нельзя использовать предложения require или ensure . Вместо них следует использовать предложение, начинающееся с:
[x]. require else , объединенное с исходным предусловием логической связкой or
[x]. ensure then , объединенное с исходным постусловием логической связкой and .
При отсутствии таких предложений действуют исходные утверждения.
Заметим, что используются нестрогие булевы операторы and then и or else , а не обычные and и or , хотя чаще всего это различие несущественно.
Иногда получаемые утверждения могут оказаться сложнее, чем необходимо на самом деле. В примере с подпрограммой обращения матриц, где исходным было утверждение
invert (epsilon: REAL) is
-- Обращение текущей матрицы с точностью epsilon
require
epsilon >= 10 ^ (-6)
...
ensure
((Current * inverse) |-| One) <= epsilon
мы не вправе в повторном объявлении использовать require и ensure, поэтому результат
примет вид
...
require else
epsilon >= 10 ^ (-20)
...
ensure then
((Current * inverse) |-| One) <= (epsilon / 2)
а стало быть, предусловие формально станет таким: (epsilon >= 10 ^ (-20)) or else (epsilon >= 10 ^ (-6)) .
Ситуация с постусловием аналогична. Такое расширение не имеет особого значения, поскольку преобладает более слабое предусловие или более сильное постусловие. Если γ влечет , то
or else γ имеет то же значение, что и . Если β влечет , то β and then
имеет то же значение, что и β . Поэтому математически предусловие повторного объявления есть: epsilon >= 10 ^ (-20) , а его постусловие есть: ((Current * inverse) |-| One) <= (epsilon / 2) , хотя запись утверждений в программе (а также, вероятно, их расчет во время выполнения при отсутствии средств символьных преобразований) является более сложной.