- •4.9.1. Изменяемость
- •4.9.2. Классы операций
- •98 Глава 4
- •4.9.3. Полнота
- •100 Глава 4
- •4.9.5. Операции egual, similar и copy
- •102 Глава 4
- •104 Глава 4
- •5. Исключительные ситуации
- •108 Глава 5
- •110 Глава 5
- •6.2.1. Сигнализация об исключительных ситуациях
- •5.2.2. Обработка исключительных ситуаций
- •112 Глава 5
- •5.2.3. Предложение resignal
- •6.2.4. Необрабатываемые исключительные ситуации
- •114 Глава 5
- •6.2.3. Предложение resignal
- •5.2.4. Необрабатываемые исключительные ситуации
- •116 Глава 5
- •118 Глава 5
- •118 Глава 5
- •120 Глава 5
- •122 Глава 5
- •124 Глава 5
- •128 Глава 6
- •130 Глава 6
- •6.2.1. Реализация итераторов
- •6.2.2. Использование итераторов
- •132 Глава 6
- •134 Глава 6
- •136 Глава 6
- •138 Глава 6
- •140 Глава 7
- •142 Глава 7
- •7.2. Абстракция данных
- •144 Глава 7
- •146 Глава 7
- •148 Глава 7
- •150 Глава 7
- •7.4. Генераторы
- •162 Глава 7
- •154 Глава 7
- •156 Глава 7
- •162 Глава 8
- •164 Глава 8
- •166 Глава 8
- •168 Глава 8
- •170 Глава 9
- •172 Глава 9
- •174 Глава 9
- •176 Глава 9
- •9.1.3. Пример
- •178 Глава 9
- •180 Глава 9
- •182 Глава 9
- •184 Глава 9
- •186 Глава 9
- •188 Глава 9
- •190 Глава 9
- •192 Глава. 9
- •194 Глава 9
164 Глава 8
было ли понятие «подмножество» выбрано достаточно продуманно или автор имел в виду соответствующее подмножество? Вторая спецификация, которую прочесть чуть сложнее, не оставляет никаких сомнений по этому вопросу. Возникает другой вопрос; почему составитель спецификации, полагая процедуру р проверкой на наличие подмножества, не указал это явно? Третья спецификация отвечает на оба этих вопроса.
Констатация одного и того же факта двумя различными способами дает возможность читателям лучше понять спецификацию. Это позволяет избежать неверного понимания и сокращает общее время изучения спецификации. С этой точки зрения удачным примером может служить спецификация процедуры indexes, приведенная на рис. 8.2.
Спецификация, описывающая одну и ту же вещь несколькими способами, облегчает понимание ее различными читателями. Очень часто критическая спецификация представляет собой концепцию с названием, мало знакомым большинству читателей. Рассмотрим, например,
pv = proc (inc, r: real, n: int) returns (value: real)
requires inc > 0 & r •> 0 & n :> 0.
effects Возвращает имеющееся значение годового дохода для inc за период n лет в проценте прироста без риска величиной г.
То есть value == inc+ (inc/(l +г)+...+ (inc/(l + г)"~'). Например, pv (100, .10,3) = 100+ 100/1.1 + 100/1.21
Для читателей, недостаточно хорошо знакомых с финансовыми вопросами, нелегко будет понять фразу «имеющееся значение». И с этой точки зрения вторая строка, «т. е.», представляет для них безусловный интерес. Вторая часть, «например», может быть использована читателями для подтверждения правильности своего понимания.
Если читатели извлекают пользу из подобной избыточности, то важно сделать так, чтобы вся подобная информация была каким-либо образом помечена с этой точки зрения. Хорошим способом является использование вводных слов и оборотов типа «например» или «т. е.».
Избыточность не сокращает число ошибок в спецификации. Она делает их более очевидными и дает возможность читателю их обнаружить. Рассмотрим, например,
too.cold = proc (temp: int) returns (b: bool)
effects b = true, если temp < 0 градусов по Фаренгейту; в противном случае b = false.
too.cold = proc (temp; int) returns (b: bool)
effects b = true, если temp < 0 градусов по Фаренгейту; в противном случае b = false. То есть b == true в точности в том случае, когда temp не больше, чем точка замерзания воды при нормальной температуре и давлении.
Спецификации
Первая спецификация не вызывает у читателя никаких подозрений, однако вторая явится для большинства предупредительным сигналом.
Одна из базовых проблем, относящихся к спецификации, заключается в том, что в процессе изучения читатель вносит в этот процесс свое представление о предмете, порождающее неоднозначность. Для исключения подобной неоднозначности может потребоваться введение весьма значительной избыточности. Рассмотрим, например,
billion = proc ( ) returns (b: int)
effects Возвращает целое число значением в один биллион. billion = proc ( ) returns (b: int) effects Возвращает целое число значением в один биллион, т. е. 10°.
Как американские, так и английские читатели найдут первую спецификацию абсолютно безошибочной. К сожалению, они интерпретируют ее совершенно по-разному, поскольку в Соединенных Штатах биллион есть 10", а в Великобритании биллион есть 10".
8.3. Почему именно спецификации?
Спецификации важны для достижения требуемой модульности программы. Абстракция используется для декомпозиции программы на модули. Однако взятая в отдельности абстракция является малопонятной. Без какого-либо описания мы не можем ни сказать, что она из себя представляет, ни отличить ее от одной из своих реализаций. В качестве такого описания и выступает спецификация.
Спецификация описывает соглашение между разработчиками и пользователями. Разработчик соглашается написать модуль, который относится к заданному набору спецификаторов. Пользователь соглашается не полагаться на знания о том, какой именно член набора используется, т. е. не предполагать ничего такого, что не было бы указано в спецификации. Такое соглашение позволяет разделить анализ реализации от собственно использования программы. Спецификации дают возможность создавать логические основы, позволяющие успешно «разделять и властвовать».
Спецификации, очевидно, полезны и для документации программы. Сам факт написания спецификации полезен также и потому, что он проливает свет на используемую абстракцию. Опыт показывает, что эта деятельность приносит столько же пользы, сколько приносит использование самого результата. Написание спецификации всегда позволяет нам узнать что-либо полезное об описываемом наборе спецификаторов. Это также всегда облегчает процесс выявления неоднозначностей, неполноты и недоопределенности. В некоторых случаях улучшение понима-
