Ответ на третий вопрос - что может программа делать с фактическими аргументами? - вытекает из того, что присоединение используется для задания семантики связывания формальных и фактических аргументов. Присоединение (см. лекцию 8) означает копирование либо ссылки, либо объекта. Это зависит от того, являются ли соответствующие типы развернутыми:
[x]. Для ссылок (обычный случай) при передаче аргументов копируется ссылка, - Void, либо присоединенная к объекту.
[x]. Для развернутых типов (включающих основные типы INTEGER, REAL и т.п.), при передаче аргументов копируется объект.
В первом случае, запрет операций прямой модификации означает, что нельзя модифицировать ссылку (reference) через повторное присоединение или создание. Но если ссылка не пустая, то разрешается модифицировать присоединенный объект.
Рис. 13.1. Допустимые операции на аргументе ссылки
Если xi - один из формальных аргументов r, то тело программы может содержать вызов:
xi.p (...)
где p - процедура, применимая к xi, (объявлена в базовом классе типа Ti аргумента xi). Процедура может модифицировать поля объекта, присоединенного к xi во время выполнения, то есть объекта, присоединенного к соответствующему фактическому аргументу ai.
Вызов q (a) никогда не может изменить значение a, если a развернутого типа и является объектом. Если же a является ссылкой, то ссылка не меняется, но объект, присоединенный к ней, может измениться в результате вызова.
Существует много причин, по которым не следует позволять программам прямую модификацию их аргументов. Одна из самых убедительных - Конфликтующие присваивания. Предположим, что язык допускает присваивания аргументам, и процедура13.1)
dont_I_look_innocuous (a, b: INTEGER) is -- я выгляжу
-- безвредной, но не стоит мне доверять.
do
a := 0; b := 1
end
Теперь рассмотрим вызов dont_I_look_innocuous (x, x). Каково значение x после возвращения: 0 или 1? Ответ зависит от того, как компилятор реализует изменения формальных - фактических аргументов при выходе программы. Это ставит в тупик не только программистов, использующих язык Fortran.
Разрешение программе изменять аргументы приводит к ограничениям на фактические аргументы. В этом случае он должен быть элементом, способным изменять свое значение, что допустимо для переменных, но не постоянных атрибутов (см. лекцию 18). Недопустимым фактическим аргументом становится сущность Current, выражения, такие как a + b. Устранение модификации аргументов позволяет избежать подобных ограничений и использовать любые выражения в качестве фактических аргументов.
Следствием этих правил является признание того, что только три способа допускают модификацию значения ссылки x: процедура создания create x...; присваивание x := y; и попытка присваивания x ?= y, обсуждаемая ниже. Передача x как фактического аргумента никогда не модифицирует x.
Это также означает, что процедура не возвращает ни одного результата, функция - официальный результат, представленный сущностью Result. Для получения нескольких результатов необходимо одно из двух:
[x]. Использовать функцию, возвращающую объект с несколькими полями (обычно, возвращается ссылка на такой объект).
[x]. Использовать процедуру, изменяющую поля объектов соответствующих атрибутов. Затем клиент может выполнять запросы к этим полям.
Первый прием уместен, когда речь идет о составном результате. Например, функция не может возвращать два значения, соответствующих заглавию и году публикации книги, но может возвращать одно значение типа BOOK, с атрибутами title и publication_year. В более общих ситуациях применяются процедуры. Эта техника будет обсуждаться вместе с вопросом побочных эффектов в разделе принципов модульного проектирования13.2).
Инструкции
ОО-нотация, разработанная в этой книге, императивна: вычисления специфицируются через команды (commands), также называемые инструкциями (instructions). (Мы избегаем обычно применимого термина оператор (предложение) (statement), поскольку в слове есть оттенок выражения, описывающего факты, а хотелось подчеркнуть императивный характер команды.)
Для имеющих опыт работы с современными языками инструкции выглядят как хорошие знакомые. Исключение составляют некоторые специальные свойства циклов, облегчающие их верификацию. Вот список инструкций: Вызов процедуры, Присваивание, Условие, Множественный выбор, Цикл, Проверка, Отладка, Повторное выполнение, Попытка присваивания.
Вызов процедуры
При вызове указывается имя подпрограммы, возможно, с фактическими аргументами. В инструкции вызова подпрограмма должна быть процедурой. Вызов функции является выражением. Хотя сейчас нас интересуют инструкции, следующие правила применимы в обоих случаях.
Вызов может быть квалифицированным или неквалифицированным. Для неквалифицированного вызова подпрограммы из включающего класса в качестве цели используется текущий экземпляр класса. Этот вызов имеет вид:
r (без аргументов), или
r (x, y, ...) (с аргументами)
Квалифицированный вызов явно называет свою цель, заданную некоторым выражением. Если a - выражение некоторого типа, C - базовый класс этого типа, а - q одна из программ C, то квалифицированный вызов имеет форму a.q. Опять же, за q может следовать список фактических аргументов; a может быть неквалифицированным вызовом функции с аргументами, как в p (m).q (n), где p(m) - это цель. В качестве цели можно также использовать более сложное выражение при условии заключения его в скобки, как в (vector1 + vector2).count.
Также разрешаются квалифицированные вызовы с многоточием в форме: a.q1q2 ...qn, где a, так же, как и qi , может включать список фактических аргументов.
Экспорт управляет применением квалифицированных вызовов. Напомним, что компонент f, объявленный в классе B, доступен в классе A (экспортирован классу), если предложение feature, объявляющее f, начинается с feature (без дальнейшего уточнения) или feature {X, Y,... }, где один из элементов списка {X, Y,...} является A или предком A. Имеет место:
процедурапроцедура 13.1
Эта техника будет обсуждаться вместе с вопросом побочных эффектов в разделе принципов модульного проектированияЭта техника будет обсуждаться вместе с вопросом побочных эффектов в разделе принципов модульного проектирования 13.2