# namespace

Команда предназначена для создания и управления областями имен для команд и переменных.

## СИНТАКСИС

          namespace ?option? ?arg?

## ОПИСАНИЕ

Команда позволяет создавать, обращаться и уничтожать отдельные области имен для команд и переменных. Более детально назначение и использование команды описаны ниже см. Пространства имен. Действия, выполняемые командой, зависят от значения аргумента option. Ниже приведены возможные опции команды.

namespace children ?namespace? ?pattern?
  Позволяет получить список областей-потомков для области имен namespace. Если аргумент namespace отсутствует, то возвращается список областей-потомков для текущего пространства имен. Команда возвращает полные имена, начинающиеся с ::. Если указан аргумент pattern, команда возвращает только те имена, которые удовлетворяют шаблону pattern. Проверка на соответствие производится по тем же правилам, что и в команде glob. При этом шаблон, начинающийся с ::, используется непосредственно, в противном случае используемый шаблон составляется из namespace (или полного имени текущего пространства имен) и pattern.
namespace code script

  Позволяет захватить контекст текущей области имен для скрипта script с тем, чтобы потом использовать этот контекст при выполнении данного скрипта. Команда возвращает новый скрипт, в котором старый скрипт завернут в команду namespace code. Новый скрипт имеет две важные особенности: во-первых, он может быть вызван в произвольном пространстве имен, при этом реально он будет выполняться в текущем пространстве имен (том, в котором выполнялась команда namespace code). Во-вторых, к созданному таким образом скрипту можно дописывать произвольные аргументы и они действительно будут использоваться как дополнительные аргументы. Например, предположим, что команда

      	  set script [namespace code {foo bar}]

  выполняется в пространстве имен ::a::b. Тогда команда

      	  eval " x y"

  может быть выполнена в любом пространстве имен и будет иметь тот же эффект, что и команда

      	  namespace eval ::a::b {foo bar x y}

  Эта команда необходима потому, что расширения Tcl, например, Tk, обычно выполняют вызванные по событиям скрипты в глобальном пространстве имен. Обертывающая команда захватывает необходимую команду вместе с ее пространством имен и позволяет корректно выполнить ее позже по соответствующему вызову. Примеры использования данного механизма приведены ниже см. Правила видимости имен.

namespace current
  Позволяет получить полное имя текущей области имен. Хотя реальное имя глобального пространства имен "" (пустая строка), эта команда возвращает для него ::, поскольку это часто бывает удобнее при программировании.
namespace delete ?namespace namespace...?
  Позволяет удалить одну или несколько областей имен, при этом удаляются все переменные, процедуры и области-потомки заданной области имен. Если внутри одного из удаляемых пространств имен выполняется какая-либо процедура, оно будет сохранено до завершения процедуры, но помечено, как приготовленное к удалению, чтобы исключить вызов других процедур. Если указанное пространство имен не существует, команда возвращает ошибку. Если ни одно пространство имен не указано, команда не делает ничего.
namespace eval namespace arg ?arg...?
  Позволяет активизировать пространство имен namespace и выполнить в его контексте заданный код. Если пространство имен namespace не существует, оно будет создано. Если пространство имен должно быть предком несуществующего пространства имен, то оно тоже создается. Если задано более одного аргумента, все они объединяются в одну строку через пробел (как при выполнении команды eval) и полученный скрипт выполняется.
namespace export ?-clear? ?pattern pattern...?
  Позволяет указать, какие команды разрешено экспортировать из данного пространства имен. Эти команды потом могут быть импортированы в другие пространства имен с помощью команды namespace import. Можно разрешать экспорт как команд, созданных в данном пространстве имен, так и команд, ранее импортированных из других пространств. Команда, разрешаемая для экспорта, может в данный момент не существовать. Каждый из шаблонов pattern может содержать специальные символы как в команде glob, но не может содержать имени пространства имен. То есть шаблон может указывать команды только в текущем пространстве имен. Каждый из шаблонов добавляется к списку шаблонов команд, разрешенных для импорта из данного пространства имен. Если в команде указан флаг -clear, команда предварительно удаляет старый список. Если не указаны ни флаг, ни шаблоны, команда возвращает текущий список шаблонов.
namespace forget ?pattern pattern...?
  Удаляет из пространства имен ранее импортированные команды. Каждый образец pattern должен быть полным именем команды с указанием хотя бы одного пространства имен и может содержать специальные символы, как в команде glob, например: foo::x или a::b::p*. Специальные символы нельзя использовать в именах пространств имен. При выполнении данной команды сначала ищутся команды, удовлетворяющие шаблону и разрешенные к экспорту из соответствующих пространств имен. Далее проверяется, какие из них были импортированы в текущее пространство имен. После чего импортированные команды удаляются. То есть команда выполняет действия, противоположные действиям команды namespace import.
