10.1.2 Context Clauses - With Clauses
1
Language Design Principles
1.a
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.)
1.b/2
{
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.
Syntax
2
3
4/2
4.1/2
limited_with_clause ::= limited [private] with library_unit_name {, library_unit_name};
4.2/2
nonlimited_with_clause ::= [private] with library_unit_name {, library_unit_name};
4.a/2
4.b/2
{
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
5
5.a/2
Discussion: {
AI95-00262-01}
Suppose a
non-private 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.
5.b
6/2
6.a
Discussion: 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 non-root library
unit makes its declaration visible. See Section 8 for details.
6.b/2
{
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.)
7
[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
8/2
{
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.
9/2
{
AI95-00262-01}
the declaration, body, or subunit of a private
descendant of that library unit;
10/2
{
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
11/2
{
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.
11.a/2
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.
11.b
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.
11.c
Example:
11.d
package A is
end A;
11.e
package A.B is
end A.B;
11.f
private package A.B.C is
end A.B.C;
11.g
package A.B.C.D is
end A.B.C.D;
11.h
with A.B.C; -- (1)
private package A.B.X is
end A.B.X;
11.i
package A.B.Y is
end A.B.Y;
11.j
with A.B.C; -- (2)
package body A.B.Y is
end A.B.Y;
11.j.1/2
private with A.B.C; -- (3)
package A.B.Z is
end A.B.Z;
11.k/2
{
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;”.
11.l/2
12/3
13/2
a private part;
14/2
15/2
a private descendant of the
unit on which one of these with_clauses
appear; or
16/2
a pragma within a context
clause.
16.a/2
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.
16.b/3
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.
16.c/2
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:
16.d/2
package A is
function B return Integer;
end A;
16.e/2
function B return Integer;
16.f/2
with A;
private with B;
package C is
use A;
V1 : Integer := B; -- (1)
private
V2 : Integer := B; -- (2)
end C;
16.g/2
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.
17/2
{
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.]
17.a/2
18/2
18.a/2
19/2
20/3
20.a/2
Reason: We have
to explicitly disallow
20.b/2
limited with P;
package P is ...
20.c/2
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
20.d/2
limited private with P.Child;
package P is ...
20.e/2
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.
20.f/3
{
AI05-0040-1}
The part about descendants catches examples like
20.g/3
limited with P;
package P.Child is ...
21/3
21.a.1/3
21.a/3
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.
22/3
22.a.1/3
22.a/2
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.
23/2
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.
23.a
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.
23.b
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.
Examples
24/2
25/2
{
AI95-00433-01}
with Ada.Strings.Unbounded;
package Office.Locations is
type Location is new Ada.Strings.Unbounded.Unbounded_String;
end Office.Locations;
26/2
{
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;
27/2
function Dept_Of(Emp : Employee) return access Departments.Department;
procedure Assign_Dept(Emp : in out Employee;
Dept : access Departments.Department);
28/2
...
private
type Employee is
record
Dept : access Departments.Department;
Loc : Locations.Location;
...
end record;
end Office.Employees;
29/2
limited with Office.Employees;
package Office.Departments is
type Department is private;
30/2
function Manager_Of(Dept : Department) return access Employees.Employee;
procedure Assign_Manager(Dept : in out Department;
Mgr : access Employees.Employee);
...
end Office.Departments;
31/2
{
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
31.a
The syntax rule for
with_clause
is modified to allow expanded name notation.
31.b
Wording Changes from Ada 83
31.c
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.
31.d
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.
31.e
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
31.f/2
{
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
31.g/2
{
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.
31.h/3
Incompatibilities With Ada 2005
31.i/3
{
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
31.j/3
{
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.
31.k/3
{
AI05-0122-1}
Correction: Fixed wording so the rules for
private with clauses also apply to "sprouted" generic child
units.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe