Выполнение r при любом из этих вызовов начинается с инициализации формальных аргументов значениями соответствующих фактических аргументов. Для простоты и согласованности правила, определяющие передачу аргументов, те же, что и правила присваивания. Другими словами, инициализация формального аргумента эквивалентна выполнению присваивания:
x := y
Это правило приводит к определению:
Определение: Присоединение
Присоединение y к x является результатом выполнения следующих двух операций:
Присваивания в форме x := y
Инициализации x при вызове подпрограммы, где x - формальный аргумент, а y - фактический аргумент вызова.
В обоих случаях x является целью присоединения, а y - источником.
Одни и те же правила действуют в обоих случаях для определения корректности присоединения (в зависимости от типов цели и источника). При условии корректности одни и те же правила определяют, каков будет эффект присоединения в период выполнения.
Присоединение: ссылочное и копии
При изучении ссылочного присваивания мы уже познакомились с эффектом присоединения. Если источник и цель являются ссылками, то эффект присваивания:
x := y
и соответствующей передачи аргументов состоит в том, что x получает значение ссылки y. Это иллюстрировалось несколькими примерами. Если значением y является void, то операция вместо присоединения сделает и x равным void; если y присоединен к объекту, то и x будет присоединен к этому же объекту.
Что происходит, когда типы x и y развернуты? Ссылочное присваивание не имеет смысла, а вот поверхностная форма копирования вполне возможна. Так и происходит. Рассмотрим объявления:
x, y: expanded SOME_CLASS
Присваивание x := y будет копировать каждое поле объекта, присоединенного к y, в соответствующие поля объекта, присоединенного к x, создавая тот же эффект, что и выполнение:
x.copy (y)
Копирование также является легальной операцией, эквивалентной в этом случае присваиванию. (В случае ссылок копирование и присваивание тоже легальны, но имеют разный эффект.)
Семантика копирования для развернутых типов дает ожидаемый эффект для всех базисных типов, которые, как отмечалось выше все относятся к развернутым типам. Например, если m и n типа INTEGER, то мы ожидаем от присваивания m := n, (или от соответствующей передачи аргументов) копирования значения n в m.
Проведенный анализ применим и к связанной с присваиванием операции эквивалентности. Рассмотрим булевы выражения: x = y и x /= y. Для x и y ссылочных типов, как уже отмечалось, истинность первого выражения (ложность второго) достигается только тогда, когда источник и цель оба имеют значение void или оба присоединены к одному и тому же объекту. Для развернутых x и y, такая семантика неприемлема, - здесь действует другая семантика, основанная на последовательном сравнении значений соответствующих полей, так что в этом случае выражение x = y имеет то же значение, что и equal (x, y).
| Разрешается, как мы увидим позже при обсуждении наследования, изменить семантику equal для придания специального смысла эквивалентности экземпляров некоторого класса. Это никак не отразится на операции эквивалентности =, которая по соображениям безопасности и простоты всегда имеет смысл оригинальной функции standard_equal. |
Правило присваивания и сравнения обобщается в следующем замечании.
Присоединение y к x означает копирование объекта x, если x и y принадлежат развернутым типам. Это ссылочное присоединение, если x и y ссылочного типа. Аналогично, тесты: x=y и x/=y означают сравнение объектов для x и y развернутых типов; это ссылочное сравнение, если x и y ссылочного типа.
Гибридное присоединение
В рассматриваемых до сих пор случаях источник и цель принадлежали одной категории - оба развернутого или ссылочного типа. Что если они из разных категорий?
Вначале рассмотрим ситуацию, когда в присваивании x := y цель x развернутого типа, а источник y - ссылочного типа. Единственно приемлемой в этом случае является семантика копирования: копирование полей объекта, присоединенного к y, в поля объекта, присоединенного к x. Все хорошо, если y не void в период выполнения. Если y - void, то результатом будет включение исключения. (Исключения изучаются в лекции 12)