namespace import ?-force? ?pattern pattern...?
  Импортирует команды в текущее пространство имен. Каждый образец pattern должен быть полным именем команды с указанием хотя бы одного пространства имен и может содержать специальные символы, как в команде glob, например foo::x или a::b::p*. Специальные символы нельзя использовать в именах пространств имен. Все команды, которые удовлетворяют шаблонам и разрешены для экспорта, добавляются к текущему пространству имен. Для этого в текущем пространстве имен создается новая команда, которая указывает на экспортируемую команду в исходном пространстве имен. При вызове этой новой команды она вызывает исходную команду. Если в текущем пространстве имен уже есть команда с таким именем, возвращается ошибка, если не указана опция -force. В противном случае импортируемая команда заменяет команду, определенную ранее. Команда namespace import импортирует в текущее пространство имен только те функции, которые в момент исполнения существуют в соответствующем пространстве имен. Если позже там будут созданы новые команды с именами, удовлетворяющими шаблонам, разрешающим экспорт, и шаблонам, определяющим импорт, то они не импортируются автоматически.
namespace inscope namespace arg ?arg...?

  Выполняет скрипт в контексте пространства имен namespace. Эта команда не предназначена для непосредственного исполнения программистом. Ее вызовы создаются автоматически при использовании команды namespace code для создания скриптов, выполняемых в фоновом режиме, например, для Tk-виджетов. Команда namespace inscope похожа на команду namespace eval, но отличается от нее наличием возможности указывать дополнительные аргументы и тем, что пространство имен namespace должно существовать в момент выполнения команды. При выполнении команды первый аргумент рассматривается как список, к которому остальные аргументы добавляются как элементы списка. Так команда

                namespace inscope ::foo a x y z

  эквивалентна

      	  namespace eval ::foo [concat a [list x y z]]

  Такая семантика весьма удобна при формировании скриптов, выполняемых в фоновом режиме.

namespace origin command
  Возвращает полное имя оригинальной команды command, от которой происходит заданная импортированная команда. При импорте команды в текущем пространстве имен создается новая команда, которая указывает на экспортируемую команду в исходном пространстве имен. Если команда последовательно импортировать в пространства имен a, b, ..., n, причем в каждое последующее пространство имен она импортировалась из предыдущего, то namespace origin вернет полное имя команды в первом пространстве имен, то есть a. Если команда command не импортирована, то namespace origin вернет ее полное имя.
namespace parent ?namespace?
  Возвращает полное имя родительского пространства имен для пространства namespace. Если аргумент namespace не указан, возвращает полное имя предка текущего пространства имен.
namespace qualifiers string
  Возвращает полное имя пространства имен для string, то есть часть строки string от начала до последнего символа :: (но не включая его). Например, для строки ::foo::bar::x эта команда вернет ::foo::bar, а для :: - "" (пустую строку). Команда является парной для команды namespace tail. При выполнении команды проверка существования соответствующих пространств имен не производится.
namespace tail string
  Возвращает простое имя, завершающее полное имя string, то есть часть строки string от последнего символа :: (но не включая его) до конца строки. Например, для строки ::foo::bar::x эта команда вернет x, а для :: - "" (пустую строку). Команда является парной для команды namespace qualifiers. При выполнении команды проверка существования соответствующих пространств имен не производится.
namespace which ?-command? ?-variable? name
  Рассматривает name как имя команды или переменной (в зависимости от указанной опции; по умолчанию - как имя команды) и возвращает ее полное имя. Например, если name не существует в текущем пространстве имен, но существует в глобальном, то возвращает полное имя в глобальном пространстве имен. Если команда или переменная не существует, данная команда возвращает пустую строку. Более подробно правила поиска имен см. Правила видимости имен.

## ЧТО ТАКОЕ ПРОСТРАНСТВО ИМЕН?

Пространство имен - это обособленный набор команд и переменных. Содержащиеся в нем команды и переменные не взаимодействуют с командами и переменными в других пространствах имен. В Tcl всегда был один такой набор, который мы будем называть глобальным пространством имен. В нем содержатся все глобальные переменные и команды. Команда namespace eval позволяет создавать другие пространства имен, например, команда

            namespace eval Counter {
          		namespace export Bump
          		variable num 0
          		proc Bump {} {
          			variable num
          			incr num
    		}
    	}

