В результате x и y становятся тесно связанными до тех пор, пока x или y не будет присвоено новое значение. В частности любая операция вида x.f, где f некоторый компонент соответствующего класса, приведет к тому же результату, что и y.f, поскольку воздействует на тот же объект.

Присоединение x к тому же объекту, что и y, известно как назначение динамического псевдонима (dynamic aliasing). Псевдоним является динамическим, поскольку существует только во время выполнения.

Статические псевдонимы закрепляют два имени за одним и тем же программным элементом в исходном тексте, и они всегда обозначают одно и то же значение вне зависимости от событий, происходящих во время выполнения. Этот прием включен в некоторые языки программирования. В Fortran директива EQUIVALENCE означает, что две переменные разделяют содержимое одной и той же области памяти. Директива препроцессора C #define x y определяет, что любое упоминание x в тексте программы эквивалентно y.

Наличие динамических псевдонимов оказывает более серьезное влияние на операции присваивания с участием сущностей ссылочного типа, нежели с участием сущностей развернутого типа. В случае x и y развернутого типа INTEGER присваивание x := y просто устанавливает для x значение y и никакого связывания x и y не происходит. После подобного присваивания с участием ссылочных типов x и y становятся псевдонимами одного объекта.

<p>Семантика использования псевдонимов</p>

Неприятным последствием применения псевдонимов (и статических, и динамических) является воздействие операций на сущности, даже не упоминаемые в операциях.

Модель вычислений без псевдонимов обладает приятным свойством: приведенный ниже фрагмент всегда справедлив

[БЕЗ СЮРПРИЗОВ]

-- Предположим, что свойство P(y) выполняется

x := y

C (x)

-- P(y) останется выполнимым.

Этот пример подразумевает, что P (y) это частное свойство y, а C (x) некая операция с участием x, но не y. В этом случае никакие действия над x не влияют на значение y.

Для сущностей развернутых типов это действительно так. Приведем типичный пример с x и y типа INTEGER:

-- Предположим, что здесь y = 0

x := y

x := -1

-- По-прежнему y "= 0.

В этом случае нет никакого способа изменить y путем присваивания значения x. Обратимся теперь к аналогичной ситуации с участием динамических псевдонимов. Пусть x и y экземпляры следующего класса C:

class C feature

boolattr: BOOLEAN

-- Булев атрибут для описания некоторого свойства объекта.

set_true is

-- Установка boolattr в true.

do

boolattr := True

end

... Другие компоненты ...

end

Теперь предположим, что тип y это C, и что y в определенный момент времени выполнения не является пустой ссылкой. Тогда следующий пример уже не обладает свойством "БЕЗ СЮРПРИЗОВ":

[СЮРПРИЗ, СЮРПРИЗ!]

-- Предполагаем, что y.boolattr равно false.

x := y

-- Значение y.boolattr по-прежнему false.

x.set_true

-- Но теперь y.boolattr равно true!

Последняя инструкция данного фрагмента никоим образом не содержит y, однако одним из ее результатов является изменение свойств y.

<p>Выработка соглашений для динамических псевдонимов</p>

Отмеченные тревожные последствия операций присваивания с участием ссылок порождают законный вопрос о целесообразности сохранения динамических псевдонимов в нашей модели вычислений.

Ответ - частично теоретический и частично практический:

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

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

Поочередно рассмотрим оба указанных аспекта.

<p>Псевдонимы в ПО и за его пределами</p>
Перейти на страницу:

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