| Для развернутого x тест x = Void не является причиной появления исключительной ситуации; он просто дает значение false. Но нет приемлемой семантики для присваивания x := Void, так что всякая подобная попытка приводит к появлению исключения. |
Рассмотрим теперь другой случай присваивания: x := y, где x ссылочного типа, а y - развернутого. Тогда в период выполнения y всегда присоединен к объекту, который мы можем назвать OY, и присоединение также должно присоединить x к объекту. Казалось бы, что можно присоединить x непосредственно к OY. Однако это привело бы к созданию ссылки на подобъект, а подобные ссылки запрещены нашими правилами. Поэтому правильной стратегией является клонирование источника OY и присоединение x к созданной копии. Рассмотрим пример:
class C feature
...
end
class COMPOSITE2 feature
x: C
y: expanded C
reattach is
do x := y end
end
При вызове компонента reattach в результате присваивания x будет присоединен к объекту, являющемуся клоном объекта y.
Следующая таблица обобщает семантику присоединения изученных случаев:
| Тип цели x | Тип источника y |
|---|
| Ссылочный | Развернутый |
|---|
| Ссылочный | Ссылочное присоединение | Клонирование: эффект x := clone(y) |
| Развернутый | Копирование: эффект x.copy(y) Ошибка, если y - void | Копирование: эффект x.copy(y) |
Таблица 8.1. Эффект присоединения x:=y
Проверка эквивалентности
Семантика операций, проверяющих эквивалентность (= и /=) должна быть совместимой с семантикой присваивания. Наряду с операцией = можно использовать и equal. Какую из этих операций следует применять, зависит от обстоятельств.
[x]. (E1) Если x и y - ссылки, их можно тестировать как на ссылочную эквивалентность, так и на объектную эквивалентность при условии, что ссылки не void. Мы определили операцию x = y, как обозначающую ссылочную эквивалентность в этом случае. Функция equal, введенная для проверки объектной эквивалентности, дополнена и применима, когда x или y - void.
[x]. (E2) Если x и y - развернутого типа, единственный смысл имеет объектное сравнение.
[x]. (E3) Если x - ссылка, y - развернутого типа, объектное сравнение - единственно возможный смысл операции и в данном случае. Сравнение расширяется, допуская случай, когда x - void, возвращая значение false в этой ситуации, поскольку y не может быть void.
Этот анализ дает желаемую интерпретацию равенства = во всех случаях. Для объектного сравнения всегда доступна функция equal, расширенная на случаи, когда один или оба операнда принимают значение void. Следующая таблица подводит итог семантике сравнения:
| Тип цели x | Тип источника y |
|---|
| Ссылочный | Развернутый |
|---|
| Ссылочный | Ссылочное сравнение | equal(x,y) объектное сравнение, если x не void, иначе - false |
| Развернутый | equal(x,y) объектное сравнение, если y не void, иначе - false | equal(x,y) объектное сравнение |
Таблица 8.2.Семантика сравнения x=y
Сравнение таблиц 8.1 и 8.2 показывает совместимость присваивания и операций сравнения в упоминавшемся уже смысле. Напомним, в частности, что equal (x, y) будет истинно после выполнения x := clone (y) или x. copy (y).
Обсуждаемые проблемы возникают во всех языках, включающих ссылки и указатели, таких как Pascal, Ada, Modula-2, C, Lisp и другие. Они особенно актуальны для ОО-языков, в которых все создаваемые пользователем типы являются ссылочными. В дополнение к причинам, объясняемых в разделе обсуждения, в синтаксисе явно не отражается факт представления объектов ссылками, так что следует быть особо внимательными при проверке эквивалентности объектов.
Работа со ссылками: преимущества и опасности
В предыдущих разделах отмечалось, что два свойства модели времени выполнения заслуживают дополнительного внимания. Во-первых, важная роль ссылок. Во-вторых, двойственность семантики базовых операций (присваивания, передачи параметров, проверки на равенство), имеющих различный смысл для ссылок и развернутых операндов.
Динамические псевдонимы
Для x и y ссылочного типа при непустом значении y присваивание x := y или соответствующее присоединение в результате вызова приведут к тому, что x и y будут присоединены к одному и тому же объекту.
Рис. 8.23. Разделение как результат присоединения