создает новое пространство имен, содержащее переменную num и процедуру Bump. Команды и переменные в этом пространстве имен изолированы от других команд и имен в той же программе. Например, в глобальном пространстве имен может существовать другая команда Bump.

Переменные пространства имен напоминают глобальные переменные. Они существуют вне процедур, но могут использоваться в процедурах с помощью команды variable, как показано в предыдущем примере.

Пространства имен - динамические образования. В них можно в любой момент добавлять команды и переменные с помощью дополнительных команд namespace eval. Например, то же пространство имен, что и в предыдущем примере, можно было создать с помощью последовательности команд:

          namespace eval Counter {
          	variable num 0
            proc Bump {} {
          		variable num
          		return [incr num]
          	}
          }
          namespace eval Counter {
          	proc test {args} {
          		return
          	}
          }

          namespace eval Counter {
          	rename test ""
          }

Обратите внимание, что процедура test создана в пространстве имен Counter, а затем удалена с помощью команды rename.

Пространства имен могут иметь собственные вложенные пространства имен и образовывать иерархию пространств имен. Вложенное пространство имен содержится в своем предке и не может взаимодействовать с другими пространствами имен.

## ПОЛНЫЕ ИМЕНА

Каждое пространство имен имеет собственное имя, например history или ::safe::interp. Полные имена используются для указания команд, переменных или подпространств имен, содержащихся в соответствующем пространстве имен. Полные имена напоминают полные имена файлов в Unix или виджетов в Tk, но в качестве разделителей в них используется не слэш или точка, а двойное двоеточие "::". Самое верхнее или глобальное пространство имен имеет имя "" (пустая строка) и :: как синоним. Как пример, имя ::safe::interp::create ссылается на команду create в пространстве имен interp, которое является подпространством пространства имен ::safe, которое в свою очередь является подпространством глобального пространства имен ::.

Если вы хотите указать команду или переменную в другом пространстве имен, вы можете указать имя пространства имен, в котором она содержится. Например, из глобального пространства имен вызвать процедуру из пространства имен Counter можно следующим образом:

          Counter::Bump 5
          Counter::Reset

А вывести текущее значение переменной count можно с помощью команды

          puts "count = ::num"

Если одно пространство имен содержит другое, может понадобиться более длинное имя. Если пространство имен Foo содержит пространство имен Counter, то чтобы вызвать процедуру Bump в последнем из глобального пространства имен, нужно воспользоваться именем

          Foo::Counter::Bump 3

Полное имя может использоваться при создании или переименовании команд. Например, можно добавить процедуру в пространство имен Foo следующей командой:

          proc Foo::Test {args} { return }

А переопределить ее в другом пространстве имен командой:

          rename Foo::Test Bar::Test

Дополнительные замечания. Имена пространств имен, за исключением глобального, не могут быть пустой строкой. Сочетание :: запрещено в именах простых команд, переменных и пространств имен кроме как в роли разделителя имен пространств имен. Дополнительные символы : в полных именах игнорируются, то есть два или больше символов : подряд считаются одним разделителем. Сочетание :: в конце имени команды или переменной указывает на команду или переменную с именем {} (пустая строка). Однако в полном имени пространства имен :: на конце игнорируется.

## ПРАВИЛА ВИДИМОСТИ ИМЕН

Все Tcl-команды, которые работают с именами переменных и команд, поддерживают полные имена. Это значит, что можно использовать полные имена в таких командах, как set, proc, rename, или interp alias. Если вы используете абсолютное имя, начинающееся с ::, то такое имя всегда интерпретируется однозначно. Однако, если вы используете относительное имя, не начинающееся с ::, поиск объекта с соответствующим именем происходит по следующим правилам: команды и переменные сначала ищутся в текущем пространстве имен, а затем (если не найдены) - в глобальном. Имена пространств имен ищутся только в текущем пространстве имен.

В следующем примере

          set traceLevel 0
          namespace eval Debug {
          	printTrace
          }

Tcl ищет переменную traceLevel в пространстве имен Debug и затем в глобальном пространстве имен. Аналогично ищется и процедура printTrace. Чтобы не оставлять неясностей, рассмотрим еще один пример:

          set traceLevel 0
          namespace eval Foo {
          	variable traceLevel 3
            namespace eval Debug {
                printTrace
            }
          }

