Область видимости () в программировании — часть программы, в пределах которой идентификатор, объявленный как имя некоторой программной сущности (обычно — переменной, типа данных или функции), остаётся связанным с этой сущностью, то есть позволяет посредством себя обратиться к ней. Говорят, что идентификатор объекта «виден» в определённом месте программы, если в данном месте по нему можно обратиться к данному объекту. За пределами области видимости тот же самый идентификатор может быть связан с другой переменной или функцией, либо быть свободным (не связанным ни с какой из них). Область видимости может, но не обязана совпадать с областью существования объекта, с которым связано имя.

Связывание идентификатора () в терминологии некоторых языков программирования — процесс определения программного объекта, доступ к которому даёт идентификатор в конкретном месте программы и / или в конкретный момент её выполнения. Это понятие по сути синонимично области видимости, но может быть более удобно при рассмотрении некоторых аспектов выполнения программ.

Области видимости входят друг в друга и составляют иерархию, от локальной области видимости, ограниченную функцией (или даже её частью), до глобальной, идентификаторы которой доступны во всей программе. Также в зависимости от правил конкретного языка программирования области видимости могут быть реализованы двумя способами: лексически (статически) или динамически.

Область видимости также может иметь смысл для языков разметки: например, в HTML областью видимости имени элемента управления является форма (HTML) от до Спецификация языка HTML , переводчик: А. Пирамидин, intuit.ru, ISBN 978-5-94774-648-8, 17. Лекция: Формы..

Типы области видимости В монолитной (одномодульной) программе без вложенных функций и без использования ООП может существовать только два типа области видимости: глобальная и локальная. Прочие типы существуют только при наличии в языке определённых синтаксических механизмов. Глобальная область видимости — идентификатор доступен во всём тексте программы (во многих языках действует ограничение — только в тексте, находящемся после объявления этого идентификатора). Локальная область видимости — идентификатор доступен только внутри определённой функции (процедуры). Видимость в пределах модуля может существовать в модульных программах, состоящих из нескольких отдельных фрагментов кода, обычно находящихся в разных файлах. Идентификатор, чьей областью видимости является модуль, доступен из любого кода в пределах данного модуля. Пакет или пространство имён. В глобальной области видимости искусственно выделяется поименованная подобласть. Имя «привязывается» к этой части программы и существует только внутри неё. Вне данной области имя либо вообще недоступно, либо доступно ограниченно.

В ООП-языках дополнительно к вышеперечисленным могут поддерживаться специальные ограничения области видимости, действующие только для членов классов (идентификаторов, объявленных внутри класса или относящихся к нему): Приватная (личная, закрытая) () область видимости означает, что имя доступно только внутри методов своего класса. Защищённая () область видимости означает, что имя доступно только внутри своего класса и его классов-потомков. Общая () область видимости означает, что имя доступно в пределах области видимости, к которой относится его класс.

Способы задания области видимости В простейших случаях область видимости определяется местом объявления идентификатора. В случаях, когда место объявления не может однозначно задать область видимости, применяются специальные уточнения.

Идентификатор, объявленный вне любого определения функции, процедуры, типа, является глобальным. Идентификатор, объявленный внутри определения функции, является локальным в данной функции, то есть его областью видимости является эта функция. Идентификатор, являющийся частью определения типа данных, в отсутствие дополнительных уточнений имеет ту же область видимости, что и идентификатор типа, в определение которого он входит. В языках, поддерживающих модули, пакеты или пространства имён идентификатор, объявленный вне всех процедур и классов, по умолчанию относится к модулю, пакету или пространству имён, внутри которого находится его объявление. Сами пределы области видимости для пакета или пространства имён указываются с помощью специальных описаний, а модульная область видимости ограничивается обычно текущим файлом исходного текста программы. Особенностью этого типа видимости является то, что язык, как правило, содержит средства, позволяющие сделать идентификатор доступным и вне своего модуля (пакета или пространства имён), то есть «расширить» его область видимости. Для этого должно иметься сочетание двух факторов: содержащий идентификатор модуль должен быть импортирован с помощью специальной команды там, где предполагается его использование, а сам идентификатор при его описании должен быть дополнительно объявлен экспортируемым. Способы объявления идентификатора экспортируемым могут быть различны. Это могут быть специальные команды или модификаторы в описаниях, соглашения об именовании (например, в языке Go экспортируемыми являются идентификаторы пакетной области видимости, начинающиеся на заглавную букву). В ряде языков каждый модуль (пакет) искусственно делится на две части: раздел определений и раздел реализации, которые могут находиться как в пределах одного файла исходного кода (например, в Delphi), так и в разных (например, в языке Модула-2); экспортируемыми являются идентификаторы, объявленные в модуле определений. Область видимости идентификатора, объявленного внутри ООП-класса, по умолчанию является либо приватной, либо общей. Иная область видимости придаётся с помощью специального описания (например, в C++ это модификаторы private, public, protected).

