- •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
100 Глава 4
для s (по предположению), а операция remel только удаляет элементы из s.
Этот способ анализа называется индукцией типа данных. Индукция осуществляется по количеству вызовов процедур, используемых для получения текущего значения объекта. Первый шаг индукции — это установить сохранение свойства для примитивных конструкторов. Индукционный шаг устанавливает сохранность свойства для конструкторов и модификаторов.
Отметим, что анализ осуществляется на абстрактном уровне, а не на уровне реализации. Нас не интересует, как реализованы упорядоченные списки. Вместо этого мы работаем прямо с их спецификацией. Работа на абстрактном уровне существенно упрощает анализ.
Индукция также используется для того, чтобы показать, что реализации операций сохраняют инвариант представления (см. разд. 4.5.3). Однако этот анализ производится на уровне реализации. Как и в нашем случае, первый шаг — это установить сохранение свойства для примитивных конструкторов. Если представление изменяемое, на индукционном шаге необходимо рассматривать все операции, так как любая из них может изменить представление. Если же представление неизменяемое, то на индукционном шаге необходимо рассмотреть только конструкторы.
4.9.5. Операции egual, similar и copy
Может показаться, что абстракции данных должны предоставлять операции copy и equal автоматически, т. е. что каждый тип автоматически должен быть обеспечен этими операциями и что их реализации должны быть сгенерированы компилятором. Однако автоматически такие реализации сгенерированы быть не могут, так как они зависят от интерпретации представления, т. е. от функции абстракции.
Проверка на равенство не может быть реализована автоматически потому, что два абстрактных объекта могут быть равны, даже если их представления различны. Возьмем в качестве примера рассмотренную нами ранее реализацию рациональных чисел, в которой представления задаются не в сокращенной форме. Очевидно, что рациональное число, представленное записью
{num: I, denom: 21
равно рациональному числу, представленному записью {пит: 13, denom: 26}.
Копирование не может быть реализовано автоматически потому, что не всегда ясно, из чего состоит объект. Например,
Абстракции данных
при копировании упорядоченного списка нужно ли нам копировать только верхний узел, чтобы копия разделяла правое и левое поддеревья с оригиналом, или мы должны копировать также и правое и левое поддеревья? Правильный ответ зависит от значения типа.
Несмотря на то что реализация таких операций, как equal, осуществляется программистом, чтобы гарантировать одинаковые значения операций с такими именами, мы рекомендуем придерживаться принятых соглашений. Мы приняли соглашение, согласно которому имя equal резервируется для условия равенства, т. е. когда невозможно различить два равных объекта. Следовательно, два изменяемых объекта равны тогда и только тогда, когда они являются одним и тем же объектом; в противном случае мы могли бы различить их, применив к одному из них модифицирующую операцию. Например, рассмотрим две ситуации, показанные на рис. 4.18. Здесь х = у, но х ~ = г.
Мы используем имя similar для операции, которая имеет дело со взаимосвязью ос и Р, а именно с фактом совпадения значений двух объектов. Мы требуем, чтобы результат операции copy совпадал по значению со своим аргументом, но не разделял с этим аргументом никаких компонентов. Так, объект z мог быть получен при вызове copy (х).
В отношении имен equal, copy и similar встроенные в язык CLU типы отвечают этим соглашениям. Должны отвечать им и определяемые пользователями типы. Таким образом, если тип данных intset предоставляет эти операции, их спецификации должны быть такими, как показано на рис. 4.19, а их реализации— как на рис. 4.20. Отметим, что операция similar сравнивает значения двух своих аргументов и проверяет, содержат ли они одни и те же элементы. Операции equal и copy могут быть реализованы в терминах операций equal и copy для массивов.
Рис, 4,18. Две концепции равенства.