Здесь Tcl ищет переменную traceLevel в пространстве имен Foo::Debug. Поскольку там ее нет, он продолжает поиск в глобальном пространстве имен. Переменная Foo::traceLevel в процессе поиска полностью игнорируется.

Чтобы разобраться в сложных ситуациях, можно использовать команду namespace which. Например, следующая команда:

          namespace eval Foo::Debug {namespace which -variable traceLevel}

вернет ::traceLevel. С другой стороны, команда:

          namespace eval Foo {namespace which -variable traceLevel}

вернет ::Foo::traceLevel.

Как уже упоминалось, относительные имена пространств имен ищутся иначе, чем имена команд и переменных. Они ищутся только в текущем пространстве имен. Это значит, что, например, команда namespace eval всегда создает потомка текущего пространства имен, если только имя нового пространства не начинается с ::.

Tcl не ограничивает доступ к командам, переменным или пространствам имен. Если вы указали имя, которое в соответствие с перечисленными выше правилами ссылается на нужный вам элемент, вы можете использовать этот элемент.

Переменные, определенные в данном пространстве имен, можно использовать в процедурах в этом же пространстве имен с помощью команды variable. Похожая на команду global, эта команда создает связь между локальной переменной в процедуре и одноименной переменной в пространстве имен. Если необходимо, эта команда также создает и инициализирует эту переменную (команда global только создает связь с переменной в глобальном пространстве имен). Команду variable можно не использовать, если вы всегда используете полное имя переменной.

## ИМПОРТ КОМАНД

Пространств имен часто используются для создания библиотек. Некоторые библиотечные команды могут использоваться так часто, что необходимость использования полных имен станет раздражать. Например, если все команды в такой библиотеке, как BLT, содержатся в пространстве имен Blt. Тогда вы смогли бы использовать их только следующим образом:

          Blt::graph .g -background red
          Blt::table .g 0,0

Если Вы используете команды graph и table регулярно, предпочтительнее использовать их без префикса Blt::. Для этого достаточно импортировать эти команды в текущее пространство имен, например, следующим образом:

          namespace import Blt::*

В результате выполнения этой команды все команды из пространства имен Blt будут экспортированы в текущее пространство имен, и вы сможете использовать их без соответствующего префикса:

          graph .g -background red
          table .g 0,0

Команда namespace import импортирует только те команды, экспорт которых разрешен с помощью команды namespace export.

Как правило, не стоит импортировать все команды из пространства имен, так как при этом может быть сложно отследить все команды, которые вы получите. Лучше указать явно, какие именно команды вам нужны. Например, команда

          namespace import Blt::graph Blt::table

импортирует только команды graph и table.

Если вы попытаетесь импортировать команду, которая уже существует в текущем пространстве имен, то вы получите ошибку. Это предупредит, например, попытки скопировать одну и ту же команду из двух разных библиотек. Однако время от времени (например, при отладке) у вас может появиться желание преодолеть данное ограничение. Для этого нужно указать в команде опцию -force, и тогда существующая команда будет заменена на импортируемую команду без сообщения об ошибке:

          namespace import -force Blt::graph Blt::table

Если вам почему-либо надо прекратить использование библиотечной команды, это можно сделать следующим образом:

          namespace forget Blt::*

Эта команда ищет в текущем пространстве имен все команды, импортированные из Blt, и удаляет их. Если таких команд не оказалось, команда ничего не делает. После исполнения команды namespace forget Blt::* команды из пространства имен Blt можно использовать только с префиксом Blt::.

Если вы удаляете команду из того пространства имен, где она была создана, например:

          rename Blt::graph ""

то она будет удалена из всех пространств имен, в которые она была импортирована.

## ЭКСПОРТ КОМАНД

Вы можете разрешить экспорт команд из определенного пространства имен:

          namespace eval Counter {
          	namespace export Bump Reset
            variable num 0
            variable max 100
            proc Bump {{by 1}} {
          		variable num
            	incr num
          		check
          		return
          	}
            proc Reset {} {
          		variable num
          		set num 0
            }
          	proc check {} {
          		variable num
          		variable max
          		if { > } {
          			error "too high!"
          		}
          	}
          }

После этого процедуры Bump и Reset можно импортировать, например, с помощью команды:

          namespace import Counter::*

Но экспорт процедуры check не разрешен, и она не будет импортирована этой командой.

Команда namespace import позволяет импортировать только те команды, которые разрешено экспортировать из их пространства имен с помощью команды namespace export. Если в команде namespace import указана команда, которую нельзя экспортировать, она не будет импортирована в соответствующее пространство имен.