((x /= Void) and then x.is_equal (y))

then

...

Излишне говорить, что не следует придерживаться этих соглашений. Нам быстро надоест писать подобные витиеватые фрагменты, а когда мы забудем это сделать, то результатом будет ошибка времени выполнения. Окончательный вариант соглашений, сформулированный в данной лекции, замечателен еще и тем, что дает ожидаемые результаты для x, равного void, - clone (x) вернет void, а equal (x, y) вернет true, если и y - void.

Вызов процедуры copy в форме x.copy (y) не создает подобных проблем, поскольку требует непустых x и y. Это следствие семантики процедуры copy, копирующей поля одного объекта в поля другого, и имеющей смысл, только если существуют оба объекта. Как показано далее, такое условие для y фиксируется формальным предусловием copy, заданным в явном виде в документации.

Отметим, что введенная выше функция is_equal существует в библиотеке системы. Причина в том, что часто удобнее определить специфические варианты эквивалентности элементов конкретного класса, перекрыв семантику по умолчанию. Для достижения этого эффекта достаточно переопределить функцию is_equal в соответствующем классе. Функция equal определяется в терминах is_equal (выражением, показанным выше при иллюстрации использования is_equal), и поэтому следует за всеми переопределениями is_equal.

Когда есть функция clone, то нет необходимости в twin. Это связано с тем, что функция clone определена как создание объекта с последующим вызовом copy. Поэтому для адаптации clone к специфике класса достаточно переопределить процедуру copy данного класса. (См. также лекция 16)

<p>Статус универсальных операций</p>

Последние комментарии частично прояснили вопрос о статусе универсальных операций clone, copy, equal, is_equal, deep_clone, deep_equal.

Эти операции не являются языковыми конструкциями, невзирая на их фундаментальную значимость для практики. Они поставляются классом ANY основной библиотеки Kernel. Этот класс имеет то специальное свойство, что каждый класс, созданный разработчиком, автоматически становится наследником (прямым или косвенным) класса ANY. Вот почему становится возможным переопределить вышеупомянутые компоненты для поддержки специального вида эквивалентности или копирования. (См. "Глобальная структура наследования", лекция 16)

Сейчас нет необходимости в деталях, поскольку мы еще вернемся к этой проблеме при изучении наследования. Но уже теперь полезно знать, что благодаря механизму наследования, мы можем полагаться на библиотечные классы, поддерживающие свойства, доступные всем классам, - и каждый класс может изменить их, приспосабливая к своим, специфическим целям.

<p>Ключевые концепции</p>

[x]. ОО-вычисления характеризуются высоко динамичной структурой времени выполнения, в которой объекты создаются только по запросу.

[x]. Некоторые объекты, используемые ПО, являются моделями внешних объектов (обычно косвенными). Другие объекты служат только для целей проектирования и реализации.

[x]. Объект состоит из ряда значений, называемых полями. Каждое поле соответствует атрибуту генератора объекта (класса, прямым экземпляром которого является объект).

[x]. Значение, в частности поле объекта, является объектом или ссылкой.

[x]. Ссылка может быть пустой (void) или присоединенной к объекту. Проверка условия x = Void позволяет определить текущее состояние ссылки. Корректное выполнение вызова x.f (...) возможно, если x не пустая ссылка.

[x]. Если объявление класса начинается с предложения class C ..., то сущность типа Cбудет обозначать ссылку, которая может быть присоединена к экземпляру C. Если начало объявления выглядит как expanded class D ..., то сущность типа D будет обозначать объект (экземпляр D) и никогда не может быть пустой ссылкой.

[x]. Базовые типы (BOOLEAN, CHARACTER, INTEGER, REAL, DOUBLE) определены как развернутые классы.

[x]. Развернутые объявления дают возможность определять составные объекты: объекты с подобъектами.

[x]. Объектные структуры могут содержать циклические цепочки ссылок.

[x]. Инструкция создания create x создает объект, инициализирует его поля значениями по умолчанию и присоединяет к нему x. Если в классе определены порождающие процедуры создания, то выполнение инструкции вида create x.creatproc (...) приведет, кроме того, к заданной специфической инициализации полей.

[x]. Для сущностей ссылочного типа присваивание (:=) и проверка эквивалентности (=) являются ссылочными операциями. Для сущностей развернутых типов используется семантика значений. Соответствующая семантика распространяется и на смешанные операнды.

Перейти на страницу:

Похожие книги