Приведённый перечень не исчерпывает всех нюансов определения области видимости, которые могут иметься в конкретном языке программирования. Так, например, возможны различные толкования сочетаний модульной области видимости и объявленной видимости членов ООП-класса. В одних языках (например, C++) объявление личной или защищённой области видимости для члена класса ограничивает доступ к нему из любого кода, не относящегося к методам своего класса. В других (Object Pascal) все члены класса, в том числе личные и защищённые, полностью доступны в пределах того модуля, в котором объявлен класс, а ограничения области видимости действуют только в других модулях, импортирующих данный.

Иерархия и разрешение неоднозначностей Области видимости в программе естественным образом составляют многоуровневую структуру, в которой одни области входят в состав других. Иерархия областей обычно строится на всех или некоторых уровнях из набора: «глобальная — пакетные — модульные — классов — локальные» (конкретный порядок может несколько отличаться в разных языках).

Пакеты и пространства имён могут иметь несколько уровней вложенности, соответственно, вложенными будут и их области видимости. Отношения областей видимости модулей и классов могут сильно отличаться в разных языках. Локальные пространства имён также могут быть вложенными, причём даже в тех случаях, когда язык не поддерживает вложенные функции и процедуры. Так, например, в языке C++ вложенных функций нет, но каждый составной оператор (содержащий набор команд, заключённый в фигурные скобки) образует собственную локальную область видимости, в которой возможно объявление своих переменных.

Иерархическая структура позволяет разрешать неоднозначности, которые возникают, когда один и тот же идентификатор используется в программе более чем в одном значении. Поиск нужного объекта всегда начинается с той области видимости, в которой располагается обращающийся к идентификатору код. Если в данной области видимости находится объект с нужным идентификатором, то именно он и используется. Если такового нет, транслятор продолжает поиск среди идентификаторов, видимых в объемлющей области видимости, если его нет и там — в следующей по уровню иерархии.

program Example1; var a,b,c: Integer; (* Глобальные переменные. *)

procedure f1; var b,c: Integer (* Локальные переменные процедуры f1. *) begin a := 10; (* Изменяет глобальную a. *) b := 20; (* Изменяет локальную b. *) c := 30; (* Изменяет локальную с. *) writeln(' 4: ', a, ',', b, ',', c); end;

procedure f2; var b,c: Integer (* Локальные переменные процедуры f2. *) procedure f21; var c: Integer (* Локальная переменная процедуры f21. *) begin a := 1000; (* Изменяет глобальную a. *) b := 2000; (* Изменяет локальную b процедуры f2. *) c := 3000; (* Изменяет локальную c процедуры f21.*) writeln(' 5: ', a, ',', b, ',', c); end; begin a := 100; (* Изменяет глобальную a. *) b := 200; (* Изменяет локальную b. *) c := 300; (* Изменяет локальную c. *) writeln(' 6: ', a, ',', b, ',', c); f21; writeln(' 7: ', a, ',', b, ',', c); end; begin (* Инициализация глобальных переменных. *) a := 1; b := 2; c := 3; writeln(' 1: ', a, ',', b, ',', c); f1; writeln(' 2: ', a, ',', b, ',', c); f2; writeln(' 3: ', a, ',', b, ',', c); end.

Так, при запуске приведённой выше программы на языке Паскаль будет получен следующий вывод:

1: 1,2,3 4: 10,20,30 2: 10,2,3 6: 100,200,300 5: 1000,2000,3000 7: 1000,2000,300 3: 1000,2,3

В функции f1 переменные b и c находятся в локальной области видимости, поэтому их изменения не затрагивают одноимённые глобальные переменные. Функция f21 содержит в своей локальной области видимости только переменную c, поэтому она изменяет и глобальную a, и b, локальную в объемлющей функции f2.

Лексические vs. динамические области видимости Использование локальных переменных — имеющих ограниченную область видимости и существующих лишь внутри текущей функции — помогает избежать конфликта имён между двумя переменными с одинаковыми именами. Однако существует два очень разных подхода к вопросу о том, что значит «быть внутри» функции и, соответственно, два варианта реализации локальной области видимости:

лексическая область видимости, или лексический контекст (), или лексическое (статическое) связывание (): локальная область видимости функции ограничена текстом определения этой функции (имя переменной имеет значение внутри тела функции и считается неопределённым за его пределами). динамическая область видимости, или динамический контекст (), или динамическое связывание (): локальная область видимости ограничена временем исполнения функции (имя доступно, пока функция выполняется, и исчезает, когда функция возвращает управление вызвавшему её коду).

Для «чистых» функций, которые оперируют только своими параметрами и локальными переменными, лексическая и динамическая области видимости всегда совпадают. Проблемы возникают, когда функция использует внешние имена, например, глобальные переменные или локальные переменные функций, в которые она входит или из которых вызывается. Так, если функция f вызывает не вложенную в неё функцию g, то при лексическом подходе функция g не имеет доступа к локальным переменным функции f. При динамическом же подходе функция g будет иметь доступ к локальным переменным функции f, поскольку g была вызвана во время работы f.

Например, рассмотрим следующую программу: x=1 function g () { echo $x ; x=2 ; } function f () { local x=3 ; g ; } f # выведет 1 или 3? echo $x # выведет 1 или 2?