3.8.2. Динамическая область видимости
Область видимости переменных в таких языках как APL, SNOBOL4 и ранние версии языка LISP является динамической. Динамический обзор данных опирается на последовательность вызова подпрограмм, а не на их пространственную взаимосвязь. Следовательно, область видимости можно определить только во время выполнения программы.
Рассмотрим повторно процедуру big из п. 3.8.1. Предположим, что правила динамического обзора данных применимы к нелокальным ссылкам. Значение идентификатора x, к которому обращается подпрограмма sub1, – динамическое, оно не может определяться во время компиляции. В зависимости от последовательности вызовов это значение может относиться к переменной из предыдущего объявления переменной х.
Для того чтобы определить корректное значение переменной x во время выполнения программы, можно начать его поиск среди локальных объявлений. Этим же способом начинается поиск и при статическом обзоре данных, правда, на этом их сходство заканчивается. При неудачном завершении поиска среди локальных объявлений рассматриваются объявления динамического родителя, или вызывающей процедуры. Если объявление переменной x не будет найдено и там, то поиск продолжается в динамическом родителе этой процедуры, и так далее, пока не будет найдено объявление переменной x. Если оно не будет найдено ни в одном из динамических предков, то это будет ошибкой периода выполнения программы.
Рассмотрим две различные последовательности вызовов процедуры sub1 в указанном примере. Предположим, что в первом случае процедура big обращается к процедуре sub2, которая вызывает процедуру subl. При этом поиск перейдет от локальной процедуры subl к вызывающей ее процедуре sub2, в которой находится объявление переменной x. Таким образом, в данном случае обращение к переменной x в процедуре subl будет обращением к переменной x процедуры sub2. Пусть теперь во втором случае процедура subl вызывается непосредственно из процедуры big. При этом динамическим родителем процедуры subl является процедура big, и обращение будет направлено к переменной x, объявленной в процедуре big.
Воздействие динамического обзора данных на программирование значительно. Корректные атрибуты нелокальных переменных, видимые операторам программы, невозможно определить статически. Оператор подпрограммы, содержащей ссылки на нелокальные переменные, во время различных вызовов этой подпрограммы может обращаться к различным нелокальным переменным. Некоторые проблемы программирования связаны непосредственно с динамическим обзором данных.
Во-первых, в период между вызовом подпрограммы и ее завершением в ней видны все локальные переменные вызывающей подпрограммы (и всех ее динамических предков), вне зависимости от их близости. От такой общедоступности локальных переменных нет защиты. Подпрограммы всегда выполняются в непосредственной среде вызывающей программы; следовательно, использование динамического обзора данных порождает менее надежные программы, чем использование статического обзора.
Второй проблемой, связанной с динамическим обзором данных, является невозможность статической проверки типов при обращении к нелокальным переменным. Это происходит из-за невозможности статически определить объявление переменной, на которую ссылаются как на нелокальную.
Использование динамического обзора данных также затрудняет чтение программ, поскольку для определения нелокальных переменных, на которые имеются ссылки, должна быть известна последовательность вызова подпрограмм. Если программу читает человек, то определить последнее практически невозможно.
Также отметим, что обращение к нелокальным переменным в языках с динамическим обзором данных происходит значительно медленнее, чем обращение в языках со статическим обзором.
С другой стороны, у динамического обзора данных есть и достоинства. В некоторых случаях параметры, передаваемые от одной подпрограммы к другой, являются простыми переменными, определяемыми в вызывающем модуле. В языках с динамическим обзором данных не требуется передачи ни одной из этих переменных, поскольку все они неявно видимы в вызываемой подпрограмме.
Причины более широкого распространения статического обзора данных состоят в том, что программы на языках со статическим обзором данных легче читать, они надежнее и выполняются быстрее, чем аналогичные программы на языках, использующих динамический обзор. Именно поэтому в большинстве современных диалектов языка LISP динамический обзор данных был заменен статическим.