Статические и динамические области видимости
Перевод статьи Static and Dynamic Scopingopen in new window.
Область видимости переменной x
это область программы в которой использование имени x
ссылается на объявление этой переменной. Одна из причин использование областей видимости — сохранить переменные в разных частях программы отличными друг от друга. Количество коротких имён для переменных ограничено и программисты используют общепринятые имена (например i
для индекса массива). В любой программе среднего размера одинаковые названия переменных используются в разных частях программы.
Области видимости делятся на два вида: статические и динамические.
Статические области видимости
Статические области видимости (Static scoping) так же называются лексическими областями видимости (Lexical scoping). В этих областях видимости имена переменных всегда ссылаются на окружение более верхнего уровня. Это свойство текста программы и не связано со стеком вызовов во время выполнения. Статические области видимости упрощают написание модульного кода, так как программист вычисляет область видимости просто смотря на код. В отличии от этого, динамические области видимости требуют от разработчика учитывать все возможные варианты динамического контекста.
В большинстве языков программирования, включая C, C++ и Java, используются статические области видимости: привязка переменных может быть определена по тексту программы и не зависит от стека вызовов функций во время выполнения.
Для примера рассмотрим программу написанную ниже. Программа выводит 10, так как значение возвращаемое f()
не зависит от того откуда вызвана функция (g()
вызывает её и имеет свою переменную x
со значением 20). f()
всегда возвращает значение глобальной переменной x
.
// программа на C демонстрирующая статические области видимости
#include<stdio.h>
int x = 10;
// Вызывается из g()
int f()
{
return x;
}
// g() содержит переменную с именем x и вызывает f()
int g()
{
int x = 20;
return f();
}
int main()
{
printf("%d", g()); // 10
printf("\n");
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
В примере компилятор сначала ищет переменную в текущем блоке, затем в глобальных переменных.
Динамические области видимости
Динамическими области видимости необычны для современных языков программирования: каждый идентификатор имеет глобальный стек привязок и при поиске значения используется самая последняя привязка. Другими словами, сначала компилятор ищет имя в текущем блоке, а затем последовательно во всех вызвавших текущий блок функциях.
// Так как динамические области видимости необычны
// мы рассмотрим следующий псевдокод. Он выведет 20
// на языке с динамическими областями видимости
int x = 10;
// Called by g()
int f()
{
return x;
}
// g() содержит переменную с именем x и вызывает f()
int g()
{
int x = 20;
return f();
}
main()
{
printf(g()); // 20
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Статические vs динамические
В большинстве языков программирования используются статические области видимости: код легче понимать, достаточно посмотреть на текст программы чтобы понять область видимости переменной.
При использовании динамических областей видимости недостаточно знать где написан код, нужно знать как он запускается. Каждый раз при запуске функции создаётся новая область видимости.
Perl поддерживает как статические так и динамические области видимости. Ключевое слово my
определяет статическую область видимости локальной переменной, а ключевое слово local
динамическую область видимости локальной переменной.
# Код на Perl демонстрирующий динамическую область видимости
$x = 10;
sub f
{
return $x;
}
sub g
{
# Так как используется local, переменная x в динамической области видимости
local $x = 20;
return f();
}
print g()."\n"; # 20
2
3
4
5
6
7
8
9
10
11
12
13
14