10.1.2 Context Clauses - With Clauses
1
[A context_clause is used
to specify the library_items whose names are
needed within a compilation unit.]
Language Design Principles
1.a
{
one-pass context_clauses}
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}
{ripple effect} 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
context_clause ::= {
context_item}
3
context_item ::= with_clause |
use_clause
4/2
{
AI95-00217-06}
{
AI95-00262-01}
with_clause ::= limited_with_clause | nonlimited_with_clause with library_unit_name {, library_unit_name};
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
Discussion: {
AI95-00217-06}
A limited_with_clause
makes a limited view of a unit visible.
4.b/2
{
AI95-00262-01}
{private with_clause} 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
{scope (of a with_clause)}
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].
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
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.
6/2
{
AI95-00217-06}
{Term=[mentioned],Sec=[in a with_clause]}
{with_clause (mentioned
in)} A
library_item
(and the corresponding library unit) is
named {named
(in a with_clause)} {with_clause
(named in)} 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.
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
Note that this rule implies that “with
A.B.C;” is 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.
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
To be honest: 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 with_clause if the sibling
is a private library unit.
12/2
{
AI95-00262-01}
A name denoting a 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:
13/2
14/2
- a body, but
not within the subprogram_specification of
a library subprogram body;
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/2
Reason: These rules
make the 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
Proof: This is
redundant because only such implicit declarations are visible in a limited_with_clause.
See 10.1.6.
18/2
{
AI95-00217-06}
{
AI95-00412-01}
A limited_with_clause
shall not appear on a library_unit_body, subunit,
or library_unit_renaming_declaration.
18.a/2
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.
19/2
{
AI95-00217-06}
A limited_with_clause
that names a library package shall not appear:
20/2
- {AI95-00217-06}
in the context_clause
for the explicit declaration of the named library package;
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.
21/2
- {AI95-00217-06}
in the same context_clause
as, or within the scope of, a nonlimited_with_clause
that mentions the same library package; or
21.a/2
Reason: Such a
limited_with_clause could have no effect,
and would be confusing. If it is within the scope of a nonlimited_with_clause,
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/2
- {AI95-00217-06}
in the same context_clause
as, or within the scope of, a use_clause that
names an entity declared within the declarative region of the library
package.
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
{
AI-00433-01}
with Ada.Strings.Unbounded;
package Office.Locations is
type Location is new Ada.Strings.Unbounded.Unbounded_String;
end Office.Locations;
26/2
{
AI-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
{
AI-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
{
extensions to Ada 83}
The
syntax rule for
with_clause is modified to
allow expanded name notation.
31.b
A use_clause in a
context_clause may be for a package (or type)
nested in a library package.
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}
{incompatibilities with Ada 95} 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}
{extensions to Ada 95} 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/2
{
AI95-00262-01}
{extensions to Ada 95} 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 in the visible part of their
compilation_unit. They also allow using private
units in more locations than in Ada 95.