Наши расширения будут включать инструкцию проверки check, а также конструкции, задающие корректность цикла (инварианты и варианты цикла), рассматриваемые в следующем разделе.
Инструкция check выражает уверенность автора программы, что некоторое свойство всегда выполняется, когда вычисление достигает точки, в которой находится наша инструкция. Синтаксически, инструкция записывается в следующей форме:
check
assertion_clause1
assertion_clause2
...
assertion_clausen
end
Включив эту инструкцию в программный текст, мы говорим, что всякий раз, когда управление достигает этой инструкции, заданное утверждение (предложения утверждения между check и end) должно выполняться.
Это некоторый способ убеждать самого себя, что некоторые свойства выполняются. Более важно, что это позволяет будущим читателям вашего программного текста понять, на каких гипотезах вы основываетесь. Создание ПО требует многочисленных предположений о свойствах объектов системы. Тривиальный, но типичный пример - вызов
if x >= 0 then y := sqrt (x) end
Но проверка может быть чуть менее очевидной, если, например:
x := a^2 + b^2
Инструкция check дает возможность выразить наше предположение о свойствах объектов:
x := a^2 + b^2
... Другие инструкции ...
check
x >= 0
-- Поскольку x был вычислен как сумма квадратов.
end
y := sqrt (x)
Здесь нет конструкции if... then..., защищающей вызов
Этот пример типичен для демонстрации того, что наиболее вероятное применение инструкции проверки состоит в добавлении ее, как раз перед вызовом программы, имеющей предусловие. В качестве еще одного примера рассмотрим вызов
s.remove
в точке, где вы точно знаете, что стек
check not s.empty end
Вариант такой ситуации встречается, когда пишется вызов в форме
if full then
error := Overflow
else
check representation /= Void end
representation.put (x); error := 0
end
Здесь читатель может думать, что вызов в
check
representation_exists: representation /= Void
-- Поскольку предложение representation_exists истинно, когда
-- full ложно, что следует из инварианта реализации.
end
