!standard 4.1.3(12) 10-01-15 AI05-0135-2/02 !standard 7.1(2) !standard 7.1(3) !standard 7.1(4) !standard 7.1(5/2) !standard 7.1(7) !standard 8.3(25) !standard 8.4(5/2) !standard 8.4(16) !standard 8.5.3(3) !standard 8.5.3(4) !standard 10.1.1(12.2/3) !standard 12.3(2/2) !standard 12.3(18) !class Amendment 10-01-07 !status work item 10-01-07 !status received 09-11-07 !priority Medium !difficulty Medium !subject "Integrated" nested packages !summary Add "package
is ..." to allow integrated packages and package renames.
!problem
One common idiom is to write a derived type to take a type declared within an
instantiation (or some other unit) and bring it out to the same level as the
instantiation (or into the new unit):
package T_Vecs is new Vectors(Element => T);
type T_Vec is new T_Vecs.Container with null record;
This is often done to bring the type and its operations to this location. But
often a new, distinct type is not what is wanted. Moreover, some related
entities (classwide operations, exceptions, generic operations) don't get
exported this way, so additional renaming or declarations are required to
completely make the instance transparent.
This use of a derived type is really something of a kludge.
What is really wanted here is a way to make all of the
declarations declared in the instantiation visible as if
they were declared at the same level as the instantiation
(as opposed to within it).
Consider a package which needs to export both a private type and an
instance of one of the container generics for that type.
Currently, this requires something like
package Pkg is
package Inner is
type T is private;
private
...
end Inner;
package I is new Some_Container_Generic (Inner.T);
end Pkg;
What is wanted here is a way to make all of the declarations visible
in Pkg.Inner (and perhaps Pkg.I; that's less clear) visible as if
they were declared immediately within Pkg.
This special case of the problem alone has been viewed as being
sufficiently important to merit considering major changes in the
language (see the 4 alternative versions of AI05-0074).
An unwanted nested package may also be introduced when a user wishes to
declare a non-primitive operation for a tagged type, as in
package Pkg is
type T is tagged ... ;
package Inner is
function Not_Primitive (X : T) return T;
end Inner;
end Pkg;
As in the previous example, what is wanted here is a way to make all of the
declarations visible in Pkg.Inner visible as if they were declared immediately
within Pkg.
!proposal
A package or package rename which is declared immediately within the
visible part of an enclosing package may be declared with angle brackets
enclosing the first occurence of the package identifier. This indicates
that the package is to be "integrated" into its parent; this means that
clients of the parent have the ability to name the constructs declared
within the integrated package as though they were declared within the
enclosing package.
One scenario where this construct may be useful is in declaring a package
that exports both a private type and a container generic instance for that
type without requiring that clients deal with nested packages.
This can be accomplished using this new construct as follows:
with Some_Container_Generic;
package Pkg is
package is" syntax instead of
"use package P".
- effective anonymity of an integrated package outside of
its immediate scope
- support for easily jettisoning integrated package renames
from the AI if it is decided that this is what we want
****************************************************************
From: Randy Brukardt
Sent: Monday, January 11, 2010 11:29 PM
You still don't have the legality rule to make an integrated renames of a
limited view of a package illegal. Since that is supposed to be equivalent to an
implicit use-clause, and we make use clauses of limited views illegal for good
reasons, we need a similar rule here or we'll reintroduce all of the problems
that we introduced 8.4(5/2) to fix. You call this an "odd corner case" in the
discussion, but there is nothing "odd" about it -- it has to be illegal and have
a rule to that effect.
I suspect that the circular rename you show also ought to be illegal, as it
could never have any useful effect (the names would always be hidden by the
direct names from the outer package).
Adding these rules will make the renames look "heavier" than it currently does,
which is an important data point in whether or not we should be allowing the
renames.
****************************************************************
From: Steve Baird
Sent: Tuesday, January 12, 2010 1:31 PM
> You still don't have the legality rule to make an integrated renames
> of a limited view of a package illegal. Since that is supposed to be
> equivalent to an implicit use-clause, and we make use clauses of
> limited views illegal for good reasons, we need a similar rule here or
> we'll reintroduce all of the problems that we introduced 8.4(5/2) to
> fix. You call this an "odd corner case" in the discussion, but there
> is nothing "odd" about it -- it has to be illegal and have a rule to that effect.
>
Good point. How about swapping the order of the "Legality Rules" and "Static
Semantics" sections of 8.5.3 (so that the definition of an integrated package
rename precedes the legality rules) and then appending the following legality
rule to 4.5.3(3.1/2):
The package_name of an integrated package_renaming_declaration
shall not denote a limited view of a package.
?
> I suspect that the circular rename you show also ought to be illegal,
> as it could never have any useful effect (the names would always be
> hidden by the direct names from the outer package).
>
Certainly we should disallow this if it introduces definitional or
implementation problems, but I don't see that it does. Disallowing something
because it is useless seems like overkill. Your next statement is a good
argument for allowing it:
> Adding these rules will make the renames look "heavier" than it currently
> does, which is an important data point in whether or not we should be
> allowing the renames.
****************************************************************
From: Randy Brukardt
Sent: Tuesday, January 12, 2010 4:07 PM
...
> Good point. How about swapping the order of the "Legality Rules" and
> "Static Semantics" sections of 8.5.3 (so that the definition of an
> integrated package rename precedes the legality rules) and then
> appending the following legality rule to 4.5.3(3.1/2):
> The package_name of an integrated package_renaming_declaration
> shall not denote a limited view of a package.
> ?
That seems OK, assuming that you meant 8.5.3(3.1/2) here and not the 4.5.3
(Binary adding operators??) that you wrote.
> > I suspect that the circular rename you show also ought to be
> > illegal, as it could never have any useful effect (the names would
> > always be hidden by the direct names from the outer package).
>
> Certainly we should disallow this if it introduces definitional or
> implementation problems, but I don't see that it does.
> Disallowing something because it is useless seems like overkill.
Maybe it is a difference in philosophy, but I think that things that are
*always* useless ought to be illegal. No one intentionally writes (well, other
than ACATS test writers!) anything useless, so if it occurs in a program, it
represents a mistake. And we want the compiler to detect mistakes.
I also worry that having circularly linked symboltable structures could be a
burden for compilers: you'd have to have some special mechanism to detect this
case otherwise you would go into an infinite regress doing lookups (as the
integrated package rename would appear inside of itself). That's probably not
that hard to do, but why spend any effort making some useless case work??
> Your next statement is a good argument for allowing it:
> > Adding these rules will make the renames look "heavier" than it currently
> > does, which is an important data point in whether or not we should be
> > allowing the renames.
Well, the implementation cost of the possibility will exist whether or not a
rule exists to prevent it, so in some sense you are being misleading by hiding
it. Not a big deal, but certainly this is a weak reason for avoiding a rule.
****************************************************************
From: Steve Baird
Sent: Tuesday, January 12, 2010 4:20 PM
>>> I suspect that the circular rename you show also ought to be
>>> illegal,
I don't feel strongly about it.
Would you like wording for this rule?
****************************************************************
From: Randy Brukardt
Sent: Wednesday, January 13, 2010 9:14 PM
Yes, please. It's easier to delete a rule that we decide isn't needed
than to create one out of air (and to remember to consider it).
****************************************************************
From: Steve Baird
Sent: Thursday, January 14, 2010 1:00 PM
We've already swapped the order of the "Legality Rules" and "Static Semantics"
sections of 8.5.3 so that the definition of an integrated package rename
precedes the legality rules.
We're already appending one legality rule after 8.5.3(3.1/2) [not after
4.5.3(3.1/2) - good catch, Randy] to disallow integrated renames of limited
views of packages.
So now we also append:
The package_name of an integrated package_renaming_declaration
shall not denote (directly or through renaming) a package
whose declarative region encloses the package_renaming_declaration.
****************************************************************
From: Randy Brukardt
Sent: Friday, January 15, 2010 9:15 PM
> Good point. How about swapping the order of the "Legality Rules" and
> "Static Semantics" sections of 8.5.3 (so that the definition of an
> integrated package rename precedes the legality rules) and then
> appending the following legality rule to 4.5.3(3.1/2):
> The package_name of an integrated package_renaming_declaration
> shall not denote a limited view of a package.
> ?
"Swapping the order" means deleting one or the other sections, because we have
to renumber the paragraphs. And that doesn't seem necessary in this case anyway:
just put the definition of *integrated package* into the legality rules (it's
not used elsewhere here, is it?) There's not a strong boundary between "Static
Semantics" and "Legality Rules" anyway (unlike "Name Resolution Rules" and
"Dynamic Semantics") So we end up with something like:
Add after 8.5.3(3.1/2):
If a package rename's package_identification consists of an
integrated_package_identification, then the package renaming
is said to be *integrated* (see 8.4). The package_name of an
integrated package_renaming_declaration shall not denote
a limited view of a package. The package_name of an integrated
package_renaming_declaration shall not denote (directly or
through renaming) a package whose declarative region encloses
the package_renaming_declaration.
I'd suggest the same in 7.1. Note that changing the paragraph numbers of
legality rules is nasty, because it not unusual for compiler error messages to
refer to them; it's much less likely that the paragraph numbers of other things
are referred to. So I'd prefer not to change the paragraph numbers of unmodified
legality rules.
I've modified the draft AI as suggested here. I'm sure someone will have an even
better idea...
****************************************************************
is
X : Integer := 0;
end Q;
-- use Q;
Y : Integer := X;
end P;
2) It is as though an implicit use_clause were added immediately
after any use_clause that applies to the enclosing package.
This allows:
package P is
Package
is
X : Integer := 0;
end Q;
end P;
with P;
use P;
-- use P.Q;
package R is
Y : Integer := X;
end R;
3) It is as though an implicit use_clause were in effect when
resolving the selector_name of a selected name whose prefix
denotes the enclosing package.
This allows:
package P is
Package
is
X : Integer := 0;
end Q;
end P;
with P;
package R is
Y : Integer := P.
-- use P.Q
X;
end R;
4) The integrated package cannot be named outside of its immediate
scope (and this is a name resolution rule).
Note that this construct is not defined in terms of implicit use_clauses.
This is just an alternative way to view it for expository purposes.
----
#2 above states
It is as though an implicit use_clause were added immediately
after any use_clause that applies to the enclosing package.
Note that this informal description applies recursively to the implicit
use clauses described in #1 - #3.
This allows:
use System;
package P is
package
is
X, Y : Integer := 0;
end Q;
X : Float;
end P;
with P;
package R is
Z : Float renames P.X; -- legal
end R:
----
If it is decided that integrated package renames are not wanted,
it would be easy to remove them from the proposal.
As Erhard has pointed out, there are good reasons to consider this
option. It is certainly possible to use integrated package renames
to write code that is very difficult to read; this was already true
of Ada83 use clauses, but integrated package renames seem to offer
substantially greater potential for confusion.
We needed rules to prevent some odd corner cases:
limited with Foo;
package P is
package
is
type T is ... ;
end Q;
end P;
limited with P;
package R is
type Ref is access P.T; -- illegal
end R;
and we have decided against that. It seems fine to say that
an integrated package, like an instance, simply does not have a limited
view.
----
When resolving the name P.Q, where P denotes a package,
declarations with names other than "Q" may be potentially use-visible
by selection at the point of the selector_name, but they will never be
use-visible by selection at that point. This is necessary because a
visible integrated package declared directly in P must be potentially
use-visible by selection regardless of the name of the package.
This allows:
package P is
package
is
X, Y : Integer;
end Q;
end P;
with P;
package R is
Z : Integer renames P.X;
end R;
both X and Y are potentially use-visible at the point of the selector_name,
but the word "such" implies that only declarations named "X" are to be
considered. Thus, the example is legal.
----
The angle brackets of an integrated package are not part of
the package's identifier.
In this example,
package P is
package
is
end Q;
end P;
, the name of the nested package is "Q", not "
".
This is why angle brackets are not repeated at the end of a package
spec, at the start or end of a package body, or for a package body stub.
--!corrigendum 8.4(3)
!ACATS test
Add ACATS tests for this new feature.
!appendix
From: Steve Baird
Sent: Thursday, January 7, 2010 6:35 PM
Here's a new version reflecting feedback from the St. Petersburg meeting and
subsequent discussions with Randy. [This is version /01 - Editor.]
This proposal includes:
- new angle-bracket "package