Annotated Ada Reference ManualLegal Information
Contents   Index   References   Search   Previous   Next 

10.1.2 Context Clauses - With Clauses

[A context_clause is used to specify the library_items whose names are needed within a compilation unit.] 

Language Design Principles

The reader should be able to understand a context_clause without looking ahead. Similarly, when compiling a context_clause, the compiler should not have to look ahead at subsequent context_items, nor at the compilation unit to which the context_clause is attached. (We have not completely achieved this.)
{AI95-00217-06} A ripple effect occurs when the legality of a compilation unit could be affected by adding or removing an otherwise unneeded with_clause on some compilation unit on which the unit depends, directly or indirectly. We try to avoid ripple effects because they make understanding and maintenance more difficult. However, ripple effects can occur because of direct visibility (as in child units); this seems impossible to eliminate. The ripple effect for with_clauses is somewhat similar to the Beaujolais effect (see 8.4) for use_clauses, which we also try to avoid. 


context_clause ::= {context_item}
context_item ::= with_clause | use_clause
{AI95-00217-06} {AI95-00262-01} with_clause ::= limited_with_clause | nonlimited_with_clause with library_unit_name {, library_unit_name};
limited_with_clause ::= limited [privatewith library_unit_name {, library_unit_name};
nonlimited_with_clause ::= [privatewith library_unit_name {, library_unit_name};
Discussion: {AI95-00217-06} A limited_with_clause makes a limited view of a unit visible.
{AI95-00262-01} A with_clause containing the reserved word private is called a private with_clause. It can be thought of as making items visible only in the private part, although it really makes items visible everywhere except the visible part. It can be used both for documentation purposes (to say that a unit is not used in the visible part), and to allow access to private units that otherwise would be prohibited. 

Name Resolution Rules

The scope of a with_clause that appears on a library_unit_declaration or library_unit_renaming_declaration consists of the entire declarative region of the declaration[, which includes all children and subunits]. The scope of a with_clause that appears on a body consists of the body[, which includes all subunits].
Discussion: {AI95-00262-01} Suppose a nonprivate  with_clause of a public library unit mentions one of its private siblings. (This is only allowed on the body of the public library unit.) We considered making the scope of that with_clause not include the visible part of the public library unit. (This would only matter for a subprogram_body, since those are the only kinds of body that have a visible part, and only if the subprogram_body completes a subprogram_declaration, since otherwise the with_clause would be illegal.) We did not put in such a rule for two reasons: (1) It would complicate the wording of the rules, because we would have to split each with_clause into pieces, in order to correctly handle “with P, Q;” where P is public and Q is private. (2) The conformance rules prevent any problems. It doesn't matter if a type name in the spec of the body denotes the completion of a private_type_declaration.
A with_clause also affects visibility within subsequent use_clauses and pragmas of the same context_clause, even though those are not in the scope of the with_clause.
{AI95-00217-06} A library_item (and the corresponding library unit) is named mentioned in a with_clause if it is denoted by a library_unit_name or a prefix in the with_clause. A library_item (and the corresponding library unit) is mentioned in a with_clause if it is named in the with_clause or if it is denoted by a prefix in the with_clause.
Discussion: {AI05-0299-1} With_clauses control the visibility of declarations or renamings of library units. Mentioning a root library unit in a with_clause makes its declaration directly visible. Mentioning a nonroot library unit makes its declaration visible. See Clause Section 8 for details.
{AI95-00114-01} Note that this rule implies that “with A.B.C;” is almost equivalent to “with A, A.B, A.B.C;”. The reason for making a with_clause apply to all the ancestor units is to avoid “visibility holes” — situations in which an inner program unit is visible while an outer one is not. Visibility holes would cause semantic complexity and implementation difficulty. (This is not exactly equivalent because the latter with_clause names A and A.B, while the previous one does not. Whether a unit is “named” does not have any effect on visibility, however, so it is equivalent for visibility purposes.)
[Outside its own declarative region, the declaration or renaming of a library unit can be visible only within the scope of a with_clause that mentions it. The visibility of the declaration or renaming of a library unit otherwise follows from its placement in the environment.]

Legality Rules

{AI95-00262-01} If a with_clause of a given compilation_unit mentions a private child of some library unit, then the given compilation_unit shall be one of: either the declaration of a private descendant of that library unit or the body or subunit of a [(public or private)] descendant of that library unit.
{AI95-00262-01} the declaration, body, or subunit of a private descendant of that library unit;
{AI95-00220-01} {AI95-00262-01} the body or subunit of a public descendant of that library unit, but not a subprogram body acting as a subprogram declaration (see 10.1.4); or
{AI95-00262-01} the declaration of a public descendant of that library unit, in which case the with_clause shall include the reserved word private. 
Reason: {AI95-00262-01} The purpose of this rule is to prevent a private child from being visible (or even semantically depended-on) from outside the subsystem rooted at its parent. A private child can be semantically depended-on without violating this principle if it is used in a private with_clause.
Discussion: This rule violates the one-pass context_clauses Language Design Principle. We rationalize this by saying that at least that Language Design Principle works for legal compilation units.
package A is
end A;
package A.B is
end A.B;
private package A.B.C is
end A.B.C;
package A.B.C.D is
end A.B.C.D;
with A.B.C; -- (1)
private package A.B.X is
end A.B.X;
package A.B.Y is
end A.B.Y;
with A.B.C; -- (2)
package body A.B.Y is
end A.B.Y;
private with A.B.C; -- (3)
package A.B.Z is
end A.B.Z;
{AI95-00262-01} (1) is OK because it's a private child of A.B — it would be illegal if we made A.B.X a public child of A.B. (2) is OK because it's the body of a child of A.B. (3) is OK because it's a child of A.B, and it is a private with_clause. It would be illegal to say “with A.B.C;” on any library_item whose name does not start with “A.B”. Note that mentioning A.B.C.D in a with_clause automatically mentions A.B.C as well, so “with A.B.C.D;” is illegal in the same places as “with A.B.C;”. 
To be honest: {AI05-0005-1} {AI95-00262-01} For the purposes of this rule, if a subprogram_body has no preceding subprogram_declaration, the subprogram_body should be considered a declaration and not a body. Thus, it is illegal for such a subprogram_body to mention one of its siblings in a nonprivate with_clause if the sibling is a private library unit. 
 {AI95-00262-01} {AI05-0077-1} {AI05-0122-1} A name denoting a library_item (or the corresponding declaration for a child of a generic within an instance — see 10.1.1), if it library item that is visible only due to being mentioned in one or more with_clauses that include the reserved word private, shall appear only within: 
a private part;
a body, but not within the subprogram_specification of a library subprogram body;
a private descendant of the unit on which one of these with_clauses appear; or
a pragma within a context clause. 
Ramification: These rules apply only if all of the with_clauses that mention the name include the reserved word private. They do not apply if the name is mentioned in any with_clause that does not include private. 
Reason: {AI05-0077-1} These rules make the library_item library item visible anywhere that is not visible outside the subsystem rooted at the compilation_unit having the private with_clause, including private parts of packages nested in the visible part, private parts of child packages, the visible part of private children, and context clause pragmas like Elaborate_All.
We considered having the scope of a private with_clause not include the visible part. However, that rule would mean that moving a declaration between the visible part and the private part could change its meaning from one legal interpretation to a different legal interpretation. For example: 
package A is
    function B return Integer;
end A;
function B return Integer;
with A;
private with B;
package C is
    use A;
    V1 : Integer := B; -- (1)
    V2 : Integer := B; -- (2)
end C;
If we say that library subprogram B is not in scope in the visible part of C, then the B at (1) resolves to A.B, while (2) resolves to library unit B. Simply moving a declaration could silently change its meaning. With the legality rule defined above, the B at (1) is illegal. If the user really meant A.B, they still can say that. 
 {AI95-00217-06} [A library_item mentioned in a limited_with_clause shall be the implicit declaration of the limited view of a library package, not the declaration of a subprogram, generic unit, generic instance, or a renaming.]
Proof: This is redundant because only such implicit declarations are visible in a limited_with_clause. See 10.1.6. 
 {AI95-00217-06} {AI95-00412-01} A limited_with_clause shall not appear on a library_unit_body, subunit, or library_unit_renaming_declaration.
Reason: {AI95-00412-01} We don't allow a limited_with_clause on a library_unit_renaming_declaration because it would be useless and therefore probably is a mistake. A renaming cannot appear in a limited_with_clause (by the rule prior to this one), and a renaming of a limited view cannot appear in a nonlimited_with_clause (because the name would not be within the scope of a with_clause denoting the package, see 8.5.3). Nor could it be the parent of another unit. That doesn't leave anywhere that the name of such a renaming could appear, so we simply make writing it illegal. 
 {AI95-00217-06} A limited_with_clause that names a library package shall not appear:
{AI95-00217-06} {AI05-0040-1} in the context_clause for the explicit declaration of the named library package or any of its descendants;
Reason: We have to explicitly disallow 
limited with P;
package P is ...
as we can't depend on the semantic dependence rules to do it for us as with regular withs. This says “named” and not “mentioned” in order that 
limited private with P.Child;
package P is ...
can be used to allow a mutual dependence between the private part of P and the private child P.Child, which occurs in interfacing and other problems. Since the child always semantically depends on the parent, this is the only way such a dependence can be broken.
{AI05-0040-1} The part about descendants catches examples like
limited with P;
package P.Child is ...
{AI95-00217-06} {AI05-0077-1} {AI05-0262-1} within a in the same context_clause for a library_item that is as, or within the scope of, a nonlimited_with_clause that mentions the same library package; or
Ramification: {AI05-0077-1} This applies to nonlimited_with_clauses found in the same context_clause, as well as nonlimited_with_clauses found on parent units. 
Reason: {AI05-0077-1} Such a limited_with_clause could have no effect, and would be confusing. If it is within the scope of a nonlimited_with_clause for the same package is inherited from a parent unit or given, or if such a clause is in the context_clause, the full view is available, which strictly provides more information than the limited view. 
{AI95-00217-06} {AI05-0077-1} {AI05-0262-1} within a in the same context_clause for a library_item that is as, or within the scope of, a use_clause that names an entity declared within the declarative region of the library package.
Ramification: {AI05-0077-1} This applies to use_clauses found in the same context_clause, as well as use_clauses found in (or on) parent units. 
Reason: This prevents visibility issues, where whether an entity is an incomplete or full view depends on how the name of the entity is written. The limited_with_clause cannot be useful, as we must have the full view available in the parent in order for the use_clause to be legal. 
3  {AI95-00217-06} A library_item mentioned in a nonlimited_with_clause with_clause of a compilation unit is visible within the compilation unit and hence acts just like an ordinary declaration. Thus, within a compilation unit that mentions its declaration, the name of a library package can be given in use_clauses and can be used to form expanded names, a library subprogram can be called, and instances of a generic library unit can be declared. If a child of a parent generic package is mentioned in a nonlimited_with_clause with_clause, then the corresponding declaration nested within each visible instance is visible within the compilation unit. Similarly, a library_item mentioned in a limited_with_clause of a compilation unit is visible within the compilation unit and thus can be used to form expanded names.
Ramification: The rules given for with_clauses are such that the same effect is obtained whether the name of a library unit is mentioned once or more than once by the applicable with_clauses, or even within a given with_clause.
If a with_clause mentions a library_unit_renaming_declaration, it only “mentions” the prefixes appearing explicitly in the with_clause (and the renamed view itself); the with_clause is not defined to mention the ancestors of the renamed entity. Thus, if X renames Y.Z, then “with X;” does not make the declarations of Y or Z visible. Note that this does not cause the dreaded visibility holes mentioned above. 


{AI95-00433-01} package Office is
end Office;
{AI95-00433-01} with Ada.Strings.Unbounded;
package Office.Locations is
   type Location is new Ada.Strings.Unbounded.Unbounded_String;
end Office.Locations;
{AI95-00433-01} limited with Office.Departments;  -- types are incomplete
private with Office.Locations;    -- only visible in private part
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);
 Employee is

         Dept : access Departments.Department;
         Loc : Locations.Location;
      end record;
end Office.Employees;
limited with Office.Employees;
package Office.Departments is
   type Department is private;
   function Manager_Of(Dept : Department) return access Employees.Employee;
   procedure Assign_Manager(Dept : in out Department;
                            Mgr  : access Employees.Employee);
end Office.Departments;
 {AI95-00433-01} The limited_with_clause may be used to support mutually dependent abstractions that are split across multiple packages. In this case, an employee is assigned to a department, and a department has a manager who is an employee. If a with_clause with the reserved word private appears on one library unit and mentions a second library unit, it provides visibility to the second library unit, but restricts that visibility to the private part and body of the first unit. The compiler checks that no use is made of the second unit in the visible part of the first unit.

Extensions to Ada 83

The syntax rule for with_clause is modified to allow expanded name notation.
A use_clause in a context_clause may be for a package (or type) nested in a library package. 

Wording Changes from Ada 83

The syntax rule for context_clause is modified to more closely reflect the semantics. The Ada 83 syntax rule implies that the use_clauses that appear immediately after a particular with_clause are somehow attached to that with_clause, which is not true. The new syntax allows a use_clause to appear first, but that is prevented by a textual rule that already exists in Ada 83.
The concept of “scope of a with_clause” (which is a region of text) replaces RM83's notion of “apply to” (a with_clause applies to a library_item) The visibility rules are interested in a region of text, not in a set of compilation units.
No need to define “apply to” for use_clauses. Their semantics are fully covered by the “scope (of a use_clause)” definition in 8.4

Incompatibilities With Ada 95

{AI95-00220-01} Amendment Correction: A subprogram body acting as a declaration cannot with a private child unit. This would allow public export of types declared in private child packages, and thus cannot be allowed. This was allowed by mistake in Ada 95; a subprogram that does this will now be illegal. 

Extensions to Ada 95

{AI95-00217-06} limited_with_clauses are new. They make a limited view of a package visible, where all of the types in the package are incomplete. They facilitate construction of mutually recursive types in multiple packages.
{AI95-00262-01} {AI05-0077-1} The syntax rules for with_clause are modified to allow the reserved word private. Private with_clauses do not allow the use of their library_item library item in the visible part of their compilation_unit. They also allow using private units in more locations than in Ada 95.

Incompatibilities With Ada 2005

{AI05-0040-1} Correction: Added missing rule that a limited with clause cannot name an ancestor unit. This is incompatible if an Ada 2005 program does this, but as this is a new Ada 2005 feature and the unintentionally allowed capability is not useful, the incompatibility is very unlikely to occur in practice. 

Wording Changes from Ada 2005

{AI05-0077-1} Correction: Fixed wording so that we are not checking whether something in a context_clause is “within the scope of” something, as context_clauses are never included in anything's scope. The intended meaning is unchanged, however.
{AI05-0122-1} Correction: Fixed wording so the rules for private with clauses also apply to "sprouted" generic child units. 

Contents   Index   References   Search   Previous   Next 
Ada-Europe Ada 2005 and 2012 Editions sponsored in part by Ada-Europe