!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 type T is private; private ...; end Inner; package is new Some_Container_Generic (T); -- exports type Valise end Pkg; with Pkg; package Client is X : Pkg.T; Y : Pkg.Valise; use Pkg; Xx : T; Yy : Valise; end Client; !wording Modify 4.1.3(12) as follows The selector_name shall resolve to denote a declaration that occurs immediately within the declarative region of the package or enclosing construct (the declaration shall be visible at the place of the expanded name — see 8.3) {, or to denote a declaration that is use-visible by selection at the point of the selector_name (see 8.4)}. The expanded name denotes that declaration. Replace 7.1(3) to allow optional "< package_id >" syntax integrated_package_identification ::= < defining_identifier > package_identification := defining_program_unit_name | integrated_package_identification package_specification ::= package package_identification is {basic_declarative_item} [private {basic_declarative_item}] end [[parent_unit_name] . identifier ] Modify 7.1(4): If an identifier or parent_unit_name.identifier appears at the end of a package_specification, then this sequence of lexical elements shall repeat the defining_program_unit_name {or, in the case of an integrated_package_identification, the defining_identifier}. Add after 7.1(5/2): If a package's package_identification consists of an integrated_package_identification, then the package is said to be *integrated* (see 8.4). The declaration of an integrated package or package renaming (see 8.5.3) shall occur immediately within the visible part of an enclosing package or generic package. The package_identification of a generic_package_declaration shall not consist of an integrated_package_identification. The package_identification of a package_declaration of a library_unit_declaration (or of a package_renaming_declaration of a library_unit_renaming_declaration) shall not consist of an integrated_package_identification. [We could have moved the legality rules after the static semantic rules and put the definition of "integrated package" into the static semantic section. But that would necessarily change the paragraph number of an unchanged legality rule; since it is very likely that compiler error messages refer to the paragraph numbers of legality rules, we prefer to avoid that. - Editor.] Add after 8.3(25) (still in the Name Resolution Rules section): A name shall not resolve to denote an integrated package or package renaming outside of the immediate scope of that declaration. AARM note: This rule means that an integrated package or package renaming is, in effect, anonymous outside of its immediate scope. However, it remains visible. This peculiar distinction (i.e., visible but unnamable) is important because visibility of the declarations declared within an integrated package may depend on the visibility of the package (see 8.4). Because this is a name resolution rule, the following example is legal: declare package P1 is package X is end X; end P1; package P2 is package is end X; end P2; use P1; use P2; package Y renames X; -- unambiguously renames P1.X begin null; end; Add after 8.4(11) (i.e. append to the end of the Static Semantics section) At any point where an integrated package or package renaming is either potentially use-visible or directly visible, and where an entity declared immediately within the package or renamed package is visible, the entity is potentially use-visible. At the point of an expanded_name whose prefix denotes a package P (or a rename thereof) which immediately encloses the visible declaration of an integrated package or package renaming, any visible declaration declared immediately within the integrated package (or, in the case of an integrated package renaming, within the renamed package) is said to be "potentially use-visible by selection" at the point of the selector_name. In addition, if the declaration of an integrated package or package rename is "potentially use-visible by selection" at the point of a selector_name, then so are any visible declarations declared immediately within the package or renamed package. A declaration which is "potentially use-visible by selection" at the point of a selector_name is said to be "use-visible by selection" at that point unless - the defining name of the declaration is not the same as the selector_name; or - a visible homograph of the declaration is declared in P; or - more than one such declaration is potentially use-visible by selection at the point of the selector_name and at least one of them is not overloadable. Add after 8.4(16) (in the Examples section) Example of integrated packages: generic type T is private; package G is function Make return T; end G; with G; pragma Elaborate (G); package Pkg1 is package is type T is private; private type T is ... ; end Inner_Pkg_1; package is new G (T); end Pkg1; with Pkg1; package Pkg2 is X : Pkg1.T := Pkg1.Make; use Pkg1; Y : T := Make; end Pkg2; Modify 8.5.3(3) to allow optional "< package_id >" syntax: package_renaming_declaration ::= package_identification renames package_name; Add after 8.5.3(3.1/2) (Legality Rules): 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. Modify 10.1.1(12.2/3) (as modified by AI05-0129-1) to disallow limited views of integrated packages: For each nested package_declaration directly in the visible part {which does not declare an integrated package}, a declaration of the limited view of that package, with the same defining_program_unit_name. Modify 12.3(2/2) to allow optional "< package_id >" syntax: generic_instantiation ::= package package_identification is new generic_package_name [generic_actual_part]; Add after 12.3(18) (i.e. append to the end of the Static Semantics section): If a package instance's package_identification consists of an integrated_package_identification, then the package instance is said to be "integrated" (see 8.4). !discussion Just to summarize, adding angle brackets to a package or package rename declaration has four main effects: 1) It is as though an implicit use_clause were added immediately after the package declaration, so that visible declarations in the integrated package's spec become potentially use-visible within the enclosing package. This allows: package P is package 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 renames System; end P; with P; package Q is package renames P; end Q; with Q; use Q; package R is A : Address; end R; ---- The usual use_clause name resolution rules apply. This allows: 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 renames Foo; end P; We don't want this for the same reasons that we don't allow use clauses of Foo. Another odd case: package Outer is package Inner is package renames Outer; end Inner; end Outer; The declarations of Outer_Rename will always be hidden by those of Outer. So this is useless. It also has a (small) implementation burden, as a simple implementation would be at risk of going into an infinite loop: Outer_Rename would appear inside of itself. Thus the case needs to be detected and handled specially; given that it is useless, that effort might as well be spent toward making it illegal. Finally, integrated package renames are not needed to solve any of the problems that provided the original motivation for introducing integrated packages. The wording changes need to delete integrated package renames from this AI would be straightforward. These would include: - in the additions after 7.1(5/2), delete "or package renaming" and "(or of a package_renaming_declaration of a library_unit_renaming_declaration)". - in the additions after 8.3(25), delete "or package renaming" (twice). - in the additions after 8.4(11), delete "or package renaming" (three occurences), "or renamed package" (twice), and "(or, in the case of an integrated package renaming, within the renamed package)" . - eliminate the changes to 8.5.3(3) and the addition after 8.5.3(3.1/2). The only occurences of any form of the word "rename" (e.g., renaming, renamed) remaining in the proposed wording changes would then be the rename declaration in the example in the AARM note after 8.3(25) and the text "(or a rename thereof)" added after 8.4(11). ---- An integrated package may not be named outside of its immediate scope. To understand the motivation for this rule, consider the following example (supplied by Tuck): Text_IO, Sequential_IO, and Direct_IO each include renames of each exception declared in the package IO_Exceptions. It is a no-brainer to replace those renames with package renames Ada.IO_Exceptions; However, what should "Some_Name" be? Well, most natural would be: package renames Ada.IO_Exceptions; But now suppose you have: with Ada.IO_Exceptions; with Ada.Text_IO; use Ada; use Text_Io; procedure What_Fun is begin ...; exception when IO_Exceptions.Name_Error => -- we want this to compile ...; end What_Fun; Tuck observes that this rule should "apply to all integrated packages, not just integrated package renames, since the same problem comes up when you declare an integrated subpackage, or an integrated generic instance. You really don't want the names of the integrated packages cluttering up the namespace when you do a "use" of the enclosing package, but you do want them when trying to disambiguate where you would be using a complete expanded name." ---- We simply disallow limited views of integrated packages (10.1.1). They are like instantiations. Now that we don't allow the normal view of an integrated package to be named outside of its immediate scope, why would we want to allow naming of the limited view of an integrated package? If we were going to go down that road, it would be better to incorporate (integrate?) integration into limited views, allowing something like 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 Aaa : Integer; package is function F return Integer; end Inner; end P1; package is package is Bbb : Integer; function F return Float; end Inner; end P2; end P; with P; package Q is X : Float := P.F; -- legal end Q; At the point of the selector_name, 8 declarations are potentially use-visible by selection: P.P1, P.P1.Inner, P.P1.Inner.F, P.P2, P.P2.Inner, P.P2.Inner.F, P.P1.Aaa, and P.P2.Bbb Only 2 declarations are use-visible by selection: P.P1.Inner.F and P.P2.Inner.F This means that the word "such" in "more than one such declaration is potentially use-visible" is important. In this example, 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

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... ****************************************************************