Пространства имен и подключение библиотек

Содержание

  1. Помещение идентификатора в пространство имен
  2. Поиск идентификатора в пространствах имен
  3. Списки составляющих пространства имен программных элементов
  4. Режим позднего импорта

Доступность для обращения по имени разнородных программных элементов: типов, констант, переменных, полей таблиц БД, процедур и функций в той или иной части программы определяется механизмом поиска в пространствах имен. В течение времени жизни перечисленных программных элементов их идентификаторы обязательно присутствуют хотя бы в одном из пространств имен. Различают встроенное в оболочку (клиент ASB) пространство имен, глобальное пространство имен модуля, локальное пространство имен процедуры, а также пространства имен дескрипторов обрабатываемых в TRY-блоках исключений.

Помещение идентификатора в пространство имен

Как программные элементы попадают в соответствующие пространства имен? Во-первых, по месту определения. Имена формальных параметров процедуры, локальных типов, констант и переменных попадают в локальное пространство имен процедуры. Имена глобальных типов, констант, переменных модуля, а также имена процедур попадают в глобальное пространство имен модуля. Имена встроенных типов, констант, переменных, процедур, встроенных библиотек, регулярных таблиц БД попадают во встроенное пространство имен. Во-вторых, в результате статического или динамического подключения библиотечного модуля. И в-третьих, в результате подключения нерегулярной таблицы БД.

Сначала рассмотрим подключение модулей, статическое или динамическое. До версии 14.246.030 статическое подключение выполнялось явно оператором IMPORT, расположенным среди глобальных определений модуля или локальных определений процедуры. Начиная с версии 14.246.030 по умолчанию действует режим позднего импорта, в котором операторы IMPORT игнорируются, а статическое подключение библиотеки выполняется в момент первого использования ее имени; либо среди глобальных или локальных определений, либо в исполняемом коде модуля. В обоих случаях появляется подпространство экспортируемых имен библиотеки, имена всех публичных программных элементов библиотеки (типов, констант, переменных и процедур) помещаются в это подпространство. Соответственно, обращаться к программным элементам, экспортируемым библиотекой, необходимо с указанием префикса - имени модуля. Операторы динамического подключения PASTE и LOADMODULE помещаются в исполняемый код модуля и добавляют (PASTE - в глобальное пространство имен подключающего модуля, LOADMODULE - в подпространство библиотеки в глобальном пространстве имен подключающего модуля) только процедуры. Библиотека может быть динамически подключена только к одному модулю (мастер-модулю) в пределах программного комплекса.

Для регулирования видимости при подключении модулей служат модификаторы доступа PUBLIC и PRIVATE. Модификатор доступа указывается перед блоком глобальных определений библиотечного модуля, т.е. перед ключевыми словами TYPE, VAR, CONST, PROCEDURE, и относится ко всем определениям блока. Модификатор PUBLIC указывает, что определение публично, т.е. экспортируется модулем, а модификатор PRIVATE указывает, что определение приватно и доступно только в пределах модуля. Модификатор доступа можно не указывать, по умолчанию типы, константы и переменные определены как приватные, а для процедур и функций умолчание задает атрибут DEFAULTACCESSLEVELFORPROCEDURE оператора MODULE; в отсутствие атрибута процедуры и функции приватны по умолчанию для статически подключаемых библиотек, публичны для динамически подключаемых.

Головной модуль и статически подключаемая библиотека несимметрично работают с глобальными переменными. Если головной модуль вызовет самого себя оператором CALL, получится два комплекта глобальных переменных: у вызывающего модуля и у вызываемого. Между тем в библиотеках при входе в CALL нового комплекта глобальных переменных не появляется. Если библиотеке разрешить импорт головного модуля, то к какому из двух комплектов глобальных переменных головного модуля она получит доступ? В связи с этим до версии 14.112.6 существовало два связанных запрета.

  1. Запрет на статическое подключение головного модуля.
  2. Запрет вызова при помощи CALL модуля, подключенного в качестве библиотеки.

Начиная с версии 14.112.6 поддержан атрибут STATICEXPORTMODE оператора MODULE, регулирующий экспорт из модуля. В режиме STATICEXPORTMODE_ASLIBRARY из модуля экспортируются все публичные типы, константы, переменные и процедуры; соответственно, если модуль является головным, его нельзя импортировать, если является библиотечным, его нельзя вызвать при помощи оператора CALL. Режим STATICEXPORTMODE_ASLIBRARY действует по умолчанию. В режиме STATICEXPORTMODE_ASMAINMODULE из модуля экспортируются только публичные типы и константы, соответственно, оба ограничения снимаются. Если модуль является головным, его можно импортировать, если является библиотечным, - можно вызвать при помощи операторов CALL.

Оператор динамического подключения PASTE может использоваться только в исполняемом коде (не в определениях) и добавляет в глобальное пространство имен мастер-модуля только публичные процедуры и функции библиотеки. Перед разбором определений paste-библиотеки в ее пространство имен копируется пространство имен мастер-модуля в состоянии на момент выполнения оператора PASTE, т.е. paste-библиотека выполняет неявное подключение мастер-модуля, игнорируя правила видимости, заданные модификаторами PUBLIC и PRIVATE.

