Руководство по Ada (Ada 2022)
10.1.2 Определения контекста — операторы with
Оператор context_clause используется для указания library_itemов, имена которых необходимы внутри единицы компиляции.
Синтаксис
Правила разрешения имен
Область видимости оператора with_clause, который появляется в library_unit_declaration или library_unit_renaming_declaration, охватывает всю декларативную область объявления, включая все дочерние элементы и подблоки. Область видимости оператора with_clause в теле состоит из тела, включая все подблоки.
library_item (и соответствующая единица библиотеки) называется в with_clause, если она обозначена именем library_unit_name в with_clause. library_item (и соответствующая единица библиотеки) упоминается в with_clause, если она названа в with_clause или обозначается префиксом в with_clause.
За пределами собственной декларативной области объявление или переименование единицы библиотеки могут быть видны только в области видимости with_clause, которая её упоминает. Видимость объявления или переименования единицы библиотеки в противном случае следует из её размещения в окружении.
Правила законности
Если with_clause данной compilation_unit упоминает закрытый дочерний элемент некоторой единицы библиотеки, то данная compilation_unit должна быть одной из:
- объявлением, телом или подблоком закрытого потомка этой единицы библиотеки;
- телом или подблоком публичного потомка этой единицы библиотеки, но не телом подпрограммы, действующим как объявление подпрограммы (см. 10.1.4); или
- объявлением публичного потомка этой единицы библиотеки, в этом случае with_clause должен содержать зарезервированное слово private.
Имя, обозначающее library_item (или соответствующее объявление для дочернего элемента обобщённого внутри экземпляра — см. 10.1.1), если оно видно только благодаря упоминанию в одном или нескольких with_clauseов единицы U, которые включают зарезервированное слово private, должно появляться только внутри:
- частной части;
- тела публичного потомка U, но не в subprogram_specification тела подпрограммы, являющейся публичным потомком U;
- закрытого потомка U или его тела; или
- псевдонима внутри оператора контекста.
Элемент библиотеки, упомянутый в limited_with_clause, должен быть неявным объявлением ограниченного вида библиотечного пакета, а не объявлением подпрограммы, обобщённого элемента, экземпляра обобщённого элемента или переименования.
Оператор limited_with_clause не должен появляться в library_unit_body, subunit или library_unit_renaming_declaration.
Оператор limited_with_clause, который называет библиотечный пакет, не должен появляться:
- в операторе контекста для явного объявления названного библиотечного пакета или любого его потомка;
- в операторе контекста для library_item, который находится в области видимости оператора nonlimited_with_clause, который упоминает тот же библиотечный пакет; или
- в операторе контекста для library_item, который находится в области видимости оператора use_clause, который называет сущность, объявленную в декларативной области библиотечного пакета.
ПРИМЕЧАНИЕ Элемент библиотеки, упомянутый в операторе nonlimited_with_clause единицы компиляции, виден внутри единицы компиляции и поэтому действует как обычное объявление. Таким образом, внутри единицы компиляции, которая упоминает его объявление, имя библиотечного пакета может быть указано в операторах use_clause, может использоваться для построения расширенных имён, библиотечная подпрограмма может быть вызвана, а экземпляры библиотечной обобщённой единицы могут быть объявлены. Если дочерний элемент родительского обобщённого пакета упоминается в nonlimited_with_clause, то соответствующее объявление, вложенное в каждый видимый экземпляр, видно внутри единицы компиляции. Аналогично, library_item, упомянутый в limited_with_clause единицы компиляции, виден внутри единицы компиляции и, таким образом, может быть использован для построения расширенных имён.
Примеры
Примеры использования операторов with, limited with и private with:
package Office is
end Office;
end Office;
with Ada.Strings.Unbounded;
package Office.Locations is
type Location is new Ada.Strings.Unbounded.Unbounded_String;
end Office.Locations;
package Office.Locations is
type Location is new Ada.Strings.Unbounded.Unbounded_String;
end Office.Locations;
limited with Office.Departments; -- типы неполны
private with Office.Locations; -- только виден в частной части
package Office.Employees is
type Employee is private;
private with Office.Locations; -- только виден в частной части
package Office.Employees is
type Employee is private;
function Dept_Of(Emp : Employee) return access Departments.Department;
procedure Assign_Dept(Emp : in out Employee;
Dept : access Departments.Department);
procedure Assign_Dept(Emp : in out Employee;
Dept : access Departments.Department);
...
private
type Employee is
record
Dept : access Departments.Department;
Loc : Locations.Location;
...
end record;
end Office.Employees;
private
type Employee is
record
Dept : access Departments.Department;
Loc : Locations.Location;
...
end record;
end Office.Employees;
limited with Office.Employees;
package Office.Departments is
type Department is ...;
package Office.Departments is
type Department is ...;
function Manager_Of(Dept : Department) return access Employees.Employee;
procedure Assign_Manager(Dept : in out Department;
Mgr : access Employees.Employee);
...
end Office.Departments;
END_OF_DOCUMENT_MARKER procedure Assign_Manager(Dept : in out Department;
Mgr : access Employees.Employee);
...
end Office.Departments;
Можно использовать ограничение для поддержки взаимозависимых абстракций, разделенных по нескольким пакетам. В этом случае сотрудник назначается в отдел, а отдел имеет руководителя, который также является сотрудником. Если ограничение со служебным словом private появляется в одном модуле библиотеки и упоминает второй модуль, оно предоставляет видимость второму модулю, но ограничивает эту видимость частной частью и телом первого модуля. Компилятор проверяет, что второй модуль не используется в видимой части первого модуля.