Рассмотрим произвольный вызов. Понимание смысла, происходящего в процессе произвольного вызова, позволит полностью разобраться в механизме ОО-вычислений. Используем сформулированный ранее принцип вызова компонентов:
(F1) Любой элемент программы может выполняться только как часть вызова подпрограммы.
(F2) Каждый вызов имеет цель.
Любой вызов может принимать одну из следующих форм:
неквалифицированная: f (a, b, ...);
квалифицированная: x.g (u, v, ...) .
Аргументы в обоих случаях могут отсутствовать. Вызов размещен в теле подпрограммы r и может выполняться только как часть вызова r. Предположим, что известна цель этого вызова - некий объект OBJ. Тогда можно легко установить цель этого вызова - t. Возможны четыре варианта, первый из которых относится к неквалифицированному вызову, а остальные - к квалифицированному:
(T1) Для неквалифицированного вызова t это просто OBJ.
(T2) Если x это атрибут, то x - поле объекта OBJ- имеет значение, которое, в свою очередь, присоединено к некоторому объекту - он и есть t.
(T3) Если x - функция, то необходимо сначала осуществить ее вызов (неквалифицированный), результат которого и дает t.
(T4) Если x - локальная сущность r, то к моменту вызова предыдущие инструкции вычислят значение x, присоединенное к определенному объекту, который и является объектом t.
Проблема в том, что все четыре ответа опять относительны и могут помочь только в том случае, если известно, чем является текущий экземпляр OBJ. Очевидно, что OBJ это цель текущего вызова! Ситуация как в песенке о том, как у попа была собака (в оригинале: котенок съел козленка, котенка укусил щенок, щенка ударила палка ...) - бесконечная цепь.
Для приведения относительных ответов к абсолютным необходимо выяснить, что происходит тогда, когда все только начинается - в момент Большого Взрыва. Итак, определение:
Определение: выполнение системы
Выполнение ОО-программной системы состоит из следующих двух шагов:
Создание определенного объекта, называемого корневым объектом выполнения.
Применение определенной процедуры, называемой процедурой создания, к данному объекту.
В момент Большого Взрыва создается объект и начинается выполнение процедуры создания. Корневой объект является экземпляром корневого класса системы, а процедура создания - одной из процедур этого класса. Выполнение системы в целом сводится к успешному развертыванию отдельных частей (прямо или косвенно зажженных от начальной искры) в гигантский комплексный фейерверк.
Зная, где все началось, несложно проследить судьбу Current в процессе этой цепной реакции. Первым текущим объектом, созданным в момент Большого Взрыва, является корневой объект. Рассмотрим далее некоторый этап выполнения системы. Пусть r- последняя вызванная подпрограмма, а текущим на момент вызова r был объект OBJ. Тогда во время выполнения r объект Current определяется следующим образом:
(C1) Если в r выполняется инструкция, не являющаяся вызовом подпрограммы (например, присваивание), то текущим остается прежний объект.
(C2) Неквалифицированный вызов также оставляет тот же объект текущим.
(C3) Запуск квалифицированного вызова x.f ... делает текущим объект, присоединенный к x. Зная объект OBJ, можно идентифицировать x, используя сформулированные ранее правила T1-T4. После завершения вызова роль текущего возвращается к объекту OBJ.
В случаях C2 и C3 вызов может в свою очередь содержать последующие квалифицированные или неквалифицированные вызовы, и данные правила нужно применять рекурсивно.
Итак, нет ничего загадочного и запутанного в определении цели любого вызова, несмотря на всю относительность и рекурсивность правил. Что действительно является удивительным, так это мощь компьютеров, которую мы используем, выступая в роли учеников чародея. Мы создаем относительно небольшой текст заклинания - ПО, и затем выполняем его, в результате чего создаются объекты и выполняются вычисления, и число этих объектов и вычислений столь велико, что кажется почти бесконечным по меркам человеческого сознания.