Оператор динамического подключения LOADMODULE может использоваться только в исполняемом коде и добавляет в глобальное пространство имен модуля подпространство библиотеки, имя которого задается алиасом библиотеки; имена всех публичных процедур и функций библиотеки помещаются в подпространство библиотеки, типы, константы и переменные не добавляются. В отличие от оператора PASTE, библиотека не наследует пространство имен мастер-модуля, но зато может подключить мастер-модуль статически. Из запрета на статическое подключение головных модулей сделано исключение специально для библиотек, подключенных оператором LOADMODULE; библиотекам, динамически подключенным головным модулем, разрешено статически подключать головной модуль.

Оператор динамического отключения FREEMODULE также может использоваться только в исполняемом коде и удаляет из глобального пространства имен вызвавшего модуля подпространство имен библиотеки, задаваемое алиасом - параметром FREEMODULE. Разумеется, отключить при помощи оператора FREEMODULE можно только модули, динамически подключенные оператором LOADMODULE. Отключить неподключенный модуль безвредно.

Наконец, при подключении нерегулярной таблицы БД встроенной процедурой-функцией ATTACH_TABLE, в глобальных пространствах имен всех модулей программного комплекса появляется подпространство таблицы БД (с именем таблицы), а имена всех полей таблицы помещаются в это подпространство. Процедура DETACH_TABLE выполняет обратную операцию, убирая из глобальных пространств имен всех модулей программного комплекса подпространство нерегулярной таблицы БД.

Поиск идентификатора в пространствах имен

В общем случае, при поиске идентификатора просмотр пространств имен выполняется в показанном на рисунке порядке.

Понятно, что в некоторых позициях исполняемого кода часть пространств имен может отсутствовать. Если исполняется тело модуля, никакого локального пространства имен нет. А пространства имен дескрипторов исключений появляются только в EXCEPT-ON-DO блоке.

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

Идентификаторы, находящиеся в одном пространстве/подпространстве имен, не должны в нем конфликтовать, кроме нескольких специальных случаев, описанных ниже. В этих специальных случаях разрешается давать одно имя двум разнородным программным элементам, находящимся в одном пространстве имен (например процедурам и полям таблиц БД), а род программного элемента определяется по косвенным признакам (например по наличию открывающей скобки после имени процедуры).

Таблица конфликтов разнородных программных элементов в одном пространстве имен
Конфликт Модуль Таблица БД Курсорный тип Тип Константа или переменная Поле таблицы БД Процедура или функция
Модуль запрещен разрешен разрешен запрещен запрещен невозможен разрешен
Таблица БД разрешен запрещен разрешен запрещен запрещен  невозможен разрешен
Курсорный тип разрешен разрешен запрещен запрещен запрещен  невозможен разрешен
Тип запрещен запрещен запрещен запрещен запрещен запрещен запрещен
Константа или переменная запрещен запрещен запрещен запрещен запрещен запрещен запрещен
Поле таблицы БД  невозможен невозможен невозможен запрещен запрещен запрещен разрешен
Процедура или функция разрешен разрешен запрещен запрещен запрещен разрешен запрещен

Как видно из таблицы, разрешены три типа конфликтов:

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

Списки составляющих пространства имен программных элементов

Пространство имен Составляющие программные элементы
      Пространство имен дескриптора обрабатываемого исключений
  1. Содержит единственный идентификатор - имя дескриптора обрабатываемого исключения. Пространство появляется в в момент входа в EXCEPT-ON-DO-блок, и удаляется после выхода из него.
      Локальное пространство имен процедуры (функции)
  1. Имена формальных параметров процедуры (функции).
  2. Имена локальных типов, констант и переменных процедуры (функции).
      Глобальное пространство имен модуля
  1. Имена глобальных типов, констант и переменных модуля.
  2. Имена неявных глобальных переменных MODE и Event.
  3. Имена процедур и функций модуля.
  4. Имена подпространств, образуемых статически подключенными библиотеками.
  5. Имена публичных процедур (функций) библиотек, подключенных оператором PASTE.
  6. Имена подпространств, образуемых нерегулярными таблицами БД, подключенными на данный момент.
  7. Для модуля, подключенного оператором PASTE: все (в том числе непубличные) имена из глобального пространства имен модуля, выполнившего PASTE.
      Встроенное в V32 пространство имен
  1. Имена встроенных в оболочку типов, констант, процедур и функций.
  2. Имена подпространств, образуемых встроенными AEL-модулями.
  3. Имена подпространств, образуемых регулярными таблицами БД.
  4. Имена курсорных типов, соответствующих таблицам БД.
Подпространство, образуемое таблицей БД
  1. Имена полей таблицы БД.
Подпространство, образуемое статически подключаемой библиотекой
  1. Имена публичных типов, констант, переменных, процедур и функций библиотеки.
Подпространство, образуемое динамически подключаемой библиотекой (LOADMODULE)
  1. Имена публичных процедур и функций библиотеки.

Режим позднего импорта

Начиная с версии 14.246.030 интерпретатор ASL по умолчанию работает в режиме позднего импорта, в котором операторы IMPORT игнорируются, а статическое подключение библиотеки выполняется автоматически в момент первого использования ее имени; либо среди глобальных или локальных определений, либо и в исполняемом коде модуля. В течение переходного периода режим может быть отключен параметром LaterImport секции "ASL Options" клиентского RED-файла; впоследствии возможность отключения будет ликвидирована. Преимуществом режима позднего импорта является быстрый запуск программного комплекса.

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

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

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