Version 1.13 of ai05s/ai05-0135-1.txt

Unformatted version of ai05s/ai05-0135-1.txt version 1.13
Other versions for file ai05s/ai05-0135-1.txt

!standard 4.1.3(12)          09-05-27 AI05-0135-1/05
!standard 7.1(2)
!standard 7.1.3(7)
!standard 8.4(5/2)
!standard 8.4(11)
!standard 8.4(18)
!standard 8.5.3(3)
!standard 8.5.3(4)
!standard 12.3(2/2)
!standard 12.3(18)
!class Amendment 09-01-31
!status No Action (9-0-0) 10-02-27
!status work item 09-01-31
!status received 08-12-17
!priority Medium
!difficulty Medium
!subject "Integrated" nested packages
!summary
Add "use package P 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 the optional reserved word "use". 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 use package Inner is type T is private; private ...; end Inner;
use package I is new Some_Container_Generic (T); -- exports type Valise end Pkg;
with Pkg; package Client is X : Pkg.T; Y : Pkg.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.
Modify 7.1(2) to allow optional "use" syntax:
package_declaration ::= {use} package_specification;
Add after 7.1.3(7) (i.e. append to the end of the Static Semantics section):
If the optional reserved word "use" is present in a package_declaration, then the package is said to be "integrated" (see 8.4).
Add after 8.4(5/2) (i.e. append to the end of the Legality Rules section)
The declaration of an integrated package or package renaming shall occur immediately within the visible part of an enclosing package or generic package. An integrated package or package renaming shall not be library unit (see 10.1.1). The limited view of an integrated package is not integrated.
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(18) (in the Examples section)
generic type T is private; package G is function Make return T; end G;
with G; pragma Elaborate (G); package Pkg1 is type T is null record; use package I 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 "use" syntax:
package_renaming_declaration
::= {use} package defining_identifier renames ...
Add after 8.5.3(4) (i.e. append to the end of the Static Semantics section):
If the optional reserved word "use" is present in a package_renaming_declaration, then the package renaming is said to be "integrated" (see 8.4).
Modify 12.3(2/2) to allow optional "use" syntax:
generic_instantiation ::= {use} package defining_program_unit_name is ...
Add after 12.3(18) (i.e. append to the end of the Static Semantics section):
If the optional reserved word "use" is present in a generic_instantiation, then the package instance is said to be "integrated" (see 8.4).
!discussion
Just to summarize, adding the reserved word "use" to a package or package rename declaration has three 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 use package Q 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 use package Q 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 use package Q is X : Integer := 0; end Q; end P;
with P; package R is Y : Integer := P. -- use P.Q X; end R;
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 withs described in #1 - #3.
This allows:
use System; package P is
use Package S_Ren renames System;
end P;
with P; package Q is use package P_Ren renames P; end Q;
with Q; use Q; package R is A : Address; end R;
----
The usual use_clause name resolution rules apply. In the case of the following example
package P is use package Q is X, Y : Integer := 0; end Q; X : Float; end P;
, this means that the use adding/deleting the reserved word "use" in the declaration of package Q can only make a difference to clients when resolving occurrences of the identifier "Y", not "X".
----
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.
Integrated package renames also make possible a number of odd corner cases:
limited with Foo; package P is use package Bar renames Foo; end P;
package Outer is package Inner is use package Outer_Rename renames Outer; end Inner; end Outer;
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. This would include:
- eliminating the wording changes in 8.5.3 - replacing "integrated package or package renaming" with
"integrated package" throughout
- eliminating references to integrated package renamings
in the change appended after 8.4(11)
----
Tuck suggests that the name of an integrated package (whether a rename or not) should not itself become "use"-visible when the enclosing package is "use"d.
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 a:
"use package <something> renames Ada.IO_Exceptions;"
in Text_IO, Sequential_IO, and Direct_IO.
However, what should the <something> be? Well, most natural would be:
"use package IO_Exceptions renames Ada.IO_Exceptions;"
but now suppose you have:
with Ada.IO_Exceptions; with Ada.Text_IO;
use Ada; procedure What_Fun is
use Text_IO;
-- oops, IO_Exceptions suddenly disappears
begin ... exception when IO_Exceptions.Name_Error => -- oops, this doesn't compile any more! end What_Fun;
If it is decided that this is what we want, then corresponding wording would probably be fairly straightforward (as long as we don't also require elegance, in which case the problem may be overconstrained).
As an aside, note that the above example would be allowed if "IO_Exceptions.Name_Error" were replaced with "Name_Error".
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."
If there is general agreement on this point, then the two alternatives described below should be discarded because they only address the case of an integrated package rename.
Another solution would be to allow anonymous integrated package renames, as in
use package <> renames Ada.Io_Exceptions;
This would be equivalent to
use package Some_Identifier_That_Occurs_Nowhere_Else_In_The_Program
renames Ada.Io_Exceptions;
Anonymous non-renames seem like a bad idea, but perhaps anonymous integrated renames would be ok?
A third approach to this problem would be to add a name resolution preference rule: if a package rename has the same simple name as the renamed entity (which might or might not itself be a rename), then prefer the renamed (and similarly through chains of renames as long as the simple name remains unchanged). This would not introduce the sort of Beaujolais effects that are typically associated with preference rules, but it does seem that treating a simple-name-preserving rename differently than a simple-name-nonpreserving rename might have some peculiar consequences (e.g., there might be some odd interactions with formal packages). This is probably a bad idea.
----
Consider the following example:
package Pkg is type T is ... ; use package Inner is function Is_Brobdingnagian (X : T) return Boolean; end Inner; end Pkg;
with Pkg; package Client is X : Pkg.T := ... ; Y : Boolean := Pkg.Is_Brobdingnagian (X); -- ok
type D is new Pkg.T; Dx : D := ... ; Dy : Boolean := Is_Brobdingnagian (Dx); -- illegal end Client;
Is this a problem? The function looks a lot like a primitive operation of the type, but the fact that it isn't really one does show through in some cases.
----
A limited view of a non-instance non-rename integrated package declaration could be defined to be integrated, thus allowing
package P is use package Q is type T is new Integer; end Q; end P;
limited with P; package R is type Ref is access P.T; -- currently illegal end R;
Would this be desirable? It won't work for instances or package renames.
----
Note that 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.
The following example is therefore legal:
package P is use package P1 is Aaa : Integer;
use package Inner is function F return Integer; end Inner; end P1;
use package P2 is use package Inner is Bbb : Integer;
function F return Float; end Inner; end P2; end P;
with P; package Q is X : Float := P.F; 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
but only 2 declarations are use-visible by selection:
P.P1.Inner.F and P.P2.Inner.F
Note that this means that the word "such" in "more than one such declaration is potentially use-visible" is important.
In this example,
package P is use package Q 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.
--!corrigendum 8.4(3)
!ACATS test
Add ACATS tests for this new feature.
!appendix

From: Steve Baird
Date: Wednesday, December 17, 2008  3:30 PM

Tucker Taft wrote in another thread:

 > One thing I think is important is being
 > able to take a type declared within an instantiation
 > and bring it out to the same level as the instantiation:
 >
 >     package T_Vecs is new private Vectors(Element => T, others => private);
 >     type T_Vec is new T_Vecs.Container with null record;
 >

This is one instance of a general problem that comes up in other contexts as
well. We are used to having to introduce a derived type, but this "idiom" is
really a bit of a hack if the only reason for doing this (as opposed to
declaring a subtype) is to avoid having to rename all of the primitive
operations. The derived type is, of course, necessary if we are completing a
private type (completing a private type with a subtype was discussed and
discarded a long time ago).

Within AdaCore there has been some discussion of a generalized renaming
construct of some sort. No consensus regarding syntax has been reached (and it
is not because so many good alternatives have been proposed that the choice is
difficult). For purposes of discussion, I'll go with what Bob Duff describes as
a "string of existing reserved words that more-or-less means the right thing":

    declare renames for <package name>.all;

This construct would be defined to be equivalent to a sequence of rename and
(constraintless) subtype declarations which rename every visible entity exported
from the given package (as seen from the point of the rename declarations). The
simple names of the renames would match those of the renamed entities.

This would allow

     with G;
     package Pkg1 is
       package I is new G ( ... ); -- exports a type I.T;
       declare renames for I.all;
     end Pkg1;

     with Pkg1;
     package Pkg2 is
       X : Pkg1.T;
     end Pkg2;

Typically this construct would occur in a package spec. Thus, the focus of this
construct is very different than that of a use clause. A use clause is
associated with importing whereas this construct is intended primarily for
(re)exporting. The effects of this construct within the scope in which it occurs
would be similar in some ways to that of a use clause, but only because that is
what happens to fall out - that is not an essential part of the design. If it
seemed desirable to emphasize this similarity, one could imagine syntax that
somehow uses the reserved word "use".

Syntax along the lines of
    package <> renames Some_Package;
might emphasize that this is somewhat like declaring a package rename and than
"inlining" it into the enclosing scope. Alternatively, it could be argued that
this syntax makes no sense at all.

There has also been some discussion of a finer-granularity
rename-with-all-the-trimmings construct for a type rather than a package
(somewhat like the relationship between "use" and "use type").
Something like
    subtype S is Some_Package.T with renames; would implicitly declare renames
not only of T, but also of all of its primitive operations which are visible
at this point.

This might be preferable to the package-rename construct because it doesn't
implicitly introduce non-overloadable declarations. In a case like

     type T is ... ;
     type Cursor is ... ;
     package I is new G (...); -- exports a type I.Cursor
     declare renames for I.all;

, the two Cursor declarations would collide. On the other hand, the definition
of "directly visible at this point" might be somewhat more complicated in the
case of a subtype as opposed to a package.

Obviously the type and package rename proposals are orthogonal. Any of the four
combinations (package only, type only, both, neither) could be defined.

Nits:
    1) A named number is "renamed" as
         Foo : constant := The_Package.Foo;

    2) Parameter default values for subprograms are preserved as is
       done for derived subprogram parameters in the case where
       no substitution is needed.

    3) A (desirable) consequence of defining this construct via an
       equivalence rule is that these implicitly declared renames
       are treated as though they were explicitly declared for
       purposes of overload resolution, overriding, etc.

Does this idea seem worth pursuing?

This construct is intended to address one of the deficiencies of the
deferred-instance-body-elaboration proposal relative to the
post-private-visible-part proposal by eliminating the need to declare a derived
type (which introduces freezing problems in some cases with the former
proposal).

I do not want to gratuitously load the language down with new features. In my
opinion, some version of this proposal coupled with the
deferred-instance-body-elaboration proposal would be preferable to the
post-private-visible-part proposal.

Is this issue therefore tied to the "instantiating a generic with a private
type" question, or is it an independent question?

****************************************************************

From: Tucker Taft
Date: Wednesday, December 17, 2008  4:13 PM

I think the subtype-oriented construct is simpler to deal with (because it
avoids the non-overloadables), and matches pretty closely what Dan Eilers and
others have been suggesting for years.

The "subtype S is P.T with renames;" actually seems pretty intuitive.
Presumably it should work in combination with others, so that there is no
complaint if multiple "renames" occur for the same operation, producing only one
actual rename:

    subtype S1 is P.T1 with renames;
    subtype S2 is P.T2 with renames;

This also addresses the complaints about "use type" which only makes operators
visible:

    subtype Enum is P.Enum with renames;

would make all of the enumeration literals for P.Enum directly visible.

I suspect you are introducing a wicked Beaujolais effect, by the way... ;-)  It
is unclear whether we would want to solve that.  Perhaps the solution is that if
by doing this you end up with a non-overloadable being hidden by an
overloadable, then both are hidden -- essentially the use-clause cancellation
rules.

****************************************************************

From: Steve Baird
Date: Wednesday, December 17, 2008  5:57 PM

...
> The "subtype S is P.T with renames;" actually seems pretty intuitive.
> Presumably it should work in combination with others, so that there is
> no complaint if multiple "renames" occur for the same operation,
> producing only one actual rename:
>
>    subtype S1 is P.T1 with renames;
>    subtype S2 is P.T2 with renames;
>

There go those simple "equivalence rule" semantics ...
Somehow I'm not surprised.

> This also addresses the complaints about "use type" which only makes
> operators visible:
>
>    subtype Enum is P.Enum with renames;
>
> would make all of the enumeration literals for P.Enum directly
> visible.
>
> I suspect you are introducing a wicked Beaujolais effect, by the
> way... ;-)

You are talking about a situation where adding or deleting the "with renames"
takes you from one legal interpretation to another? It's easy to see how the
resolution of a name could change within the declarative region where the
subtype declaration occurs. Outside of that region, I'm not so sure.

> It is unclear whether we would want to solve that.

Agreed. If you have an uplevel reference and then someone adds a hiding
declaration to an intermediate scope, nobody is surprised when the resolution of
the name changes. How is this any different than a situation like

    package Pkg is
       type T is null record;
      -- function F (X : T := (null record)) return Integer;
    end Pkg;

    package body Pkg is ... ;

    F : constant Integer := 17;
  begin
    declare
       type D is new Pkg.T;
       X : constant Integer := F;
    begin
       null;
    end;

where uncommenting the declaration of the function F changes the resolution of
the use of F in the declare block?

> Perhaps the solution is that if by doing this
> you end up with a non-overloadable being hidden by an overloadable,
> then both are hidden -- essentially the use-clause cancellation rules.

I'd like to see a plausible example where this rule would
prevent something bad from happening.

****************************************************************

From: Bob Duff
Date: Wednesday, December 17, 2008  6:35 PM

> Does this idea seem worth pursuing?

I've wanted something like this for years.

> I do not want to gratuitously load the language down with new features.
> In my opinion, some version of this proposal coupled with the
> deferred-instance-body-elaboration proposal would be preferable to the
> post-private-visible-part proposal.

I tend to agree.

> Is this issue therefore tied to the "instantiating a generic with a
> private type" question, or is it an independent question?

Independent.

****************************************************************

From: Bob Duff
Date: Wednesday, December 17, 2008  6:39 PM

> I think the subtype-oriented construct is simpler to deal with
> (because it avoids the non-overloadables), ...

In my opinion, the subtype-oriented one doesn't really solve the problem. I much
prefer the package-oriented version.  This issue is all about visibility, and
has nothing to do with types.

I want to reexport all the stuff in that package from this package. That
includes exceptions, generics, etc -- not just operations (primitive ones?) of
some type.

I think it can be done without Beaujolais effects.  If there's a name clash, all
decls are hidden (or don't get renamed, or some such).

****************************************************************

From: Bob Duff
Date: Wednesday, December 17, 2008  6:52 PM

> Agreed. If you have an uplevel reference and then someone adds a
> hiding declaration to an intermediate scope, nobody is surprised when
> the resolution of the name changes.

Well, I won't claim to be surprised, but I am annoyed. I consider this to be a
Beaujolais-like effect. In the case of subunits and child units, it's
particularly bad, because it crosses source-file boundaries.

My hobby language doesn't have that sort of implicit hiding, by the way.

Ichbiah came up with a quite clever way of avoiding Beaujolais effects for use
clauses.  I'm a little surprised he didn't apply this idea elsewhere.

>...How is
> this any different than a situation like
>
>     package Pkg is
>        type T is null record;
>       -- function F (X : T := (null record)) return Integer;
>     end Pkg;
>
>     package body Pkg is ... ;
>
>     F : constant Integer := 17;
>   begin
>     declare
>        type D is new Pkg.T;
>        X : constant Integer := F;
>     begin
>        null;
>     end;
>
> where uncommenting the declaration of the function F changes the
> resolution of the use of F in the declare block?

This case is even worse, because there's no F in sight to hide the outer one.
It seems very bad for an implicit decl to hide an explicit one.

This is exactly the same problem that Pascal's 'with' statement has been
criticized for.  When you say, "with SomeRecord do...", a component declared off
in the far boondocks hides a local variable.

I think for the above, if F is uncommented, _both_ F's should be hidden, making
the program illegal, thus avoiding the Beaujolais-like effect.

> Perhaps the solution is that if by doing this
> > you end up with a non-overloadable being hidden by an overloadable,
> > then both are hidden -- essentially the use-clause cancellation
> > rules.
> >
>
> I'd like to see a plausible example where this rule would prevent
> something bad from happening.

In my opinion, you have shown such an example above.  ;-) Just replace type D
with this new package-reexporting gizmo.

By the way, why would you ever want to use this new gizmo in a nested block or
procedure?  Isn't essentially the same as a use clause in that case?

****************************************************************

From: Randy Brukardt
Date: Wednesday, December 17, 2008  7:47 PM

> >...How is this any different than a situation like
> >
> >     package Pkg is
> >        type T is null record;
> >       -- function F (X : T := (null record)) return Integer;
> >     end Pkg;
> >
> >     package body Pkg is ... ;
> >
> >     F : constant Integer := 17;
> >   begin
> >     declare
> >        type D is new Pkg.T;
> >        X : constant Integer := F;
> >     begin
> >        null;
> >     end;
> >
> > where uncommenting the declaration of the function F changes the
> > resolution of the use of F in the declare block?
>
> This case is even worse, because there's no F in sight to hide the
> outer one.
> It seems very bad for an implicit decl to hide an explicit one.

I agree. This case is a serious bug waiting to happen; it's unfortunate that we
can't make this illegal. Surely we don't want any *more* cases like this.

(This gets to the reason that I dislike derived types as much as I do: you can't
figure out what is getting declared without a fancy tool. It's the reason I hate
use clauses multiplied by 5.)

> This is exactly the same problem that Pascal's 'with'
> statement has been criticized for.  When you say, "with SomeRecord
> do...", a component declared off in the far boondocks hides a local
> variable.
>
> I think for the above, if F is uncommented, _both_ F's should be
> hidden, making the program illegal, thus avoiding the Beaujolais-like
> effect.

Right, although I suspect that the compatibility cost might be too severe to do
it now. For instance, such a rule could very well make instantiating a container
in a nested scope illegal, because of some outer object named "Element" or
"First" or "Last". And I have a lot of objects with names like that...

> > > Perhaps the solution is that if by doing this you end up with a
> > > non-overloadable being hidden by an overloadable, then both are
> > > hidden -- essentially the use-clause cancellation rules.
> > >
> >
> > I'd like to see a plausible example where this rule would prevent
> > something bad from happening.
>
> In my opinion, you have shown such an example above.  ;-) Just replace
> type D with this new package-reexporting gizmo.
>
> By the way, why would you ever want to use this new gizmo in a nested
> block or procedure?  Isn't essentially the same as a use clause in
> that case?

That's interesting: that suggests that this "gizmo" really *is* a use clause --
it's just one that is visible to clients (unlike the normal variety). I wonder
if it would be better to think of it that way (we wouldn't need new visibility
rules then). Something like:
     declare use Pkg;
or (if we were willing to have a new keyword):
     export use Pkg;

and only allow that in a package (or generic package) specification (or just
have it have the same meaning as a usual use clause).

After all, didn't someone say this is all about visibility? Maybe we should say
so (renames are not necessarily about visibility; they're more about
shorthands).

****************************************************************

From: Steve Baird
Date: Wednesday, December 17, 2008  8:07 PM

> Right, although I suspect that the compatibility cost might be too
> severe to do it now. For instance, such a rule could very well make
> instantiating a container in a nested scope illegal, because of some
> outer object named "Element" or "First" or "Last". And I have a lot of
> objects with names like that...
>

I didn't follow this.
You have

    declare
      Last : Integer;
      package Ii is new Gg; -- exports a function Ii.Last

How does Ii become illegal?

****************************************************************

From: Randy Brukardt
Date: Wednesday, December 17, 2008  8:45 PM

> > Right, although I suspect that the compatibility cost might be too
> > severe to do it now. For instance, such a rule could very well make
> > instantiating a container in a nested scope illegal, because of some
> > outer object named "Element" or "First" or "Last". And I have a lot
> > of objects with names like that...
> >
>
> I didn't follow this.

I don't follow it either, rereading it. :-)

> You have
>
>     declare
>       Last : Integer;
>       package Ii is new Gg; -- exports a function Ii.Last
>
> How does Ii become illegal?

I was thinking of the derived from contents case, but I botched the explanation
badly.

     declare
       Last : Integer;
       package Ii is new Gg; -- exports a function Ii.Last
       type My_Vector is new Ii.Vector with null record;

This sort of thing is pretty common. (OTOH, I only do it in package
specifications.)

****************************************************************

From: Steve Baird
Date: Wednesday, December 17, 2008  7:52 PM

> I think for the above, if F is uncommented, _both_ F's should be
> hidden, making the program illegal, thus avoiding the Beaujolais-like effect.
>

It sounds like you don't buy the argument that because Ada already has
constructs with problems that are just as bad as the problems this new construct
would introduce, these new problems are ok.

Fair enough.

>> Perhaps the solution is that if by doing this
>>> you end up with a non-overloadable being hidden by an overloadable,
>>> then both are hidden -- essentially the use-clause cancellation
>>> rules.

It would be odd to introduce a rule like this only for the implicit declarations
associated with this new construct. On the other hand, there wouldn't be any
compatibility issues with such a rule, whereas changing the legality of my
original example would be an incompatible change. Are you arguing for the
incompatible change?

>> I'd like to see a plausible example where this rule would prevent
>> something bad from happening.
>
> In my opinion, you have shown such an example above.  ;-) Just replace
> type D with this new package-reexporting gizmo.

As you point out, any example where this gizmo occurs outside of a package spec
fails the plausibility test. I generally don't like to add language restrictions
that aren't associated with any definitional or implementation issues, so I
would prefer not to see a requirement that this gizmo must occur in a package
spec. Still, such a requirement wouldn't be completely unreasonable.

The example could be modified by adding a package and then we'd have the badness
we are looking for. How bad is this problem?

> By the way, why would you ever want to use this new gizmo in a nested
> block or procedure?  Isn't essentially the same as a use clause in
> that case?

This seems like an advantage of the "subtype S is P.T with renames;" proposal.
It is more generally useful because its semantics differ from those of "use
type" within the scope where the renaming occurs.

****************************************************************

From: Tucker Taft
Date: Wednesday, December 17, 2008  8:17 PM

> This seems like an advantage of the "subtype S is P.T with renames;"
> proposal. It is more generally useful because its semantics differ
> from those of "use type" within the scope where the renaming occurs.

That was my point.  If you really want the entire package to be visible, then a
"use" clause in the clients isn't terribly painful.  But if you just want the
operations of a single type to be visible, then we don't have any such thing,
except type derivation.  This provides a lighter weight version of type
derivation, which also happens to avoid some of the difficulties of type
derivation, such as the situation where the new derived type is incompatible
with the other things declared in the package, such as generics.  And also the
nasty case where there are two types declared in the package, and deriving from
both produces a useless muddle of operations.

****************************************************************

From: Steve Baird
Date: Wednesday, December 17, 2008  8:46 PM

Agreed,
I left out an "As Tuck observed,".

It is a little odd that these renaming things (package or type versions) differ
from use clauses within the scope where they are declared with respect to hiding
of declarations from enclosing scopes.

     package P is
        X : Float;
     end P;

     with P;
     procedure P_Client is
       X : Integer;
       type D is new Integer;
       Y : D;
     begin
       declare
         -- use P;
         -- declare renames for P.all;
       begin
         Y := D (X);

If the "use P;" is uncommented, then the operand of the type conversion is still
the Integer-valued X. If the "declare renames for P.all;" is uncommented
instead, then the operand is the Float-valued X.

Perhaps this is an error and the new construct(s) should be defined to be more
consistent with use clauses in this respect. The simplicity of the "it's just
like a bunch of renames" approach is appealing, but it looks like it has
problems.

****************************************************************

From: Randy Brukardt
Date: Wednesday, December 17, 2008  8:56 PM

> That was my point.  If you really want the entire package to be
> visible, then a "use" clause in the clients isn't terribly painful.

While I understand your point, this argument doesn't fly. Besides the fact that
some people don't like use clauses (one could make the argument that such people
wouldn't use this new construct anyway, for similar reasons), it breaks the
abstraction. If the package is supposed to be exporting a vector of some type,
telling users that "oh, by the way, you'll need to add a use clause for some
subpackage with a random name everywhere that you use our package". And the
reason is because 'it isn't terribly painful'! That could be a lot of extra use
clauses (or a lot of extra and unneeded visibility).

> But if you just want the operations of a single type to be visible,
> then we don't have any such thing, except type derivation.  This
> provides a lighter weight version of type derivation, which also
> happens to avoid some of the difficulties of type derivation, such as
> the situation where the new derived type is incompatible with the
> other things declared in the package, such as generics.

I have sympathy for this position as well. I think *both* of these things are
problems, and *both* deserve solution.

Bob's point is that if your packages are structured well, the two things are
pretty equivalent. But losing exceptions and generics and deferred constants is
annoying. (We had trouble with that in Claw, as iterator generics don't get
inherited by type extensions. They have to be redefined, which is tough to do.)

> And also the nasty case where there are two types declared in the
> package,

> and deriving from both produces a useless muddle of operations.

I don't think it is worth trying to solve this problem; it would be a nasty set
of visibility exceptions. Indeed, this is the best argument against the subtype
case, because I don't even want to think about this (I can't imagine a simple
way to do this in our compiler; all of these operations are declared in the
symbol table, and this would be a case where we're supposed to somehow allow
what is usually illegal. No thanks.)

****************************************************************

From: Tucker Taft
Date: Wednesday, December 17, 2008  9:11 PM

> While I understand your point, this argument doesn't fly. Besides the
> fact that some people don't like use clauses (one could make the
> argument that such people wouldn't use this new construct anyway, for
> similar reasons), it breaks the abstraction. If the package is
> supposed to be exporting a vector of some type, telling users that
> "oh, by the way, you'll need to add a use clause for some subpackage
> with a random name everywhere that you use our package". And the
> reason is because 'it isn't terribly painful'! That could be a lot of extra
> use clauses (or a lot of extra and unneeded visibility).

I'm afraid I am beginning to lose you.  You may have to give an example.  I
don't know what you mean by "extra and unneeded" visibility.

If you are allergic to use clauses, then you would reference the things that are
*not* "brought out" by using the original subpackage name as a prefix.  If you
like use clauses, then you would do a "use" for the subpackage, presuming you
had already done a "use" for the enclosing package, if you want direct
visibility on generics, etc.  If the construct "brought out" everything from the
subpackage in the first place, then a "use" clause on the enclosing package
would give you direct visibility on all of these things, but that would be
exactly the same set of things you would get by doing the two "use" clauses in
the first scenario.  So I don't see any "extra or unneeded" visibility. It is
exactly the same set of things that are directly visible in the two cases.

> ...
> And also the nasty case where there are two types declared in the
> package,
>
>> and deriving from both produces a useless muddle of operations.
>
> I don't think it is worth trying to solve this problem; it would be a
> nasty set of visibility exceptions. Indeed, this is the best argument
> against the subtype case, because I don't even want to think about
> this (I can't imagine a simple way to do this in our compiler; all of
> these operations are declared in the symbol table, and this would be a
> case where we're supposed to somehow allow what is usually illegal. No
> thanks.)

I don't follow your point here either.  Again perhaps an example would clarify.
I was merely suggesting that if you did two of these "subtype...with renames"
(is that something like "friends ... with benefits"? ;-), you wouldn't get any
complaints, because any shared operations would only be effectively renamed once
into the scope.  That is,

    subtype S1 is P.T1 with renames;
    subtype S2 is P.T2 with renames;

would not complain if there is an operation in P that is a primitive of both T1
and T2.  You wouldn't get two renames of it that somehow clobber each other.

****************************************************************

From: Randy Brukardt
Date: Wednesday, December 17, 2008 10:40 PM

...
> I'm afraid I am beginning to lose you.  You may have to give an
> example.  I don't know what you mean by "extra and unneeded"
> visibility.
>
> If you are allergic to use clauses, then you would reference the
> things that are *not* "brought out" by using the original subpackage
> name as a prefix.  If you like use clauses, then you would do a "use"
> for the subpackage, presuming you had already done a "use" for the
> enclosing package, if you want direct visibility on generics, etc.  If
> the construct "brought out" everything from the subpackage in the
> first place, then a "use" clause on the enclosing package would give
> you direct visibility on all of these things, but that would be
> exactly the same set of things you would get by doing the two "use"
> clauses in the first scenario.  So I don't see any "extra or unneeded"
> visibility.
> It is exactly the same set of things that are directly visible in the
> two cases.

You aren't making any sense at all. "everywhere" is a lot of places; if you
limit the scope of use clauses, you're going to have to put them in every place
that you would otherwise use a single use clause. (I typically use them, if I
use them at all, within blocks or subprograms.) Or (because you have a bunch of
them rather than just one) you just have to give up and put them at the top
level, but that is giving you "extra and unneeded" visibility.

Having to write two things in place of one logical thing might not be "terribly
painful" if you only have to do that in one place. If you have to do it in
dozens, it gets messy.

To see what I'm talking about, imagine that you have the following library
package that should be logically viewed as one item:

    package Pack is
        type T is ...;
        -- Operations on T.
        -- Now, define "file of T" as part of this package:
        package T_IO is new Ada.Sequential_IO (T);
        -- declare use T_IO; -- Or whatever syntax you want for a package visibility.
        -- subtype File_Type is T_IO.File_Type with renames; -- Or whatever syntax you want for subtype visibility.
    end Pack;

(I used Sequential_IO here because it has exceptions, but if you don't like
that, imagine any package that declares its own exceptions.) Note that T_IO is a
junk name that exists solely because Ada requires one here; we just want these
entities to be available. That same is potentially true of the subtype name --
we probably don't want to give it a different name.

    with Pack;
    procedure Something is
        A : Pack.T_IO.File_Type; -- Full name. Definitely breaks the abstraction of "file of T" being part of Pack.
        use Pack;
        B : T_IO.File_Type; -- Still breaks the abstraction.
        use Pack, Pack.T_IO;
        C : File_Type; -- The declaration is OK now, but the *use clause* breaks the abstraction.
    begin
        ...
    exception
        when Use_Error => ... -- Only works with the third use clause.
    end;

-- Now let's imagine that we use the package renaming scheme:
    with Pack;
    procedure Something is
        A : Pack.File_Type; -- Full name. Abstraction is fine.
        use Pack;
        B : File_Type; -- Abstraction is fine here, too.
    begin
        ...
    exception
        when Use_Error => ... -- Abstraction is fine here, three.
    end;

-- But with the subtype renaming scheme, it isn't quite as perfect:
    with Pack;
    procedure Something is
        A : Pack.File_Type; -- Full name of subtype. Abstraction is fine.
        use Pack;
        B : File_Type; -- Abstraction is fine here, too.
    begin
        ...
    exception
        when Use_Error => ... -- Nope, no good. Have to go back to T_IO
                              -- as in T_IO.Use_Error. Grrr.
    end;

...
> I don't follow your point here either.  Again perhaps an example would
> clarify.  I was merely suggesting that if you did two of these
> "subtype...with renames" (is that something like "friends...
> with benefits"? ;-), you wouldn't get any complaints, because any
> shared operations would only be effectively renamed once into the
> scope.  That is,
>
>     subtype S1 is P.T1 with renames;
>     subtype S2 is P.T2 with renames;
>
> would not complain if there is an operation in P that is a primitive
> of both T1 and T2.  You wouldn't get two renames of it that somehow
> clobber each other.

What the heck is a "shared operation" in language terms?? And how would you
implement such a thing? You can't just search for homographs, as they could come
up in other ways. What happens if someone writes:

     type T1 is new P.T1;
     subtype S2 is P.T2 with renames;

I would expect that you'd still get the mess of crossover operations; how would
the compiler tell that they're conflicting?

Do you really mean that the presence of some other declaration pages away
changes what's declared here? Is there any way to implement that without going
back through all of the previously generated symbols and trying to eliminate
extra ones? (We don't do that for anything else, so doing that would be weird
and expensive.) There are thousands of such symbols in OOP programs (such as
children of Claw), that's not going to be cheap. (And doing it the other way, by
name is no better, because there are often thousands of the various operator
symbols in a program.)

The package idea has no such problems; it's nothing but an inherited use clause
which means it's unlikely that there are many semantic issues with it.

Besides, I don't see much reason to encourage giant messy packages (even if I
write them from time-to-time). If you stick to one type to one package, the two
ideas are equivalent, but the package one is easier to describe and doesn't have
funny cases.

****************************************************************

From: Tucker Taft
Date: Wednesday, December 17, 2008 11:38 PM

> What the heck is a "shared operation" in language terms?? And how
> would you implement such a thing? You can't just search for
> homographs, as they could come up in other ways.

I didn't mean anything sophisticated here.  All I meant was that if you used the
"subtype ... with renames" twice from the same package in the same scope, it
wouldn't end up creating two renames for the same operation.  By a "shared"
operation I mean one that is a primitive on both types.


> ...
> What happens if someone writes:
>
>      type T1 is new P.T1;
>      subtype S2 is P.T2 with renames;
>
> I would expect that you'd still get the mess of crossover operations;
> how would the compiler tell that they're conflicting?

Yes, this would still produce a bit of a mess.  I wasn't suggesting to fix this.
Merely to say that if we provide this "subtype ... with renames," it shouldn't
cause conflicts with other subtype-with-renames from the same package which are
given in the same scope.

> Do you really mean that the presence of some other declaration pages
> away changes what's declared here? ...

No.

****************************************************************

From: Jean-Pierre Rosen
Date: Thursday, December 18, 2008  3:03 AM

> That's interesting: that suggests that this "gizmo" really *is* a use
> clause
> -- it's just one that is visible to clients (unlike the normal
> variety). I wonder if it would be better to think of it that way (we
> wouldn't need new visibility rules then). Something like:
>      declare use Pkg;
> or (if we were willing to have a new keyword):
>      export use Pkg;
>
> and only allow that in a package (or generic package) specification
> (or just have it have the same meaning as a usual use clause).
>

Alternatively, why not:
    pragma Inline (Pkg);

which would declare everything from the package directly in the enclosing
construct. Could be applied to an instantiation, too....

****************************************************************

From: Ed Schonberg
Date: Thursday, December 17, 2008  4:13 PM

This is confusing, it might mean that all subprograms within the package are to
be inlined. However, the point is that we would want to associate this with  an
instance, so why not label the instance accordingly? Randy does not want some
rule that declares that the new renaming construct should only appear in a
restricted context, and I tend to agree.  So let's use some new syntax on the
instantiation itself:

     package V is new open G (X);   -- your favorite new keyword here.

Indicating that all the entities in G are available in the enclosing context,
with the same name. It seems confusing to relate this to a use-clause:  the
use-clause affects  locally the visibility of entities declared elsewhere, while
here we want to create exportable views of those entities.

****************************************************************

From: Bob Duff
Date: Thursday, December 18, 2008  8:47 AM

> That was my point.  If you really want the entire package to be
> visible, then a "use" clause in the clients isn't terribly painful.

I think it is somewhat painful.

I agree with what Randy said on this point.

You haven't specified exactly what declarations this subtype-based idea brings
out.  By analogy with type derivation, I assume you mean primitive operations of
the type.  But surely you want class-wide ops as well.

You really want everything related to the type.  For example, you want
exceptions that are raised by primitive operations of the type.

My point is that "everything related to the type" is "everything in the package
visible part" -- presuming the package is properly designed.

****************************************************************

From: Bob Duff
Date: Wednesday, December 17, 2008  8:47 AM

> ...Are you arguing > for the incompatible change?

I am not.

I guess (after seeing Randy's point of view) that I am saying we don't want this
new feature to have the same problems of confusing hiding.  And thinking of it
as a "transitive use clause" is the right direction in that regard.

One possible syntax is "use Pack_Name.all;".

> As you point out, any example where this gizmo occurs outside of a
> package spec fails the plausibility test. I generally don't like to
> add language restrictions that aren't associated with any definitional
> or implementation issues, so I would prefer not to see a requirement
> that this gizmo must occur in a package spec.
> Still, such a requirement wouldn't be completely unreasonable.

I agree 100% with the above wishy-washy opinion.  ;-)

****************************************************************

From: Bob Duff
Date: Thursday, December 18, 2008  9:37 AM

>   So let's use some new syntax on the instantiation
> itself:
>
>      package V is new open G (X);   -- your favorite new keyword here.

I think the new gizmo Steve has proposed is not specific to instances.

As I see it, it would allow you have an abstraction that is viewed as a single
"thing" by clients, but is structured as many packages internally.  The idea is
that the client doesn't need to know about the many packages -- it just refers
to one package that collects it all together.

Some of those packages might be instances.  Some might be physically nested,
others children.  You might rearrange their structure from time to time, while
presenting an unchanging/compatible view to clients.

There might be some "interesting" (in a good way) interactions with
limited-with's, but I'm too busy to think about that right now...

****************************************************************

From: Bob Duff
Date: Thursday, December 18, 2008  9:38 AM

>      package V is new open G (X);   -- your favorite new keyword here.

If that keyword is reserved, Text_IO becomes illegal.  ;-)

****************************************************************

From: Tucker Taft
Date: Thursday, December 18, 2008  12:27 PM

I think we should make it a "use" clause, but with some kind of extra
indication.  I don't like ".all" as that automatically conjures up thoughts of
access values, which seems completely unrelated to the situation.  I could see:

    use P with renames;

and presumably:

    use type T with renames; -- makes operators transitively visible

If there is interest in having direct visibility on all primitive operations
(and perhaps class-wide as well, though that would take some more thought), then
probably we should just define a new kind of "use" clause, such as:

    use all type T [with renames];
       -- makes all primitives (and classwides) directly visible,
       -- transitively so if "with renames" included.

One interesting question is whether the primitives of a tagged type remain
dispatching after such a transitive use clause.  Clearly they do with a normal
use clause, but they don't with a normal rename.

Another possible syntax:

    use P for all;

That is the "use P" is effectively exported "for all" contexts where the direct
components of P are visible.

Or:

     use and declare P;

     use P and declare;

****************************************************************

From: Steve Baird
Date: Thursday, December 18, 2008 12:38 PM

>     package V is new open G (X);   -- your favorite new keyword here.

My gut feeling is that restricting this new mechanism to instances does not seem
like a good idea. Ditto for the general idea of associating this new visibility
property with the declaration of the entity itself (as opposed to introducing a
separate rename/use-clause-like construct). If pressed, I will try to justify
this position.

****************************************************************

From: Bob Duff
Date: Friday, December 19, 2008 10:12 AM

OK, I'd like to hear your justification.  I mean, for the part starting
"Ditto..." -- I definitely agree with the previous part, but I'm not sure about
the "Ditto...".

****************************************************************

From: Steve Baird
Date: Friday, December 19, 2008  4:42 PM

I was thinking about the case of a package spec consisting of nothing but
expressionless renames, constraintless subtypes, named numbers initialized to
other named numbers, etc.

This, for example, might reflect a (static) implementation choice, as in

    with Task_Safe_Foo;
    package Foo is
        procedure Bar renames Task_Safe_Foo.Bar;
        ...;
    end Foo;

or a restricted subset of a more general interface

     with Foo;
     package ReadOnly_Foo is
        subtype T is Foo.T;
        function Bar_Selector (X : T) return Integer renames
          Foo.Bar_Selector;
        -- no mention here of the corresponding procedure
        -- for assigning to the Bar attribute of a Foo.T
     end ReadOnly_Foo;

or whatever.

Suppose that we want to rename something like Ed's example,

    package V is new open G (X);   -- your favorite new keyword here.

Choices include:

    1) A rename loses this special visibility property (just as a rename
       of a primitive operation can't be called via a dispatching call).
       This will make problems either for whoever has to write/maintain
       the ReadOnly_Foo spec (because they would have to declare
       explicit renames corresponding to those that are implicitly
       declared in Foo) or for the clients (if these explicit renames
       are omitted from the ReadOnly_Foo spec).
       I would view this as a bad thing.

    2) A rename preserves this special visibility property.
       This means we have lost the ability to generate a "simple"
       rename in the case where that is all we want.
       This makes me nervous.
       This would also confuse the semantic equivalence between
       renames and actual-to-formal bindings for instantiations.
       Finally, consider a generic package that exports a rename
       of a formal instance;  I suppose the set of declarations that
       are exported depends on the actual parameter.
       This all seems a bit complicated.

    3) The rename itself gets new optional syntax so that the choice can
       go either way:

           package P renames Q [and all in P with out exception];

       This pretty well takes us back to where we started. If we have
       to support this case, then why do we need anything else?

As another point, consider the interaction with more nested packages.
With the rename/use-clause approach, the following is straightforward:

    package Pkg is
       package Inner is
          package I is new G;
       end Inner;

       use or rename or somehow reexport Inner.I;
    end Pkg;

It is not at all clear how to accomplish the same thing using the

      package I is new G and it glows in the dark;

approach of including the specification of the special visibility property in
the declaration of the package itself. The significance of this is, of course,
open to debate.

Does any of this seem convincing?

****************************************************************

From: Bob Duff
Date: Friday, December 19, 2008 10:10 AM

> I think we should make it a "use" clause, but with some kind of extra
> indication.  I don't like ".all"
> as that automatically conjures up thoughts of access values, which
> seems completely unrelated to the situation.

Shrug.  That doesn't bother me.

By the way, I'm a huge fan of compatibility, but I'm not allergic to new
reserved words -- that's just about the least harmful kind of incompatibility.

>...I could see:
>
>     use P with renames;
>
> and presumably:
>
>     use type T with renames; -- makes operators transitively visible

Yes, the use-type version seems useful, now that you mention it.

The above syntax seems tolerable, but "use all [type] X;"
seems nicer (not meaning what you say below).

> If there is interest in having direct visibility on all primitive
> operations (and perhaps class-wide as well, though that would take
> some more thought),

I don't see any use in that.  A typical package spec has 1 type, 15 subprograms,
1 exception, and 1 generic.  Why would I want to import all but 2 of those
things (or all but 4, if you leave out the class-wide ops)?

> One interesting question is whether the primitives of a tagged type
> remain dispatching after such a transitive use clause.

The correct answer is "yes".

>...  Clearly they do with a normal use clause,  but they don't with a
>normal rename.

> Another possible syntax:
>
>     use P for all;
>
> That is the "use P" is effectively exported "for all" contexts where
> the direct components of P are visible.
>
> Or:
>
>      use and declare P;
>
>      use P and declare;

All of the above tolerable.

****************************************************************

From: Ed Schonberg
Date: Friday, December 19, 2008  4:19 PM

> The above syntax seems tolerable, but "use all [type] X;"
> seems nicer (not meaning what you say below).

I also find "use all type P.T"  clear and concise. But I'm confused about the
semantics of the construct. A use clause makes the entities potentially visible
in the current context, nothing else. I thought that we wanted this construct to
also create a local entity that is visible outside of the current package.
That's certainly the effect of the  null derivation that we are trying to
replace.  I don't see how this new-fangled use-clause achieves this purpose.

****************************************************************

From: Randy Brukardt
Date: Friday, December 19, 2008  4:53 PM

The idea is that the use clause is effective in clients of the package as well,
such that:

    package P is
       ...
       package Vect is new Ada.Containers.Vectors (Some_Type);
       use all Vect;
    end P;

    with P;
    procedure One is
        A : P.Vector; -- The selection lets us see entities that are
                      -- use-all-visible in P, as well as real declarations.
    begin
        null;
    end One;

    with P; use P;
    procedure Two is
        A : Vector; -- The "use P" also makes things that are use-all-visible in P visible.
    begin
        null;
    end Two;

And other rules (in particular conflicting declarations) are handled as they are
for use clauses.

This is a pretty mimimal change to the language (how minimal to compilers I
don't know and haven't thought about). The only thing that is truly new here is
the selection followed by a use-all-visible item (the other way of course
already happens). I recall that we had to work hard to disallow transitive
use-clauses -- I think it is more natural for them to be transitive (depending
on how you implement them), so I don't expect that part to be hard.

****************************************************************

From: Ed Schonberg
Date: Friday, December 19, 2008  5:08 PM

OK, that's a very clear formulation, the "all" marks the use clause as
transitive.  I don't think the implementation is too complex, and the
description has the great virtue of conciseness.  I suppose that "use all" can
be a context item as well?

****************************************************************

From: Tucker Taft
Date: Friday, December 19, 2008  5:28 PM

> I also find "use all type P.T"  clear and concise. But I'm confused
> about the semantics of the construct. A use clause makes the entities
> potentially visible in the current context, nothing else. I thought
> that we wanted this construct to also create a local entity that is
> visible outside of the current package.  That's certainly the effect
> of the null derivation that we are trying to replace.  I don't see how
> this new-fangled use-clause achieves this purpose.

I think we have two separate threads going here, and I am afraid I am
responsible for the confusion.  I have seen a desire for some kind of "use"
clause that makes enumeration literals directly visible.  "use type" only makes
operators visible, so I was suggesting something like "use all type" to pick up
enumeration literals, and any other primitive subprograms.

A relatively independent thread is one about creating "transitive" use clauses,
or "reexporting" or whatever you want to call them.  They work sort of like a
bunch of renames, but I think we were concluding that they may need to have some
special rules to deal with Beaujolais effects.  One suggestion was "use P with
renames" for a transitive "use" package clause.  Once you establish this as
merely a special "tweak" on a "use" clause, then it makes sense to generalize it
to any kind of use clause, such as "use type P.T with renames;"

I have confused the situation by talking about both at the same time.  Sorry
about that.  Bob added a bit to the confusion by expressing a preference for the
syntax "use all type P.T" to mean what I suggested to be "use type P.T with
renames."  I don't understand why "all" communicates transitivity to Bob, so
I'll have to let him explain that.

So we have two relatively separate ideas:

    Add a new kind of "use" clause oriented toward
    getting direct visibility on enumeration literals
    (and other primitives).

    Define a syntax that can be used with any kind of
    "use" clause to make it transitive, so that the
    entities made directly visible at the point of
    the use clause are also visible in the extended
    scope of the enclosing package spec (a transitive
    use clause would presumably be no different from
    a non-transitive one when not in a package spec).

I don't know if that clarifies or confuses, perhaps both?  ... ;-)

****************************************************************

From: Tucker Taft
Date: Friday, December 19, 2008  5:30 PM

I don't find "use all" an intuitive syntax for transitivity.  I could understand
"all use" perhaps... ;-)

****************************************************************

From: Bob Duff
Date: Friday, December 19, 2008  5:31 PM

...
> And other rules (in particular conflicting declarations) are handled
> as they are for use clauses.

Yes, that matches my understanding of the idea.

But I think the wording will be tricky to get right.

So there needs to be an implicit decl of Vector in P, so P.Vector makes sense.
But the "conflicting declarations" issue is interesting.

I think you want to be able to say:

    package P is
       ...
       package Int_Vect is new Ada.Containers.Vectors (Integer);
       use all Int_Vect;
       subtype Int_Vector is Int_Vect.Vector;

       package Boolean_Vect is new Ada.Containers.Vectors (Boolean);
       use all Boolean_Vect;
       subtype Boolean_Vector is Boolean_Vect.Vector;

    end P;

and then P.Vector in clients should be illegal.
But package P itself should be OK.
And P.Append is just overloaded.

> This is a pretty mimimal change to the language (how minimal to
> compilers I don't know and haven't thought about). The only thing that
> is truly new here is the selection followed by a use-all-visible item
> (the other way of course already happens). I recall that we had to
> work hard to disallow transitive use-clauses -- I think it is more
> natural for them to be transitive (depending on how you implement
> them), so I don't expect that part to be hard.

And in message that came in while I was composing the above, Ed wrote:

>   I suppose that "use
> all" can be a context item as well?

Sure.  Why not?

Are there "interesting" interactions with "limited with"?

****************************************************************

From: Steve Baird
Date: Friday, December 19, 2008  9:32 PM

> Are there "interesting" interactions with "limited with"?

I would think these new constructs would be ignored in a limited view, just a
use clauses and renames are already ignored.

The case where the construct does not occur in a limited view but references a
limited view is more interesting. In this example

    package P is
       type T is  ... ;
       procedure Foo;
       package Inner is
         type TT is ... ;
         procedure Bax;
       end Inner;
       package I is new G;
    end P;

    limited with P;
    package Q is
      use all P; -- whatever the syntax is
    end Q;

the use clause only allows clients of Q to name Q.T and Q.Inner, right?
It doesn't matter whether the client can see a non-limited view of P.

****************************************************************

From: Randy Brukardt
Date: Friday, December 19, 2008  9:54 PM

Ummm, use_clauses are illegal for limited views (8.4(5/2)). I'd surely expect
that property to carry over, and thus the "use all" would be illegal here. So
that's not very interesting, either.

****************************************************************

From: Steve Baird
Date: Saturday, December 20, 2008  1:56 AM

Good point.

I guess I'm still thinking of these things as being like renames, not use
clauses. The use clause model is looking better and better.

****************************************************************

From: Brad Moore
Date: Sunday, December 21, 2008  1:06 PM

A very interesting thread. I like the overall intent. I see this being useful as
it is a problem I have run into often enough.

I am wondering it there are some other cases worth considering. In particular, I
am thinking it would be nice to be able to use this renaming concept to simplify
access to a protected object or a task object exported from a generic.

For example, suppose I have;

generic
   type F is private;
package G is

   protected P  is
      procedure Foo;
      function Bar returns Integer;
   private
      X : F;
   end Driver;
end G;


with G;
package Pkg1 is
   type T is null record;
   package I is new G (T);
   declare renames for I.P; -- Or whatever syntax works best end Pkg1;

with Pkg1;
package Pkg2 is
 Pkg1.Foo;   -- Really calling Pkg1.I.P.Foo
end Pkg2;

I didn't recall seeing the ability to do this in the thread so far.
Please accept my apology if this is already covered.

This is actually something I could have used to enhance the example I just
provided in my first email under the subject of private generic actuals.

****************************************************************

From: Brad Moore
Date: Friday, January 9, 2009  12:29 AM

This email actually applies to both AI05-0074 and this thread.

One of the problems that AI05-0074 is trying to solve is being able to
instantiate a generic in the visible part of a package using a private type.

The quoted example is:

"generic
   type Elem is private;
   with function Hash(El : Elem) return Integer; package Hashed_Sets is

   type Set is private;
   function Union(Left, Right : Set) return Set;
   ...

   package Signature is new Set_Signature(Elem, Set); private
   type Set is record ... end record;
end Hashed_Sets;

The problem is that we can't do the instantiation of Set_Signature where we
would want to do so, because the instantiation freezes the type "Set"
prematurely."

The AI states that the there is a workaround in Ada 2005, which is stated as;

"Ada 2005 provides solutions to these problems, but they are not ideal. For the
first example, making the instantiation a child unit solves the problem.
However, this is annoying, because accessing the instance requires an extra with
and instantiation (since children of generics must be generic):

generic
   type Elem is private;
   with function Hash (El : Elem) return Integer; package Hashed_Sets is
   type Set is private;
   function Union(Left, Right : Set) return Set;
   ...
private
   type Set is record ... end record;
end Hashed_Sets;

generic
package.Hashed_Sets.Signature is
   package The_Signature is new Set_Signature(Elem, Set); end Hashed_Sets.Signature;

A user of Hashed_Sets must with and instantiate Hashed_Sets.Signature in order
to access the instance. "

It seems to me that a better work around does exist, which involves the use of
nested packages.

generic
   type Elem is private;
   with function Hash (El : Elem) return Integer; package Hashed_Sets is
   package Sets is
      type Set is private;
      function Union(Left, Right : Set) return Set;
   private
      type Set is record ... end record;
   end Sets;

   type Set is new Sets.Set;

   package The_Signature is new Set_Signature(Elem, Set);

end Hashed_Sets;

No messy child packages to deal with. It all happens in one place. This is
somewhat like the end private alternative, in that a second visible part occurs
after the end of a private section, except that its available today in Ada 2005.

This should work if it is possible to derive a new type from the private type.
If you can't do the derivation, for example because the type is a protected
type, then you can declare a subtype instead, but then you run into the renaming
issue. eg

generic
   type Elem is private;
   with function Hash (El : Elem) return Integer; package Hashed_Sets is
   package Sets is
      type Set is private;
      function Union(Left, Right : Set) return Set;
   private
      type Set is record ... end record;
   end Sets;

   subtype Set is Sets.Set;
   function Union (Left, Right : Set) return Set renames Sets.Union;
   ...

   package The_Signature is new Set_Signature(Elem, Set);

end Hashed_Sets;

Now here is where this email thread kicks in. Hopefully all of the renames could
be replaced by one of these new super-duper rename clauses. This sort of feels
to me like a better work around to the problem than a solution, but others may
feel differently.

Comments?

****************************************************************

From: Brad Moore
Date: Tuesday, January 20, 2009 10:39 PM

> I think you want to be able to say:
>
>    package P is
>       ...
>       package Int_Vect is new Ada.Containers.Vectors (Integer);
>       use all Int_Vect;
>       subtype Int_Vector is Int_Vect.Vector;
>
>       package Boolean_Vect is new Ada.Containers.Vectors (Boolean);
>       use all Boolean_Vect;
>       subtype Boolean_Vector is Boolean_Vect.Vector;
>
>    end P;
>
> and then P.Vector in clients should be illegal.
> But package P itself should be OK.
> And P.Append is just overloaded.

First I have a question, then I will describe a problem that I can see, then I
have a suggestion for how it might be possible to address/improve the situation.

First the question:

Will it be possible to complete an incomplete type with a "use all"
statement?

e.g.

   -- A generic implementing a protected interface
   private with Protected_Queue;

   package Pkg is
      type T is private;
   private
      type Queue_Type;
      type T is
        record
          Queue : access Queue_Type;
        end record;
      package I is new Protected_Queue (T);
      use all I;
      --  Queue_Type is exported from package I, and completes the
      --  incomplete type declaration.

      -- Can't derive a new type here, i.e.,
      -- type Queue_Type is new I.Queue with null record;
      -- ERROR Cannot derive a new type from a protected type or
      -- interface.
   end Pkg;

Without this capability this is a problem without any workaround that I can see.
You cannot derive from a synchronized tagged type, for example. You cannot use a
subtype, because the incomplete type needs a completing type declaration, not a
subtype declaration. Yet this seems like something users could run into easily
enough. Suppose that type T has a task component that writes to the queue. Some
sort of concurrency support is needed. One option might be to allow synchronized
tagged types to be extended, but I don't feel that is the correct solution to
this particular problem.

We don't want to have to derive a new type here, we just want to be able to use
the one we created with the instantiation.

Assuming the use all can complete the incomplete type, this solves the problem
above, but now suppose there are two difference instantiations of the same
generic package declared and referenced in type T. The name collisions would be
a problem, and you wouldn't be able to have two incomplete type declarations
with the same name. Once again, subtype declarations wouldn't help you here. The
problem once again becomes unsolvable.

   -- A generic implementing a protected interface
   -- Similar to Ada.Containers.Hashed_Maps, but a protected type
   private with Protected_Hashed_Map;

   package Pkg is
      type T is private;
   private
      type Map;  -- Need an incomplete type for the Integer Map type
      type Map;  -- Need an incomplete type for the float Map type
                 -- Cant use the same name for both!
      type T is
        record
          Integer_Map : access Map_Type;
          Float_Map : access Map_Type;
        end record;
      package I is new Protected_Hashed_Map
         (Key => T, Element => Integer, ...);
      use all I;
      package J is new Protected_Hashed_Map
        (Key => T, Element => Float, ...);
      use all J;
      -- Broken
   end Pkg;

Both of these examples seems to want something different than what the "use all"
statement would provide here. The use all enabled us to get rid of having to
derive a new type. That's an improvement. But we still are being forced to
export the entire instantiated packages into the main package. Don't get me
wrong, the use all clause is a great idea, and I can see it having many uses,
but in this particular case it seems to be overkill for what we are trying to
achieve. All we really want here is to just be able to use the types that have
been instantiated.

Instead of trying to bring the water to the horse, what if we instead tried to
bring the horse to the water?

The idea here is to be able to declare what I would call a scoped incomplete
type, for lack of a better term. The incomplete type declaration could
optionally include package name qualifiers, which indicates that the declaration
will be completed by a type declaration in a matching named scope.

eg. Something like;

incomplete_type_declaration
  ::= TYPE {[defining_program_unit_name].}defining_identifier
           [discriminant_part] [IS TAGGED];

Then the above example could be fixed to look like;

 -- A Map abstraction implementing a protected interface
   with Protected_Hashed_Map;

   package Pkg is
      type T is private;
   private
      type I.Map;  -- Need an incomplete type for the Integer Map type
      type J.Map;  -- Need an incomplete type for the float Map type
                 -- Now we have a unique name for both incomplete types
      type T is
        record
          Integer_Map : access I.Map;
          Float_Map : access J.Map;
        end record;
      package I is new Protected_Hashed_Map
        (Key => T, Element => Integer, ...);
      package J is new Protected_Hashed_Map
        (Key => T, Element => Float, ...);
      -- I.MAP is completed by the I instantiation
      -- J.MAP is completed by the J instantiation
   end Pkg;

In this case, there would be no need to use a "use all" statement.

I don't see this as a replacement for use all, just as an extra tool that can be
used in addition to the "use all" tool. If such a tool existed I would have also
used it in the first example with the protected queue rather than use a use all
statement.

Does this idea seem like it would be worth pursuing?
Maybe if this feature existed, we wouldn't need to worry about having to have
the use all feature be able to complete an incomplete type declaration.

****************************************************************

From: Brad Moore
Date: Tuesday, January 20, 2009  11:02 PM

...
> First the question:
>
> Will it be possible to complete an incomplete type with a "use all"
> statement?

A use clause doesn't complete anything, and the model as I see it is that this
is just a super use clause. So I surely would not expect it to complete
anything.

...
>    -- A generic implementing a protected interface
>    private with Protected_Queue;
>
>    package Pkg is
>       type T is private;
>    private
>       type Queue_Type;
>       type T is
>         record
>           Queue : access Queue_Type;
>         end record;
>       package I is new Protected_Queue (T);
>       use all I;
>       --  Queue_Type is exported from package I, and completes the
>       --  incomplete type declaration.
>
>       -- Can't derive a new type here, i.e.,
>       -- type Queue_Type is new I.Queue with null record;
>       -- ERROR Cannot derive a new type from a protected type or
>       -- interface.
>    end Pkg;
>
> Without this capability this is a problem without any workaround that
> I can see. You cannot derive from a synchronized tagged type, for
> example.
> You cannot use a subtype, because the incomplete type needs a
> completing type declaration, not a subtype declaration.

Why not put the instantiation first (I'm presuming that we find a way to do
this, it is too fundamental to container usage to not solve it somehow - without
it, we can't have real iterators or container interfaces). Using my limited
instantiation idea, for instance:

    package Pkg is
       type T is private;
    private
       package I is limited new Protected_Queue (T);
       type T is
         record
           Queue : access I.Queue_Type;
         end record;
       package I is new Protected_Queue (T);
    end Pkg;

(I took the use clause out 'cause I don't like them much, but you could leave it
in, of course.)

Whatever solution we come up with ought to be able to do this.

...
> Does this idea seem like it would be worth pursuing?
> Maybe if this feature existed, we wouldn't need to worry about having
> to have the use all feature be able to complete an incomplete type
> declaration.

It doesn't seem necessary, assuming we solve the basic problem. And there are
all kinds of traps waiting if we try to expand the meaning of incomplete types
-- we had a lot of places where ugly cases couldn't happen because everything
has to occur in the same scope.

Your examples here do tell me one thing, however: the workarounds to fixing the
instance problem directly are never going to handle all of the cases. (The
problem is, that all of the instance problem solutions don't handle all of the
cases, either.) We really have to solve the AI05-0074-x problem somehow.

****************************************************************

From: Brad Moore
Date: Wednesday, January 21, 2009 10:34 AM

> Whatever solution we come up with ought to be able to do this.

I agree.

> Your examples here do tell me one thing, however: the workarounds to
> fixing the instance problem directly are never going to handle all of
> the cases. (The problem is, that all of the instance problem solutions
> don't handle all of the cases, either.) We really have to solve the
> AI05-0074-x problem somehow.

Note also, the second example using the hashed map generic is a bigger problem
than just for synchronized tagged types. It applies to any types. You would have
the same problem if you actually tried to do the same thing with the existing
Ada.Containers.Hashed_Maps container. This second case is really a problem that
appears to have existed all along since the dawn of Ada. Though the fact that it
is being reported now seems to suggest that there are not a lot of cases of
people running into this particular problem. However, the problem is exacerbated
with Ada 2005 since we now have containers such as the Hashed Map container,
making it more likely that people could run into the problem. It may be that in
the past, people just shrugged their shoulders, and redesigned their software to
work some other way.


The private instantiation proposal solves these problems, but it currently has
to straddle the visible/private boundary.

e.g.

   private with Ada.Containers.Hashed_Maps;
   package Pkg is
      type T is private;

      package I is new private Ada.Containers.Hashed_Maps
         (others => private);
      package J is new private Ada.Containers.Hashed_Maps
         (others => private);

   private
      type T is
        record
          Integer_Map : access I.Map;
          Float_Map : access J.Map;
        end record;
      package I is new Ada.Containers.Hashed_Maps
        (Key => T, Element => Integer, ...);
      package J is new Ada.Containers.Hashed_Maps
        (Key => T, Element => Float, ...);
   end Pkg;

I believe my proposal can be reworked fairly easily with only fairly minor
alterations so that it is not restricted to crossing the visible/private
boundary.

The syntax would be modified to change an occurrence of the word "private" to
"limited", as in.


limited_instantiation_declaration ::=
   PACKAGE defining_program_unit_name IS
         NEW LIMITED generic_package_name [deferred_generic_actual_part];

deferred_generic_actual_part ::=
   (deferred_generic_association {, deferred_generic_association})

deferred_generic_association ::=
   [generic_formal_parameter_selector_name =>] explicit_generic_actual_parameter  |  [generic_formal_parameter_selector_name =>] PRIVATE  | others => PRIVATE

The (OTHERS => PRIVATE) syntax would remain intact, but could only be used in
cases where the instantiation straddles the visible/private bounddary.
Otherwise, the instantiation and completion can also occur both in the visible
part, or both in the private part.

e.g.

   private with Ada.Containers.Hashed_Maps;
   package Pkg is
      type T is private;
   private
      package I is new limited Ada.Containers.Hashed_Maps
        (Key => T, Element => Integer, ...);
      package J is new limited Ada.Containers.Hashed_Maps
        (Key => T, Element => Float, ...);
      type T is
        record
          Integer_Map : access I.Map;
          Float_Map : access J.Map;
        end record;
      package I is new Ada.Containers.Hashed_Maps
        (Key => T, Element => Integer, ...);
      package J is new Ada.Containers.Hashed_Maps
        (Key => T, Element => Float, ...);
   end Pkg;

I'm also thinking that a shorthand form of the others=>private syntax might be
allowed where you simply don't have to supply any parameters. This shorthand
form could be used anywhere the others=>private could be used, but in addition
could be used in cases such as this, as in;

   private with Ada.Containers.Hashed_Maps;
   package Pkg is
      type T is private;
   private
      package I is new limited Ada.Containers.Hashed_Maps;
      package J is new limited Ada.Containers.Hashed_Maps;
      type T is
        record
          Integer_Map : access I.Map;
          Float_Map : access J.Map;
        end record;
      package I is new Ada.Containers.Hashed_Maps
        (Key => T, Element => Integer, ...);
      package J is new Ada.Containers.Hashed_Maps
        (Key => T, Element => Float, ...);
   end Pkg;

I am currently reworking my proposal to include some other ideas. Most notably,
I think the May_Be_Partial pragma should allow deriving a new type from a formal
that has the pragma applied within the visible part of the generic spec. (i.e.
Freezing does not occur for type derivations that have a May_Be_Partial pragma
applied.)

generic
  type T is private;
  pragma May_Be_Partial (T);
package Pkg is
  type Y is new T;
end Pkg;

My reasoning is that if the actual for T is a partial type, then it should be OK
to derive a new type from it, because you can derive from a partial type. If the
actual for T isn't a partial type, it should still be OK, because the
May_Be_Partial pragma ensures that there will be no objects or expressions of
that type in the package specification. I think freezing issues can be avoided
in either case. If the pragma is not applied to a formal type, then deriving
from that type will cause freezing to occur, as it does currently in the
standard.

****************************************************************

From: Steve Baird
Date: Wednesday, January 28, 2009  7:47 PM

>  I think the semantics is pretty clear (a reexporting use clause), but
> surely it would be good to write that up. (Shouldn't be too hard.)


One more corner case to clear up ...

Should we allow a child unit to conflict with a homograph that is made visible
in a package spec via this new construct?

Consider:

     package P is
       type R is record F : Integer; end record;
       X : R;
     end P;

     with P;
     package Q is
         use all P; -- syntax TBD
     end Q;

     package Q.X is -- legal?
         F : Integer;
     end Q.X;

     with Q;
     -- with Q.X;
     procedure Foo is
     begin
         Q.X.F := 17;
     end Foo;

If the declaration of the child unit is legal, then does the name Q.X.F mean two
different things depending on whether the with of Q.X is commented out or not?
This would be particularly confusing in the case where the name and the
context_clause are in different compilation units (e.g., the name Q.X.F is in a
subunit and the context clause of an enclosing unit is modified by
adding/deleting a with of Q.X).

However this ends up being handled, the case of a "sprouted" generic (RM
10.1.1(9/2)) should be treated consistently:

     package P is
       generic
       package G is
       end G;
     end P;

     with P;
     generic
     package Q is
         use all P; -- syntax TBD
     end Q;

     with Q;
     package I1 is new Q;

     generic
     package Q.G is -- legal?
     end Q.X;

     with I1;
     -- with Q.G;
     procedure Foo is
         package I2 is new I1.G;
     begin
         null;
     end Foo;


****************************************************************

From: Randy Brukardt
Date: Saturday, January 31, 2009  11:26 PM

> One more corner case to clear up ...

Isn't there always? :-)

> Should we allow a child unit to conflict with a homograph that is made
> visible in a package spec via this new construct?
>
> Consider:
>
>      package P is
>        type R is record F : Integer; end record;
>        X : R;
>      end P;
>
>      with P;
>      package Q is
>          use all P; -- syntax TBD
>      end Q;
>
>      package Q.X is -- legal?
>          F : Integer;
>      end Q.X;
>
>      with Q;
>      -- with Q.X;
>      procedure Foo is
>      begin
>          Q.X.F := 17;
>      end Foo;
>
> If the declaration of the child unit is legal, then does the name
> Q.X.F mean two different things depending on whether the with of Q.X
> is commented out or not?
> This would be particularly confusing in the case where the name and
> the context_clause are in different compilation units (e.g., the name
> Q.X.F is in a subunit and the context clause of an enclosing unit is
> modified by adding/deleting a with of Q.X).

Humm. My original thought was that this should work just like use clauses, warts
and all.

After all, you make this sound nasty and original; but it already happens for
use clauses and child units, and has since Ada 95 was introduced. We've
survived. :-)

For example:

     package P is
        type R is record F : Integer; end record;
        X : R;
     end P;

     package Q is
     end Q;

     package Q.X is
        F : Integer;
     end Q.X;

     with P; use P;
     -- with Q.X;
     procedure Q.Z is
     begin
        X.F := 17;
     end Q.Z;

If you add the with clause for Q.X, package X becomes directly visible and hides
the use visible object from P. But the programmer probably never even considered
the idea of calling the package plain X (they've always thought of it as Q.X),
so they're likely to be very confused. All of the same concerns apply about
doing it in another unit (it can also happen when an unrelated unit is converted
to a child).

This case does seem a bit worse, because it doesn't require a child unit to get
in trouble; and it happens in selected notation (as we didn't have use-visible
selected entities before).

I guess the question has to be "how nasty is the rule preventing children?".
That is, how hard is to word, and how hard is it to understand. If it's
relatively simple, perhaps we should simply ban the confusion (we did similar
things with "private with" even though the similar problems with children are
not prevented). But a big mess it isn't worth.

I worry that it might get very messy once you bring "sprouting" into the mix.
I'll trust you to work that out.

****************************************************************

From: Bob Duff
Date: Monday, February  2, 2009  2:15 PM

> After all, you make this sound nasty and original; but it already
> happens for use clauses and child units, and has since Ada 95 was introduced.

You can come up with similar surprises even in Ada 83.  And with subunits, you
can make the surprise cross source-file boundaries.  Ada 95 makes it a little
worse, with child units.

>...We've
> survived. :-)

I tend to agree with that attitude.  I don't like it, but as you point out,
we already have similar cases, and we can't fix the whole problem compatibly.

These are really Beaujolais-like effects.  Ichbiah came up with some excellent
visibility rules for use_clauses, and prevented Beaujolais effects (with a few
minor bugs, fixed in Ada 95).  But I wonder why he defined "Beaujolais effect"
purely in terms of use_clauses -- it should be defined more broadly, in terms
of all visibility-related things.

****************************************************************

From: Robert I. Eachus
Date: Monday, February  2, 2009  6:28 PM

>You can come up with similar surprises even in Ada 83.  And with
>subunits, you can make the surprise cross source-file boundaries.  Ada
>95 makes it a little worse, with child units.

Reminds me of a very old gotcha in Ada.  I think I originally wrote it as
part of a test of compiler overload resolution.  Dave Emery, Rich Hilliard and
I extracted one case and ran it against Ada compilers on display at a SIGAda
meeting.  The reaction of almost all who saw their compiler reject it was:
"That must be a compiler bug--I'll write it up."  We then assured the
astonished demonstrator that there was no bug their compiler was right to reject
the program:

procedure Hiding is
   procedure Foo (X: in Integer := 1) is begin null; end; begin
   declare
      procedure Foo is begin null; end;
   begin
      Foo;
   end;
end Hiding;

The outer Foo can be called by providing an explicit parameter, the inner Foo
never can.

Is this a bug in Ada that you can declare a subprogram that can't be called?
Not really, this case is pretty harmless. The case where both subroutines are
declared in the same scope is similar, and again, a surprise at compile time, but
relatively harmless. There are variations using use clauses and/or nested packages,
which were the original purpose of the test, but none of them result in a
subprogram being totally uncallable.

Why bring this up?  The old joke:

"Doctor, Doctor, it hurts when I do this!"
"Well, don't do it then."

There are lots of areas in Ada that may be of great interest to language lawyers,
but which Ada programmers have learned to avoid.  If not because they are bad
software engineering, because any rocks they run into in those shoals will make
them look foolish later.

****************************************************************

From: Steve Baird
Date: Friday, February  6, 2009  6:18 PM

The attached [Version /01 of the AI] is a first cut at wording for this AI.

The syntax for this construct is still very much up in the air; I just went with
"use all" here in order to have a specific proposal.

Note that the new super-powers for "use all type" are completely orthogonal to the
rest of the proposal. We are using this new reserved word to indicate two new
properties which are really unrelated (other than that they both increase visibility).

The only hard part of separating the two properties would be deciding on syntax.

****************************************************************

From: Tucker Taft
Date: Thursday, March 12, 2009  6:05 AM

I am growing pretty fond of the "use package P is ..."
proposal as a way to both define and then "open" a subpackage, particularly
since it solves the private-type instantiation problem so nicely. I had a few
additional thoughts about the proposal:

1) Don't make the subpackage name itself directly visible when the enclosing
package is "use"d -- just make the contents of the subpackage directly visible.

Rationale: I was somewhat enamored of allowing the subpackage name to be "<>"
but I understand Erhard's objection to it, and I also realize if there were more
than one, defining the body for the subpackage would be ambiguous. The main
reason for wanting "<>" was so that the subpackage name didn't pollute the
namespace.  Then I realized that if we simply didn't make the subpackage name
directly visible when the enclosing package were "use"d, it would solve the
problem.  This way you can call the subpackage "Inner" or any name you find
suggestive of its purpose, but if the enclosing package is "use"d, the
subpackage name won't end up creating any problems by "cancelling" other
use-visible entities that happen to have the same name.  It also seems to make
some intuitive sense.  The whole point of this use package P ... syntax is that
the contents of P are made directly visible when the enclosing package is
"use"d. It seems reasonable then to "subtract" the name of the subpackage itself
if you are getting all of its contents.

Example:


     package Abstraction is

      use
        package Inner is
          -- "Inner" is *not* made directly
          -- visible by a "use Abstraction"
            type ADT is private;
            ...
        private
            type ADT is ...
        end Inner;


        package Signature is
          new Container_Signature(ADT, ...);
            -- Instantiate signature

      use
        package ADT_Vectors is Vectors(ADT, ...);
           -- Create vector of ADT

        subtype ADT_Vector is ADT_Vectors.Vector;
           -- Define longer name
    end Abstraction;


2) Allow "use" in front of a package rename, with the effect of "open"ing the
named package.

Rationale:  This seems consistent, since there are three ways to create
something that looks like a subpackage -- define one, instantiate one, or rename
one.  Furthermore, it gives us the "transitive" use, but with a syntax that is
clearly distinct from the current "use" clause syntax. And finally, by providing
a name to the renamed package, we avoid running into the same problem that
Erhard identified with package instantiations, so there is always a way to
handle name collisions that result from transitive "use."

Example:

     with Useful_Stuff, More_Useful_Stuff;
     package Combination is

       use package Part1 renames Useful_Stuff;

       use package Part2 renames More_Useful_Stuff;

     end Combination;

3) Consider using syntax similar to aspect specification
    to rename components as part of doing a "use package":

Rationale: If you are going to "open" a package into the enclosing scope, you
may periodically want to rename some of its components to avoid collisions.

Example:

    use package ADT_Vectors is new Vectors(ADT, ...)
      with
        ADT_Vector renames Vector,
        ADT_Cursor renames Cursor;

This would instantiate Vectors and then "open" up the instance, but with the two
types renamed to better reflect their meaning in the enclosing scope.  This
would only be allowed on package instantiations and renames, not on newly
defined nested packages.

****************************************************************

From: Bob Duff
Date: Thursday, March 12, 2009  8:47 AM

> Rationale: I was somewhat enamored of allowing the subpackage name to
> be "<>" but I understand Erhard's objection

This is the third time in as many days that I've seen proposals to add new
meanings to the <> symbol!

****************************************************************

From: Tucker Taft
Date: Thursday, March 12, 2009  1:08 PM

But in my case it was just a strawman, and I am not recommending it.  But it is
a very nice symbol, after all ... ;-)

****************************************************************

From: Steve Baird
Date: Thursday, March 12, 2009  3:24 PM

> I am growing pretty fond of the "use package P is ..."
> proposal as a way to both define and then "open" a subpackage,
> particularly since it solves the private-type instantiation problem so
> nicely.

I like it too.
I think it is a clean solution to an important problem.

> I had a few additional thoughts about the proposal:
>
> 1) Don't make the subpackage name itself directly visible when the
> enclosing package is "use"d -- just make the contents of the
> subpackage directly visible.
>

I don't like this idea, but I don't feel strongly about it. I don't see any
definitional problems with it - it just seems strikes me as unnecessarily
irregular. I would be interested in knowing whether others feel that I am
underestimating the impact of the name space pollution problem,


> Rationale: I was somewhat enamored of allowing the subpackage name to
> be "<>" but I understand Erhard's objection to it, and I also realize
> if there were more than one, defining the body for the subpackage
> would be ambiguous.
> The main reason for wanting "<>" was so that the subpackage name
> didn't pollute the namespace.  Then I realized that if we simply
> didn't make the subpackage name directly visible when the enclosing
> package were "use"d, it would solve the problem.  This way you can
> call the subpackage "Inner" or any name you find suggestive of its
> purpose, but if the enclosing package is "use"d, the subpackage name
> won't end up creating any problems by "cancelling" other use-visible
> entities that happen to have the same name.  It also seems to make
> some intuitive sense.  The whole point of this use package P ...
> syntax is that the contents of P are made directly visible when the
> enclosing package is "use"d.
> It seems reasonable then to "subtract" the name of the subpackage
> itself if you are getting all of its contents.
>
> Example:
>
>
>     package Abstraction is
>
>      use
>        package Inner is
>          -- "Inner" is *not* made directly
>          -- visible by a "use Abstraction"
>            type ADT is private;
>            ...
>        private
>            type ADT is ...
>        end Inner;
>
>
>        package Signature is
>          new Container_Signature(ADT, ...);
>            -- Instantiate signature
>
>      use
>        package ADT_Vectors is Vectors(ADT, ...);
>           -- Create vector of ADT
>
>        subtype ADT_Vector is ADT_Vectors.Vector;
>           -- Define longer name
>    end Abstraction;
>
>
> 2) Allow "use" in front of a package rename, with the effect of
> "open"ing the named package.
>
> Rationale:  This seems consistent, since there are three ways to
> create something that looks like a subpackage -- define one,
> instantiate one, or rename one.  Furthermore, it gives us the
> "transitive" use, but with a syntax that is clearly distinct from the
> current "use" clause syntax.
> And finally, by providing a name to the renamed package, we avoid
> running into the same problem that Erhard identified with package
> instantiations, so there is always a way to handle name collisions
> that result from transitive "use."
>

Is it clear that we need this generality?

This would require adding wording to cope with various pathological cases that
this would make possible (e.g. a rename of a limited view of a package, a rename
of a package whose spec encloses the rename).

All this is doable, but I think that it would introduce some definitional
complexity.

This feature also has a very high potential for misuse.
Use clauses can already be used to write code which is difficult to read; this
construct would make matters even worse in this respect.

Incidentally, should the following be legal?

    package Outer is
        use package Inner is
            type T is new Integer;
        end Inner;
    end Outer;

    limited with Outer;
    package Snort is
        type T_Ref is access Outer.T;
    end Snort;

In other words, is the distinction between a "use" and a "non-use" package
retained in the limited view of an enclosing package?


> Example:
>
>     with Useful_Stuff, More_Useful_Stuff;
>     package Combination is
>
>       use package Part1 renames Useful_Stuff;
>
>       use package Part2 renames More_Useful_Stuff;
>
>     end Combination;
>
> 3) Consider using syntax similar to aspect specification
>    to rename components as part of doing a "use package":
>
> Rationale: If you are going to "open" a package into the enclosing
> scope, you may periodically want to rename some of its components to
> avoid collisions.
>
> Example:
>
>    use package ADT_Vectors is new Vectors(ADT, ...)
>      with
>        ADT_Vector renames Vector,
>        ADT_Cursor renames Cursor;
>
> This would instantiate Vectors and then "open" up the instance, but
> with the two types renamed to better reflect their meaning in the
> enclosing scope.  This would only be allowed on package instantiations
> and renames, not on newly defined nested packages.

This seems like a fairly big change, because it is no longer so simple to define
this construct just in terms of use-visibility.

As I imagine it, adding the word "use" to a package declaration would have only
three effects:

    1) Visible declarations within the inner package spec become
       use-visible within the enclosing package. Informally,
       this can be thought of as meaning that an implicit use
       clause is inserted immediately after the package declaration,
       as in

           package P is
               use package Q is
                  X : constant Integer := ... ;
               end Q;

               use Q; -- implicitly inserted

               Y : Integer := X;
           end P;

    2) A use clause which applies to the enclosing package
       also applies to the inner package. Informally,
       this can be thought of as meaning that an implicit
       use clause is inserted immediately after any
       use clause which applies to the enclosing package,
       as in

           with P;
           package Gronk is
               use P;
               use P.Q; -- implicitly inserted

               Z : Integer := X;
           end Gronk;

     3) At the point of resolving an expanded name whose
        prefix denotes the enclosing package, any visible
        declarations of the inner package become
        "use visible by selection", which is
        a term defined in the current (now obsolete)
        version of AI05-0135. Informally (and I mean
        *really* informally), this can be thought of
        as meaning that an implicit use clause is
        inserted at the point of the dot in the selected
        name, as in

            with P;
            package Snuffle is
                W : Integer := P .
                     use P.Q; -- implicitly inserted
                     X;
            end Snuffle;

The change you are proposing does not seem to fit this model well. I'm not
trying to let the implementation dictate the specification here. I'm saying that
we have a fairly clean model which
    - should not require a lot of complicated RM wording
    - should be possible for users to understand and I'm reluctant to give that
      up.

This approach I've outlined depends on the fact that we are only making existing
declarations use-visible - we are not introducing renames or any other new
implicitly-declared declarations.

Rename-based (as opposed to use-visibility-based) approaches to this problem
were discussed a while back (that was the approach that I initially had in mind)
and have been abandoned for good reasons having to do with homograph collisions.

If we really wanted to include this feature, I'd think about a "like a rename,
but different" approach where the identifier "Vector" in your example becomes
use-visible by the name of "Adt_Vector". I'm not advocating this approach - I'd
rather not include the feature - but this seems like the way to define it if we
decide that we really want the feature. I don't think mixing implicit rename
declarations into a definition that is based on use-visibility is the way to go.

****************************************************************

From: Gary Dismukes
Date: Thursday, March 12, 2009  3:55 PM

> I like it too.
> I think it is a clean solution to an important problem.

I haven't completely decided whether I like it yet, but I certainly like it
better than other alternatives proposed for solving the "private instantiation"
problem, so from that point of view it's appealing.

> > I had a few additional thoughts about the proposal:
> >
> > 1) Don't make the subpackage name itself directly visible when the
> > enclosing package is "use"d -- just make the contents of the
> > subpackage directly visible.
> >
>
> I don't like this idea, but I don't feel strongly about it. I don't
> see any definitional problems with it - it just seems strikes me as
> unnecessarily irregular.
> I would be interested in knowing whether others feel that I am
> underestimating the impact of the name space pollution problem,

I also find that odd.  For one thing, it seems weird to have a name that can't
be referenced.  It seems like it should still be possible to name the entities
in the package by selection from the package, though I realize that's
unnecessary once they're "reexported". As you say, it feels irregular.

****************************************************************

From: Randy Brukardt
Date: Thursday, March 12, 2009  4:07 PM

> I haven't completely decided whether I like it yet, but I certainly
> like it better than other alternatives proposed for solving the
> "private instantiation" problem, so from that point of view it's
> appealing.

So far, I think it's a good idea. I've never liked using derivation to make
things visible (too tricky for my taste, and you get types that you don't need
or want). But since I don't like "use" clauses much, I'll reserve final judgment
until we get further along with the definition.

...
> I also find that odd.  For one thing, it seems weird to have a name
> that can't be referenced.  It seems like it should still be possible
> to name the entities in the package by selection from the package,
> though I realize that's unnecessary once they're "reexported".
> As you say, it feels irregular.

I agree with Gary and Steve. It doesn't seem necessary to add complexity to this
proposal. If you really are worried about name pollution and you are pretty sure
that you'll never want to use the package name, just name it something like
"package Dont_Ever_Use_This_Package_Name_In_Your_Code" or "package
This_Package_Has_No_Name_and_Dont_Ever_Use_It" and you should not have to worry
about conflicts. (And yes, I have done that in a few cases in my code.)

****************************************************************

From: Tucker Taft
Date: Thursday, March 12, 2009  4:02 PM

...
> I don't like this idea, but I don't feel strongly about it. I don't
> see any definitional problems with it - it just seems strikes me as
> unnecessarily irregular.
> I would be interested in knowing whether others feel that I am
> underestimating the impact of the name space pollution problem,

I think the namespace pollution issue is a big one.  If we don't do this, I
foresee people using all kinds of weird names to try to be sure they don't have
any collisions, and that seems like a waste of time and something that will make
such packages look bogus.  Hiding the name of the subpackage itself from use
visibility, for a subpackage that is "used at birth" (or "always open") feels
like a much cleaner approach, and allows the user to pick a name for the
subpackage that is descriptive rather than intentionally obscure.  I don't see
it as "irregular" but rather I see it as a fairly natural consequence of having
its contents always use-visible.

>> 2) Allow "use" in front of a package rename, with the effect of
>> "open"ing the named package.
>> ...
>
> Is it clear that we need this generality?
>
> This would require adding wording to cope with various pathological
> cases that this would make possible (e.g. a rename of a limited view
> of a package, a rename of a package whose spec encloses the rename).

Why are these pathological?  Can you explain what makes them worse than a rename
followed by a normal "use" of the package?  (My mind isn't as fiendish as yours,
I suspect.)

> All this is doable, but I think that it would introduce some
> definitional complexity.

I would agree if this adds complexity it isn't worth it.  But if not, it just
feels unnatural if you see the three ways of defining a subpackage, but we allow
"use" in front of two of them but not the third, even though a "normal" use
clause is legal with any of the three.

> This feature also has a very high potential for misuse.
> Use clauses can already be used to write code which is difficult to
> read; this construct would make matters even worse in this respect.

I'm not sure I see the issue here, so perhaps an example might help.

>
> Incidentally, should the following be legal?
>
>    package Outer is
>        use package Inner is
>            type T is new Integer;
>        end Inner;
>    end Outer;
>
>    limited with Outer;
>    package Snort is
>        type T_Ref is access Outer.T;
>    end Snort;
>
> In other words, is the distinction between a "use" and a "non-use"
> package retained in the limited view of an enclosing package?

It would be weird if when you changed from non-limited to limited or vice versa,
you had to insert/remove the name of the subpackage.  I don't see a big
implementation burden here, and thus far limited views have been subsets of the
full view.  It would be annoying if they were not just subsets, but really
markedly different from the full view.

...
>> 3) Consider using syntax similar to aspect specification
>>    to rename components as part of doing a "use package":
...
> This seems like a fairly big change, because it is no longer so simple
> to define this construct just in terms of use-visibility.

That's why I said "consider using" ;-)

The rationale for this is that after instantiating a container, users are
probably going to have to have several "subtype" declarations, as illustrated
above. It just seems preferable to do it all in one fell swoop. I think the
renames could be implicitly inserted *inside* the subpackage, just prior to any
private part.  That would mean that you would still rely on use-visibility
rather than "rename" visibility" for any effect outside the package.

****************************************************************

From: Bob Duff
Date: Thursday, March 12, 2009  3:39 PM

> I like it too.

Me, three.

> I think it is a clean solution to an important problem.
>
> > I had a few additional thoughts about the proposal:
> >
> > 1) Don't make the subpackage name itself directly visible when the
> > enclosing package is "use"d -- just make the contents of the
> > subpackage directly visible.
> >
>
> I don't like this idea, but I don't feel strongly about it.

Same here.

>...I don't see any definitional problems with it -  it just seems
>strikes me as unnecessarily irregular.
> I would be interested in knowing whether others feel that I  am
>underestimating the impact of the name space pollution problem,
...
> > 2) Allow "use" in front of a package rename, with the effect of
> > "open"ing the named package.
...
> Is it clear that we need this generality?

I won't say we "need" it, but it seems quite useful.

> > 3) Consider using syntax similar to aspect specification
> >    to rename components as part of doing a "use package":
...
> This seems like a fairly big change, because it is no longer so simple
> to define this construct just in terms of use-visibility.

Furthermore, it doesn't buy you much.  What does this give you beyond:

    use package ADT_Vectors is new Vectors(ADT, ...)
    subtype ADT_Vector is ADT_Vectors.Vector,
    subtype ADT_Cursor is ADT_Vectors.Cursor;

?

****************************************************************

From: Ed Schonberg
Date: Thursday, March 12, 2009  4:25 PM

> I think the namespace pollution issue is a big one.  If we don't do
> this, I foresee people using all kinds of weird names to try to be
> sure they don't have any collisions, and that seems like a waste of
> time and something that will make such packages look bogus.  Hiding
> the name of the subpackage itself from use visibility, for a
> subpackage that is "used at birth"
> (or "always open") feels like a much cleaner approach, and allows the
> user to pick a name for the subpackage that is descriptive rather than
> intentionally obscure.  I don't see it as "irregular"
> but rather I see it as a fairly natural consequence of having its
> contents always use-visible.

The potential for name pollution comes from the opening of the package, not from
the name of the package on its own. If the name is in the source it should be
usable, and it should still be possible to use qualified names to retrieve its
contents (even if this is redundant). I agree with the other critics of this
idea: a name in the source must be usable. Otherwise <> would be the right name,
but this has been discarded for other reasons.

****************************************************************

From: Randy Brukardt
Date: Thursday, March 12, 2009  4:55 PM

...
> > Incidentally, should the following be legal?
> >
> >    package Outer is
> >        use package Inner is
> >            type T is new Integer;
> >        end Inner;
> >    end Outer;
> >
> >    limited with Outer;
> >    package Snort is
> >        type T_Ref is access Outer.T;
> >    end Snort;
> >
> > In other words, is the distinction between a "use" and a "non-use"
> > package retained in the limited view of an enclosing package?
>
> It would be weird if when you changed from non-limited to limited or
> vice versa, you had to insert/remove the name of the subpackage.  I
> don't see a big implementation burden here, and thus far limited views
> have been subsets of the full view.  It would be annoying if they were
> not just subsets, but really markedly different from the full view.

Umm, normally use clauses aren't allowed for limited views. I forget the exact
reasons, but I believe it had something to do with weird cases that we don't
want to allow. So having use visibility of a limited view *solely* for this use
would surely be unusual and irregular.

OTOH, not having it would harm the abstraction that we're trying to create.
I'm not sure what the correct answer is.

****************************************************************

From: Steve Baird
Date: Thursday, March 12, 2009  5:54 PM

> I think the namespace pollution issue is a big one.

As I said, I don't feel strongly about this one.
If I really thought that it would be common practice to introduce weird names to
avoid collisions, I would certainly support this proposal.

It does seem odd that you would get an error if you move some code out of the
enclosing package (code which references the inner package explicitly) and plunk
it down within the scope of a use-clause which names the outer package. On the
other hand, I suppose this is an unimportant corner case.

What about the case where explicit qualification is needed to resolve a
use-visibility collision?

     generic
        type T is private;
     package G is
         X : Integer;
         ... ;
     end G;

     with G;
     package P is
         use package I1 is new G (Integer);
         use package I2 is new G (Float);
     end P;

     with P;
     use P;
     package P_Client is
        Y : Integer renames I1.X; -- illegal
        Z : Integer renames P.I1.X; -- legal
     end P_Client;

Don't you think users would find this confusing?


>>> 2) Allow "use" in front of a package rename, with the effect

>
> Why are these pathological?  Can you explain what makes them worse
> than a rename followed by a normal "use" of the package?  (My mind
> isn't as fiendish as yours, I suspect.)
>>

You may be right. I ran into problems with these constructs during an earlier
attempt at this problem, but I think the equivalences we have been discussing
move these constructs from the "undefined" category into merely "confusing".

Would this sort of thing pose any problems?

     package Outer is
         package Inner is
            use package Ren renames Outer;
         end Inner;
         X : Integer := ... ;
         Y : Integer := Inner.X -- legal
                        + Inner.Y -- illegal
                        + Inner.Z; -- illegal
         Z : Integer := ... ;
     end Outer;

I remember very tangled discussions about the rules concerning a package which
has a limited with of a unit but which has the full view of the unit indirectly
in its closure.

Would there be issues along those lines with something like

     package Pkg is
        Squamish_Players_Per_Team : constant := 43;
     end Pkg;

     limited with Pkg;;
     package Zoofle is
         use package Ren renames Pkg;
     end Zoofle;

     with Pkg;
     with Zoofle;
     package Doofle is
        X : Integer := Zoofle.Squamish_Players_Per_Team; -- legal?
     end Doofle;

?


...
>> This feature also has a very high potential for misuse.
>> Use clauses can already be used to write code which is difficult to
>> read; this construct would make matters even worse in this respect.
>
> I'm not sure I see the issue here, so perhaps an example might help.

I see this as the stronger argument against this construct.

If you have something like

     use P1;
     use P2;
     use P3;
     ...
     use P9;
     package User is
         X : Integer := Foo;
     end User;

and you have no idea where Foo is coming from, you currently have to look in
each of the used specs. If any of the packages named in the use clauses are
library unit renames, you have to look through those renames. Assuming that you
haven't run into a particularly nasty case of an inherited function with
defaults for all parameters, you ought to find it in one of those specs.

If each of the used units now looks like

    with P3A;
    with P3B;
    ...
    with P3Z;
    package P3 is
       use package A renames P3A;
       use package B renames P3B;
       ...
    end P3;

, you've got a bigger search on your hands. And it need not end there - P3A may
have the same structure. And woe unto you if you're down in a subunit where
you've inherited a with of the child unit P3B.Foo ...

In the restricted case where "use package" is not used for renames, you can
still see this search-space expansion in the case of an instance (now you have
to go look at the generic spec) but somehow this seems more forgivable (for one
thing, it stops after one iteration if you ignore library unit renames).

>>
>> Incidentally, should the following be legal?
>>
>>    package Outer is
>>        use package Inner is
>>            type T is new Integer;
>>        end Inner;
>>    end Outer;
>>
>>    limited with Outer;
>>    package Snort is
>>        type T_Ref is access Outer.T;
>>    end Snort;
>>
>> In other words, is the distinction between a "use" and a "non-use"
>> package retained in the limited view of an enclosing package?
>
> It would be weird if when you changed from non-limited to limited or
> vice versa, you had to insert/remove the name of the subpackage.  I
> don't see a big implementation burden here, and thus far limited views
> have been subsets of the full view.  It would be annoying if they were
> not just subsets, but really markedly different from the full view.
>>

I completely agree. The argument against this (which I think is weak) is that
this requires extracting additional information from the limited view before
full semantic analysis has been run.

...
>>> 3) Consider using syntax similar to aspect specification
>>>    to rename components as part of doing a "use package":
...
>> This seems like a fairly big change, because it is no longer so
>> simple to define this construct just in terms of use-visibility.
>
> That's why I said "consider using" ;-)
>

I think Bob makes a good point here.
It is sufficiently easy to do this using existing mechanisms that the cost
associated with inventing any sort of new mechanism does not seem to be
justified (Bob - speak up if I'm misinterpreting your comment).

Adding implicit declarations to a package at some point other than the package
declaration is fine as long as you are sure that you are the only one doing it.
Suppose that you add a subtype named Foo to a package spec which then turns out
to have a child unit named Foo. We ran into this with the two different
mechanisms for defining a child unit of a package instance. Not that this case
couldn't be defined, but why bother?

There might also be issues with a Foo declared in the private part of the
package and a client who can see both the private part and the rename-inducing
"use package".


****************************************************************

From: Steve Baird
Date: Thursday, March 12, 2009  6:13 PM

>     limited with Pkg;
>     package Zoofle is
>         use package Ren renames Pkg;
>     end Zoofle;
>

Randy Brukardt wrote:
> Umm, normally use clauses aren't allowed for limited views.

I suppose the rule Randy cited would need to be generalized to disallow the
above example if "use" package renames are introduced.

****************************************************************

From: Bob duff
Date: Thursday, March 12, 2009  6:58 PM

> > I think the namespace pollution issue is a big one.

Tuck, I don't understand the problem here.  Why wouldn't people just use some
naming convention, like "use package Subpack is...", and have lots of things all
over the place called Subpack, which are not directly nameable because they all
conflict with each other?  I don't see why anyone would write "use package
Some_Horribly_Long_Name_That_Nobody_Would_Write". I mean, there's no real _harm_
in referring to it, so why not call them all "Subpackage" or whatever?

Am I missing something obvious?  We're talking about the package name polluting,
not the contents of, right?

If you like, you can call it "use package Box is" instead of "use package <>
is".  ;-)

> As I said, I don't feel strongly about this one.

Me, too.

...
> , you've got a bigger search on your hands. And it need not end there
> - P3A may have the same structure. And woe unto you if you're down in
> a subunit where you've inherited a with of the child unit P3B.Foo ...

I don't buy such "can be abused" arguments.  Patient: It hurts when I abuse use.
Doctor: So don't do that.  ;-) Anyway, in practice, you click on your fancy IDE
to find the thing.

> > That's why I said "consider using" ;-)
>
> I think Bob makes a good point here.
> It is sufficiently easy to do this using existing mechanisms that the
> cost associated with inventing any sort of new mechanism does not seem
> to be justified (Bob - speak up if I'm misinterpreting your comment).

[Bob wisely remains silent, indicating that Steve understood correctly.  ;-)]

****************************************************************

From: Tucker Taft
Date: Thursday, March 12, 2009  8:19 PM

> The potential for name pollution comes from the opening of the
> package, not from the name of the package on its own. If the name is
> in the source it should be usable, and it should still be possible to
> use qualified names to retrieve its contents (even if this is
> redundant). I agree with the other critics of this idea: a name in the
> source must be usable. Otherwise <> would be the right name, but this
> has been discarded for other reasons.

Just to be clear, I'm not suggesting the name completely disappears.  I'm
suggesting that if you "use" the *enclosing* package, and thereby also
implicitly "use" the inner package, you don't end up with the name of the inner
package itself directly (use) visible.   For example:

     package P is
        type S is ...;
        use package Inner is
           type T is ...
        end P;
        -- At this point "Inner", "S",
        -- "Inner.T" and simply "T" are all legal names.

     end P;

     -- At this point, "P", "P.S", "P.Inner", "P.Inner.T",
     -- "P.T" are all legal names.

     use P;
      -- At this point, in addition to the above, we can
      -- now use "S" and "T" legally.  My proposal is that
      -- "Inner" would *not* be directly use-visible,
      -- but you could still say "P.Inner".

The reason I am recommending this is that I think without it you will have
trouble using this feature when you are given an abstract spec, and you decide
the best way to implement it is using one of these "used-at-birth" subpackages.

For example, suppose we define a package spec in the Ada standard, or the ASIS
standard.  It turns out it can be nicely implemented by one or more
used-at-birth package instantiations, package renames, or nested packages.
Unfortunately, if someone does a "use" of this package, some user code might not
compile which should compile, because of the "extra" identifiers introduced by
these used-at-birth packages.  To avoid this problem, the implementor will have
to pick names that are unlikely to collide with any names used by clients,
meaning that every conscientious user of this feature will find themselves using
stupid-looking intentionally-unlikely names on all such used-at-birth packages.
By simply saying that the name of a used-at-birth subpackage doesn't get made
use-visible when the enclosing package is used, we eliminate this need to use
bogus-looking names.

****************************************************************

From: Jean-Pierre Rosen
Date: Friday, March 13, 2009  3:30 AM

> I think the namespace pollution issue is a big one.  If we don't do
> this, I foresee people using all kinds of weird names to try to be
> sure they don't have any collisions, and that seems like a waste of
> time and something that will make such packages look bogus.  Hiding
> the name of the subpackage itself from use visibility, for a
> subpackage that is "used at birth"
> (or "always open") feels like a much cleaner approach, and allows the
> user to pick a name for the subpackage that is descriptive rather than
> intentionally obscure.  I don't see it as "irregular"
> but rather I see it as a fairly natural consequence of having its
> contents always use-visible.

If you think the name of the package itself is not useful, why not make the
package anonymous, as I suggested earlier? i.e. instead of "use package Blah is
", just say "package is", and such a package would automatically be "open".

****************************************************************

From: Edmond Schonberg
Date: Friday, March 13, 2009  8:44 AM

Jean-Pierre's latest suggestion that the fictitious package should have no name
brings us back to the beginning: replace "use package"  with "private" and what
we have is the multiple private parts proposal, with fewer characters.  In fact
this is the full semantic contents of the "use package" proposal:  a way of
slipping in interspersed visible and private parts.  If this is the desired
effect we might as well go with it rather than define strange semantics for
"almost invisible" inner packages.  The implementation costs might be even
smaller.

****************************************************************

From: Steve Baird
Date: Friday, March 13, 2009  9:07 AM

> If you think the name of the package itself is not useful, why not
> make the package anonymous, as I suggested earlier? i.e. instead of
> "use package Blah is ", just say "package is", and such a package
> would automatically be "open".

Someone pointed out that there are problems with providing the body for an
anonymous package, particularly if you declare more than one in the same
enclosing package.

****************************************************************

From: Bob Duff
Date: Friday, March 13, 2009  7:09 AM

> For example, suppose we define a package spec in the Ada standard, or
> the ASIS standard.  It turns out it can be nicely implemented by one
> or more used-at-birth package instantiations, package renames, or
> nested packages.  Unfortunately, if someone does a "use" of this
> package, some user code might not compile which should compile,
> because of the "extra" identifiers introduced by these used-at-birth
> packages.  To avoid this problem, the implementor will have to pick
> names that are unlikely to collide with any names used by clients,
> meaning that every conscientious user of this feature will find
> themselves using stupid-looking intentionally-unlikely names on all
> such used-at-birth packages.  By simply saying that the name of a
> used-at-birth subpackage doesn't get made use-visible when the
> enclosing package is used, we eliminate this need to use bogus-looking
> names.

I find this argument convincing.  In fact, in this scenario, even a
stupid-looking name is technically in violation of the ASIS standard.

Can you tell us what the problem is with your "use package <> is" idea?
I assume the same issues would apply to J.P.'s proposed syntax "package is"
(which seems preferable -- we got enough <>'s in the syntax!).

****************************************************************

From: Tucker Taft
Date: Friday, March 13, 2009  12:22 PM

The problem with "package <> is" comes when you get to the body.  If there is
more than one, things are ambiguous.  Also, Erhard made a convincing argument
that if you use unnamed packages, there really is no good way to workaround
collisions that might come up due to multiple "use" clauses.  With a name for
these packages, you can at least give a full expanded name in the case of a
collision.

****************************************************************

From: Tucker Taft
Date: Friday, March 13, 2009  3:43 PM

I just ran into another potential use for this feature.  Periodically I want to
define a new generic package which has somewhat different formal parameters than
an existing generic, but declares essentially the same types and operations.

This could be done quite easily with this proposed feature:

  given an existing generic:

    generic
        type T is private;
        with procedure Op(...);
        Blah : in T;
    package Old_Generic is
        type Container is private;
        ...
    end Old_Generic;

  Presume I want to create a version of the generic that
  only takes derivatives of P.T as the formal type,
  and has fewer generic formals:

    with P;
    generic
       type T is new P.T;
    package New_Generic is
       use package Instance is
         new Old_Generic(T, Op => P.Op1, Blah => T(P.Val));
    end New_Generic;

Very elegant, in my view.  In the current language you end up having to repeat
the entire package spec, and then in the private part or body instantiate the
old generic, and define each of the operations via renaming or wrapping of the
old one.

(This is another example of where you really have no interest in having the name
"Instance" be made directly visible when you apply a "use" clause to some
instance of New_Generic, though I promise that wasn't the point of the
example... ;-)

****************************************************************

From: Steve Baird
Date: Friday, March 13, 2009  4:14 PM

> Very elegant, in my view.

Typos aside, I agree.
This could be a useful idiom.

> In the current language you end up having to repeat the entire package
> spec, and then in the private part or body instantiate the old
> generic, and define each of the operations via renaming or wrapping of
> the old one.
>
> (This is another example of where you really have no interest in
> having the name "Instance" be made directly visible when you apply a
> "use" clause to some instance of New_Generic, though I promise that
> wasn't the point of the example... ;-)

Until you want to instantiate a generic which takes a formal instance of
Old_Generic. This is really more of an argument against making the name
completely unavailable, as opposed to your proposal which only makes it
unavailable via a use clause.

****************************************************************

From: Bob Duff
Date: Friday, March 13, 2009  4:56 PM

> Very elegant, in my view.

Yes, very nice.

****************************************************************

From: Randy Brukardt
Date: Thursday, March 19, 2009  12:25 AM

...
> >> 2) Allow "use" in front of a package rename, with the effect of
> >> "open"ing the named package.
> >> ...
> >
> > Is it clear that we need this generality?
> >
> > This would require adding wording to cope with various pathological
> > cases that this would make possible (e.g. a rename of a limited view
> > of a package, a rename of a package whose spec encloses the rename).
>
> Why are these pathological?  Can you explain what makes them worse
> than a rename followed by a normal "use" of the package?  (My mind
> isn't as fiendish as yours, I suspect.)

The problem I see here is that we decided we didn't like "use all pack;" because
of issues with re-exporting existing packages (rather than new, as in an
instance or nested package).

We didn't like:
   with Bar;
   package Glarch is
      use all Bar;
   end Glarch;

But Tucker wants to allow:
   with Bar;
   package Glarch is
      use package Foo renames Bar;
   end Glarch;

I have an amazingly hard time figuring the (semantic) difference between these
two, except that we now have a name Glarch.Foo. That doesn't seem to be an
improvement over "use all Bar"!

---

The annoying thing here is I didn't record in the minutes precisely why we
thought this was distasteful. All I have is:

There is some discomfort with the idea that this essentially forces a use clause
into clients of a package. Use-adverse programmers will not be happy. It seems
especially weird when it is used on a package that is defined outside of the
current unit.

Based on this, I'm confused. If we don't find the latter example distasteful,
then I don't see how we can find the former example distasteful, either. So then
we should simply go back to "use all Pack", because it surely looks simpler to
me than this funny prefix.

Otherwise, "use" should not be allowed on renames.

****************************************************************

From: Tucker Taft
Date: Thursday, March 19, 2009  7:48 AM

One of Erhard's major complaints with the "use all" was that it was subject to
use-clause cancellation with no workaround.  The "use package Foo renames
X.Bar;" avoids that problem, by providing the name "Foo" as a way to identify
declarations within X.Bar that might be subject to cancellation.

I don't understand the "use-averse" comment.  The presumption is that if they
didn't have this capability, the programmer would have to use a derived type or
a bunch of individual renames to get the names from the other package declared
directly within the new package.  This merely allows the programmer to do this
more efficiently and without the cut-and-paste errors that can crop up with a
sequence of renames. It also avoids introducing the potentially confusing new
types that a derived type would imply.

Nothing is made directly visible unless the client of the enclosing package
decides to "use" that package, which of course wouldn't happen if the client
were use-averse.

****************************************************************

From: Micronian
Date: Thursday, April 2, 2009  12:38 PM

I read this AI and while it does seem useful to make a package abstraction by
"combining" other packages, I am concerned about the possibility of people
inadvertently coding a hierarchy such as below:

package Pkg1 is
    -- some stuff declared here
end Pkg1;


with Pkg1;
package Pkg2 is
    use package Inner renames Pkg1;
    -- some stuff declared here
end Pkg2;


with Pkg2;
package Pkg3 is
    use package Inner renames Pkg2;
    -- some stuff declared here
end Pkg3;


This would make it confusing for a person to trace down declarations since now
you have to look through a chain of packages. This is also one of the reasons
why I dislike working with C code with the transitive nature of the #include
statements:

header1.h <----header2.h <----header3.h

This linear case is simple, but sometimes there are a few more branches of
header dependencies further along the hierarchy. It is possible that this new
extended-scope use clause would invite such coding habits into Ada (e.g. C
programmers programming Ada in a C like fashion).

Any thoughts?

****************************************************************

From: Randy Brukardt
Date: Thursday, April 2, 2009  1:44 PM

This has recently been discussed within the ARG. The original "use package"
proposal only applied to nested packages and to instances, but not renames.
So the example you give wasn't intended.

It was suggested that it be extended to include package renames for consistency
reasons. But I think that is essentially the same as the original "use all
<package>;" proposal, and the reason it was rejected (at least the reason *I*
rejected it) was because of examples like the one you give here.

"Use all <package>;" has the effect of allowing the author of an abstraction to
*force* clients to use "use clauses" whether they want to or not. For
programmers that are use-averse (like me), that's not acceptable.

The non-use-adverse claim that the inclusion of the name in the renames makes
all the difference, and I admit that it does help a bit - you at least have a
fully expanded name to use. But the readability problems in other people's code
remain.

The argument has been made that you can use your fancy IDE to find the
declaration; but I don't buy that. My "fancy IDE" is an 1980's vintage MS-DOS
text editor, since it is a better *programming editor* than anything I've ever
tried on Windows. No IDE capabilities there, and oddly enough, I don't expect an
update to add any! And, in any case, you have to be able to compile most of a
program before the fancy IDE can provide any help at all; it is no help on
snippets of code or partially completed programs.

****************************************************************

From: Micronian
Date: Thursday, April 2, 2009  2:19 PM

I'm glad to hear that renames were rejected. That helps keep the hierarchy very
shallow.

Normally when I use a USE clause in my Ada code, I still try to qualify many,
but not all things with the package names because I dislike looking into code
that makes it inconvenient to find out at first glance where things came from.
Like you, I often still use my good ol' super "text" editor (Emacs :) ), but
there are plenty of cases where the projects I'm on happen to use a nicer IDE
(e.g. Visual Studio). While these IDE's make code navigation easier, I agree
that it should not be a requirement to have these tools around.

****************************************************************

From: Dmitry A. Kazakov
Date: Thursday, April 2, 2009  2:15 PM

> Any thoughts?

I think that the proposal is extremely important for designing reusable
components. Presently it is impossible to decompose a package declarative part
into several smaller packages without exposing these parts later to the clients.
Since their declarations remain outside the "main" package, the user must be
aware of the relationship between these packages, which is often occasional and
implementation controlled. This becomes especially painful with instances of
generic packages within the declarative part. Another extremely important case
is generic packages themselves. For example:

   generic
      with package Numbers is new Rational_Numbers (<>);
   package Rational_Series is
      use all Numbers;
      ...
   end Rational_Series;

It makes no sense to do "use Rational_Series" without "use"-ing its numbers.
Usually such hierarchies of packages are quite deep, and it is very tedious to
find all corresponding instances and then "with" and "use" all of them.

In my view transitiveness is exactly what is needed to make design of packages
use-clause friendly.

****************************************************************

From: Micronian
Date: Thursday, April 2, 2009  2:33 PM

Don't get me wrong, I still think the feature is useful, but I just don't think
WITHing one package should automatically include a large deep hiearchy that
makes it a hassle to navigate through. When I learned Ada, I was happy to see
that it did not have the transitive nature of C's #includes. But, yes I have
come into cases like you have said where you split the implementation to keep
the "main" package smaller, yet increasing the number of WITHs for the user. I
just think it would be great if the extended-use feature has a good balance.

****************************************************************

From: Randy Brukardt
Date: Thursday, April 2, 2009  11:06 PM

> I'm glad to hear that renames were rejected. That helps keep the
> hierarchy very shallow.

Umm, that's my opinion; the full ARG hasn't really considered the issue. I could
imagine it going either way, because this is a "deep pit" issue (as Tucker once
described it). We're already in a deep pit (in this case, because of inheritance
-- it's pretty much necessary to have a tool to figure out where things are
declared when doing OOP, because nothing interesting appears in the source), and
it is not clear whether there is any reason to avoid going all the way to the
bottom.

I know where *I* stand on this one, and it is good to know that others think
like me. But whether that will be enough to defeat the forces of "consistency"
remains to be seen.

****************************************************************

From: Randy Brukardt
Date: Thursday, April 23, 2009  12:22 AM

Now for the technical comments:

You have:

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.

This wording is very different than the existing wording for potentially
use-visible (which talks about "scope enclosing a place" and "each
declaration that occurs immediately within the declaration region of the
package"). And we always try to avoid stuff like "at any point". You seem
to have "solved" that by putting it as far away as possible from 8.4(8).
But I think all of reasons for a declaration being "potentially use-visible"
should go together; this paragraph should go right after 8.4(8) (it's not
really related to "potentially use-visible by selection", which can go later).

----

The main reason I was reading the above was that I was trying to figure out
what happens when the same declaration is use-visible (and use-visible by
selection) by multiple paths. This is where the equivalence you give at the
beginning of the discussion breaks down (or something is getting very
complicated). Consider the following:

    package P1 is
       C : constant Boolean := True;
    end P1;

    with P1;
    package P2 is
       use package P3 renames P1;
    end P2;

    with P1, P2; use P1, P2;
    procedure M1 is
    begin
       if C then -- OK?
           ...
       end if;
    end M1;

One would like this to be legal, by analogy with a regular use clause.
But use-by-selection starts getting messy:

    with P1;
    package P4 is
        use package P1 renames Standard.P1;
    end P4;

    with P1, P4; use P1, P4;
    procedure M2 is
    begin
       if P1.C then -- (1)
            ...
       end if;
    end M2;

Is (1) OK? I suppose it is because the prefix P1 is directly visible,
which hides the use-visible P4.P1.

But then try:

    with P1;
    package P5 is
        use package P1 renames Standard.P1;
    end P5;

    with P4, P5; use P4, P5;
    procedure M3 is
    begin
       if P1.C then -- (2)
            ...
       end if;
    end M3;

Both P4.P1.C and P5.P1.C denote the same declaration, so one would expect
this to work. (That is how I read the proposed wording.) But it isn't clear
to me at all how that gets worked out from the non-overloadable prefixes.
(Currently, there can only be one interpretation of a non-overloadable name,
but here it seems that we have two.)

One could argue that we don't need this complication, and declare (2) to be
ambiguous. But then you would risk eliminating declarations that don't
conflict with anything and that we need to see.

    package P6 is
       V : Integer := 0;
    end P6;

    with P6;
    package P7 is
        use package P1 renames Standard.P6;
    end P7;

    with P4, P7; use P4, P7;
    procedure M4 is
    begin
       if P1.C then -- (3)
            ...
       end if;
    end M4;

One would hope there is no ambiguity here (in (3)), as there is only one
C in the program. Again, this is what the wording appears to say.

So it looks like *everything* is overloadable in a practical sense (the
compiler will have to treat every prefix that way at least). At which point
I wonder what the advantage of continuing to even have non-overloadable
declarations will be, since they'll no longer provide any benefit in
resolution or error correction.

Unfortunately, this last case can happen with instances and nested packages
as well as package renames (obviously, the declarations can't be same unless
a rename is involved). I admit that I was trying to find cases where "integrated"
renames caused semantic problems, but it appears that instead I've found that
this whole idea is going to cause significant implementation problems (at
least for any implementation that takes any advantage of knowing that a name
is non-overloadable).

This is going to happen a lot in practice, because there is no good name for
typical nested packages (especially as there is no real intent to use them
via that name). So I expect a lot of use of the same names (much like the
style of calling all object-oriented types "Object" and using the package
name as the "real" name). That's going to lead to this sort of conflict.

So it appears that my objection to the renames case has now spread to the
entire idea. Besides making it pretty much impossible to find the declaration
of something without a fancy tool (which of course doesn't work if the code
isn't compilable), it also will substantially complicate implementation. So,
if this is the proposal that is going forward, I'm opposed.

****************************************************************

From: Steve Baird
Date: Thursday, April 23, 2009  10:37 AM

> ...  this paragraph should go right after 8.4(8) (it's not really
> related to "potentially use-visible by selection", which can go
> later).
>

Good point.

> ----
>
> The main reason I was reading the above was that I was trying to
> figure out what happens when the same declaration is use-visible (and
> use-visible by
> selection) by multiple paths. This is where the equivalence you give
> at the beginning of the discussion breaks down (or something is
> getting very complicated). Consider the following:
>
>     package P1 is
>        C : constant Boolean := True;
>     end P1;
>
>     with P1;
>     package P2 is
>        use package P3 renames P1;
>     end P2;
>
>     with P1, P2; use P1, P2;
>     procedure M1 is
>     begin
>        if C then -- OK?
>            ...
>        end if;
>     end M1;
>
> One would like this to be legal, by analogy with a regular use clause.

And we agree that it is legal, right?

> But use-by-selection starts getting messy:
>
>     with P1;
>     package P4 is
>         use package P1 renames Standard.P1;
>     end P4;
>
>     with P1, P4; use P1, P4;
>     procedure M2 is
>     begin
>        if P1.C then -- (1)
>             ...
>        end if;
>     end M2;
>
> Is (1) OK? I suppose it is because the prefix P1 is directly visible,
> which hides the use-visible P4.P1.
>

Right.

> But then try:
>
>     with P1;
>     package P5 is
>         use package P1 renames Standard.P1;
>     end P5;
>
>     with P4, P5; use P4, P5;
>     procedure M3 is
>     begin
>        if P1.C then -- (2)
>             ...
>        end if;
>     end M3;
>
> Both P4.P1.C and P5.P1.C denote the same declaration, so one would
> expect this to work. (That is how I read the proposed wording.) But it
> isn't clear to me at all how that gets worked out from the non-overloadable prefixes.
> (Currently, there can only be one interpretation of a non-overloadable
> name, but here it seems that we have two.)
>

This is ambiguous because the prefix of the name P1.C is ambiguous.
I believe the wording I suggested captures this correctly, and that this is consistent
with the informal implicitly-inserted-use_clauses model.

It is similar to the following situation in the current language:

   declare
      package P1 is
          X : Integer := 0;
      end P1;

      package P2 is
          package P1_Ren renames P1;
      end P2;

      package P3 is
          package P1_Ren renames P1;
      end P3;

      use P2, P3;

      Y : Integer := P1_Ren.X; -- illegal

> One could argue that we don't need this complication, and declare (2)
> to be ambiguous. But then you would risk eliminating declarations that
> don't conflict with anything and that we need to see.
>
>     package P6 is
>        V : Integer := 0;
>     end P6;
>
>     with P6;
>     package P7 is
>         use package P1 renames Standard.P6;
>     end P7;
>
>     with P4, P7; use P4, P7;
>     procedure M4 is
>     begin
>        if P1.C then -- (3)
>             ...
>        end if;
>     end M4;
>
> One would hope there is no ambiguity here (in (3)), as there is only
> one C in the program. Again, this is what the wording appears to say.
>

No, I believe the prefix of the name "P1.C" is ambiguous and that this example should be
rejected. Certainly that was my intent and I believe the suggested wording captures that.

> So it looks like *everything* is overloadable in a practical sense
> (the compiler will have to treat every prefix that way at least). At
> which point I wonder what the advantage of continuing to even have
> non-overloadable declarations will be, since they'll no longer provide
> any benefit in resolution or error correction.

I don't think so. I think the bad consequences you describe are based on a misunderstanding.
Support for ambiguous prefixes was certainly not intended. I believe the suggested wording
captures that intent, but if it doesn't then the wording needs to be corrected.

****************************************************************

From: Tucker Taft
Sent: Thursday, May 21, 2009  5:27 AM

I had a couple of "waking up" thoughts, as Jimmy Carter used to call them:

[Editor's note: The other thought pertains to AI05-0142-2 and is filed in that AI.]

  2) I had a perfect example of why the name of an "integrated" package
      should not become "use" visible when the enclosing package
      is "use"d, and a good example of why integrated package renames
      are useful:  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 a:
        "use package <something> renames Ada.IO_Exceptions;"
      in Text_IO, Sequential_IO, and Direct_IO.

      However, what should the <something> be?  Well, most natural would be:
        "use package IO_Exceptions renames Ada.IO_Exceptions;"

      but now suppose you have:

         with Ada.IO_Exceptions;
         with Ada.Text_IO;
         use Ada;
         procedure What_Fun is
            use Text_IO;
              -- oops, IO_Exceptions suddenly disappears
         begin
             ...
         exception
             when IO_Exceptions.Name_Error =>
                 -- oops, this doesn't compile any more!

         end What_Fun;

      There is always a compatibility problem whenever we consider
      adding another identifier to an existing package.  But the
      problem is always about "use" visibility of that new identifier.
      We don't worry about there being another identifier available
      for "selective" visibility, because no existing program would
      have a reference to the newly added identifier as a component
      of the existing package.

      I really think this integrated package concept will be a
      useful way to implement packages, allowing after-the-fact
      reusability of parts of packages, but every time I think
      about it, I end up worrying what the heck I am going to use for
      the names of those integrated packages.  We considered allowing "<>"
      for the name of the integrated package, but Erhard seems to have
      convinced us that you need them for resolving ambiguities.  Just
      making integrated package names *not* themselves use-visible provides
      an elegant solution and ensures upward compatibility when you
      decide to (re)implement part of the functionality of an existing
      package by using one.

      By the way, a *nice* feature of implementing the sequence of
      renames of exceptions via "use package blah renames Ada.IO_Exceptions"
      is that the exception names would presumably *not* cancel each other
      out if you use'd two different instantiations of, say, Direct_IO.
      But I suppose that depends on the details of the wording for
      how the contents of an integrated package rename (presuming we
      support them) become visible...  Steve?

****************************************************************

From: Randy Brukardt
Sent: Friday, May 22, 2009  12:45 PM

...
>       There is always a compatibility problem whenever we consider
>       adding another identifier to an existing package.  But the
>       problem is always about "use" visibility of that new identifier.
>       We don't worry about there being another identifier available
>       for "selective" visibility, because no existing program would
>       have a reference to the newly added identifier as a component
>       of the existing package.

Client use clauses are always a problem. They ought to be used very sparingly.

>       I really think this integrated package concept will be a
>       useful way to implement packages, allowing after-the-fact
>       reusability of parts of packages, but every time I think
>       about it, I end up worrying what the heck I am going to use for
>       the names of those integrated packages.  We considered allowing "<>"
>       for the name of the integrated package, but Erhard seems to have
>       convinced us that you need them for resolving ambiguities.

You also need a name for limited with, which does not allow any use clauses. That has
to be true for these "integrated" packages as well. (You could easily get the same sorts
of anomolies.)

>       Just making integrated package names *not* themselves use-visible provides
>       an elegant solution and ensures upward compatibility when you
>       decide to (re)implement part of the functionality of an existing
>       package by using one.

Banning client use clauses would work, too. ;-)

>       By the way, a *nice* feature of implementing the sequence of
>       renames of exceptions via "use package blah renames Ada.IO_Exceptions"
>       is that the exception names would presumably *not* cancel each other
>       out if you use'd two different instantiations of, say, Direct_IO.
>       But I suppose that depends on the details of the wording for
>       how the contents of an integrated package rename (presuming we
>       support them) become visible...  Steve?

I made an argument like this once (in terms of implementation difficulty) and Steve
convinced me that there is none because we're not allowing anything new. This sounds new,
since we get such conflicts from renames with client use clauses:

    package P is
        Obj : Natural;
    end P;

    with P;
    package Q is
        package Inner renames P;
    end Q;

    with P;
    package R is
        package Inner renames P;
    end R;

    with Q, R;
    procedure Test is
       use Q.Inner, R.Inner;
    begin
       Obj := 10; -- Not use-visible due to collision.
    end Test;

I don't see why we would want "integrated packages" to work differently, that would make
a lot of additional work and would add confusion to users (which kind of use clause works how??).

****************************************************************

From: Steve Baird
Sent: Friday, May 22, 2009  4:04 PM

...
>      However, what should the <something> be?  Well, most natural would be:
>        "use package IO_Exceptions renames Ada.IO_Exceptions;"
>
>      but now suppose you have:
>
>         with Ada.IO_Exceptions;
>         with Ada.Text_IO;
>         use Ada;
>         procedure What_Fun is
>            use Text_IO;
>              -- oops, IO_Exceptions suddenly disappears
>         begin
>             ...
>         exception
>             when IO_Exceptions.Name_Error =>
>                 -- oops, this doesn't compile any more!
>
>         end What_Fun;
>

Good point. I'll certainly include this example in the AI.

>      By the way, a *nice* feature of implementing the sequence of
>      renames of exceptions via "use package blah renames Ada.IO_Exceptions"
>      is that the exception names would presumably *not* cancel each other
>      out if you use'd two different instantiations of, say, Direct_IO.
>      But I suppose that depends on the details of the wording for
>      how the contents of an integrated package rename (presuming we
>      support them) become visible...  Steve?
>

Right.
The compilation error you mentioned above can be fixed by replacing
   when Io_Exceptions.Name_Error =>
with
   when Name_Error =>
.

****************************************************************

From: Tucker Taft
Sent: Friday, May 22, 2009  4:18 PM

> Right.

Can you be a bit more specific?  Randy seemed to think you had said something
else.  My presumption is that if we support integrated renames, "use"ing the
package enclosing the integrated rename as well as "use"ing the renamed inner
package itself will not cause cancellation, any more than it would if you do a
"use" of two different renames of the same package.

****************************************************************

From: Steve Baird
Sent: Friday, May 22, 2009  5:22 PM

I agree with your interpretation.

One way to verify this is a two-step process
    1) Check the informal definition of how integrated packages work
       at the beginning of the !discussion section to see if it
       yields the desired behavior.
    2) Check the wording to see if it correctly captures the
       informal definition.

We are looking at something like

    with Ada.Io_Exceptions;
    package P1 is
        use package Io_Exceptions renames Ada.Io_Exceptions;
    end P1;

    with Ada.Io_Exceptions;
    package P2 is
        use package Io_Exceptions renames Ada.Io_Exceptions;
    end P2;

    with P1, P2;
    use P1, P2;
    procedure Foo is
    begin
       ...
    exception
       when Name_Error => ... ;
    end Foo;

By informal equivalence #2, "use P1" is equivalent to "use P1; use P1.Io_Exceptions".
Ditto for "use P2".

It has been well established since Ada83 that it makes no difference whether a
use clause names a package or a rename of that package. It is similarly
well established that being within the scope of two uses clauses of a given
package is no different than being within the scope of one.
Let me know if you would like a more detailed justification for thoee assertions,
but this is stuff that hasn't changed in years.

Taken together, this means that the use of Name_Error occurs in a use-clause state
that is equivalent to being in the scope of a use clause that denotes Ada.Io_Exceptions.

Thus, the use of the simple name Name_Error is legal.

The AI wording that corresponds to equivalence #2 is
   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.

Note that homographs can be simultaneously potentially use-visible.
The fact that they are homographs doesn't matter until we come to the question of
whether they are use-visible (as opposed to potentially use-visible).

****************************************************************

From: Tucker Taft
Sent: Friday, May 22, 2009  2:12 PM

>     with Q, R;
>     procedure Test is
>        use Q.Inner, R.Inner;
>     begin
>        Obj := 10; -- Not use-visible due to collision.

Huh?  I don't believe that.  Are you sure?
Our front end has no problem compiling this example.

>     end Test;
>
> I don't see why we would want "integrated packages" to work
> differently, that would make a lot of additional work and would add
> confusion to users (which kind of use clause works how??).

I agree that integrated renames should work like regular renames from this point
of view, and my claim is that the above "use" clauses do *not* cause cancellation,
because they are "using" the *same* package (through two different renamings).

If you look in RM 8.4, it talks about *packages* denoted by the name appearing
in the "use" clause (as opposed to "package declarations).  A package *rename*
does not create a distinct package, though of course it is a distinct declaration.
In general when talking about entities (as opposed to declarations), renames are
irrelevant.  No matter how many different renames are involved, there is only
one entity involved, and the two "use" clauses in your example denote the *same*
package entity.  So that is why I wanted integrated packages to work the same way.

Steve, do you disagree?

****************************************************************

From: Steve Baird
Sent: Friday, May 22, 2009  5:44 PM

I agree, both with respect to the existing language and with respect to integrated
packages.

****************************************************************

From: Steve Baird
Sent: Friday, May 22, 2009  4:56 PM

> I made an argument like this once (in terms of implementation
> difficulty) and Steve convinced me that there is none because we're
> not allowing anything new. This sounds new, since we get such
> conflicts from renames with client use clauses:
>
>     package P is
>         Obj : Natural;
>     end P;
>
>     with P;
>     package Q is
>         package Inner renames P;
>     end Q;
>
>     with P;
>     package R is
>         package Inner renames P;
>     end R;
>
>     with Q, R;
>     procedure Test is
>        use Q.Inner, R.Inner;
>     begin
>        Obj := 10; -- Not use-visible due to collision.
>     end Test;

I'm not sure what you are talking about here.
This example is legal Ada.
If you rewrote it with integrated package renames in what seems to me like
the obvious way, it would still be legal.

****************************************************************

From: Randy Brukardt
Sent: Friday, May 22, 2009  5:29 PM

Without Tucker's explanation, I would have no idea what you are talking about. Even
with Tucker's explanation, I find the idea that this is supposed to work highly
distrubing. I don't buy the notion that Q.Inner.Obj and R.Inner.Obj are the same entity
for resolution proposes; you're essentially claiming that the full name of Obj in this
example would be P.Obj, even though that name isn't even visible in this context. I
suppose the counter-argument is that it doesn't matter to the Ada program (but it makes
writing tools - especially a use-clause remover - much more difficult).

What you guys are telling me is that the features which I detest so much about *this*
proposal and its interaction with renames (to the point that I've been trying to keep
this particular combination out of "integrated packages") is in fact already a part of Ada.

Indeed, this entire area makes me so uncomfortable that at this point I cannot in good
conscience support any expansion of use-visibility. (I'd rather see pragma
Restrictions(No_Package_Use); added to the language...) Thus "integrated packages" are
a dead idea in my mind, and I'm not going to spend any more of my time (other than
administratively, of course) on it.

P.S. The only acceptable way IMHO to deal with these interactions is to outright ban
the use of 'package use' on packages that contains "integrated packages". But that seems
like a weird restriction, even to me.

P.P.S. Besides this issue, I've also soured on this version of "integrated packages"
because they re-emerge annoyingly: you have to use the nested package name when you are
using limited withs; you have to use the nested package name to work around naming
conflicts; and I think there was another case where you had to use the "real" name (which
I've forgotten the details of). This really doesn't have the effect of "integrating" the
package (treating it as being non-nested for almost all purposes) as we really wanted.

****************************************************************

From: Tucker Taft
Sent: Friday, May 22, 2009  9:27 PM

This is not very radical.  In fact, when it doesn't work it is more surprising.
Use-clause cancellation is generally a pain, and we should minimize unnecessary
cancellation.

****************************************************************

From: Randy Brukardt
Sent: Friday, May 22, 2009  10:57 PM

Ada is a name-equivalence language, and Q.Inner.Obj and R.Inner.Obj are not name equivalent;
therefore they're not the same. They *ought* to use-clause cancel. I realize that I'm going
against Ichbiah on this one, but I really don't want to see any expansion of what I see as
a major error in the language definition. I really dislike using renames in this way in any
case (the only reason to use a renames of a package is to provide a shorter name when you
are *not* using use clauses; a use clause of such a package is clearly a hack and very bad
style).

Also note that I think that we have usage problems with this proposal anyway - above and beyond
this particular concern. These nested packages are going to pop up at inopportune times;
they are not really going to "feel" integrated. I'd really rather have a mechanism where the
names really are part of the root package. (I realize that we sort of tried that initially
and had some problems with collisions; I'm thinking now that such names should simply be
illegal (rather than some sort of hiding)). But I've got so many other proposals to work on
- ones that appear to work out - that spending more time on this one just doesn't make sense.

P.S. This is all your fault. :-) I have such strong regrets about ignoring my gut feelings
in favor of "rationality" and letting you put the "coextension" abomination into the
language, that I've vowed to take stronger stands against things that "feel" wrong. This
appears to be the first real test...

****************************************************************

From: Randy Brukardt
Sent: Friday, May 22, 2009  11:28 PM

I should also say that if this is the way things are intended to work, it is extremely
irregular in that it only works for packages. It greatly rubs me the wrong way that you
would get different results for:

   with Ada.IO_Exceptions;
   package Ada.Text_IO is
       Name_Error : renames Ada.IO_Exceptions.Name_Error;
   end Ada.Text_IO;

   with Ada.IO_Exceptions;
   package Ada.Stream_IO is
       Name_Error : renames Ada.IO_Exceptions.Name_Error;
   end Ada.Stream_IO;

   with Ada.Text_IO, Ada.Stream_IO;
   use  Ada.Text_IO, Ada.Stream_IO; -- This is pretty much the only time I'd use one of these...
   procedure Test is
       null;
   exception
      when Name_Error => null; -- Illegal, use-clause cancelation
   end;

versus

   with Ada.IO_Exceptions;
   package Ada.Text_IO is
       use package IO_Exceptions renames Ada.IO_Exceptions;
   end Ada.Text_IO;

   with Ada.IO_Exceptions;
   package Ada.Stream_IO is
       use package IO_Exceptions renames Ada.IO_Exceptions;
   end Ada.Stream_IO;

   with Ada.Text_IO, Ada.Stream_IO;
   use  Ada.Text_IO, Ada.Stream_IO; -- This is pretty much the only time I'd use one of these...
   procedure Test is
       null;
   exception
      when Name_Error => null; -- Supposedly OK.
   end;

I want "integrated packages" to work exactly as if the declarations are in the outer package,
and this difference is aggravating.

****************************************************************

From: Tucker Taft
Sent: Saturday, May 23, 2009  10:29 AM

It doesn't work differently for package *names*, but it works for the contents of a package
if it is "use"d via two different renames.  Ada is not a "name equivalent" language in the
sense you imply.  It is "name equivalent" only if there are no renamings in the name, and you
start from "Standard".

Even "full conformance" allows matching of two different "expanded names" so long as they
denote the "same" declaration (see 6.3.1(21.a-f) for an explicit discussion of this).

Renaming a package doesn't create
a new package, nor a new set of declarations for the components of the package.
It only creates a new "package renaming declaration,"
and (somewhat annoyingly) these package *renamings* will cancel each other out in a case like:

     with R;
     package P is
        package S renames R.S;
        ...
     end P;

     with R;
     package Q is
        package S renames R.S;
        ...
     end Q;

     with P, Q;
     procedure Test is
        use P, Q; -- "S" is canceled out here;
                  -- packages are *not* a special case

        use P.S, Q.S;  -- But no cancellation occurs here.
                       -- because P.S and Q.S denote
                       -- the *same* package.

Package renamings would not work if they created a new set of declarations of the components
of the package. We clearly want P.S.T and Q.S.T to denote the same declaration.  If for example,
T is a type declaration, P.S.T and Q.S.T are the same type.

****************************************************************

From: Edmond Schonberg
Sent: Saturday, May 23, 2009  12:38 PM

>  with Ada.IO_Exceptions;
>   package Ada.Text_IO is
>       use package IO_Exceptions renames Ada.IO_Exceptions;
>   end Ada.Text_IO;
>
>   with Ada.IO_Exceptions;
>   package Ada.Stream_IO is
>       use package IO_Exceptions renames Ada.IO_Exceptions;
>   end Ada.Stream_IO;
>
>   with Ada.Text_IO, Ada.Stream_IO;
>   use  Ada.Text_IO, Ada.Stream_IO; -- This is pretty much the only time I'd use one of these...
>   procedure Test is
>       null;
>   exception
>      when Name_Error => null; -- Supposedly OK.
>   end;
>
> I want "integrated packages" to work exactly as if the declarations
> are in the outer package, and this difference is aggravating.

But as Steve points out, this has always been legal with regular use- clauses on renamings.
My understanding is that use clauses look through the renaming, and redundant use clauses are
noops. If instead of "integrated packages" you write:

  with Ada.Text_IO, Ada.Stream_IO;
   use  Ada.Text_IO, Ada.Stream_IO; -- This is the only time I'd use one of these ...
   procedure Test is
    use Ada.Text_IO.IO_Exceptions;
    use Ada.Stream_IO.IO_Exceptions;
   begin
       null;
   exception
      when Name_Error => null; -- Supposedly OK.
   end;

this has been legal for some 14 years.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, May 26, 2009  6:38 PM

> It doesn't work differently for package *names*, but it works for the
> contents of a package if it is "use"d via two different renames.  Ada
> is not a "name equivalent" language in the sense you imply.  It is
> "name equivalent" only if there are no renamings in the name, and you
> start from "Standard".

Sorry, but this last sentence is clearly False. And that is what I'm objecting
to. If you had said:

It is "name equivalent" only if there are no renamings {of packages} in the name,
and you start from "Standard".

then you would have made a True statement. But why should packages get this special
treatment, and not renames of exceptions, or generics, or subprograms, etc.? We have
"Ada is a name equivalence language unless the name is a renaming of a package".

...
>      with P, Q;
>      procedure Test is
>         use P, Q; -- "S" is canceled out here;
>                   -- packages are *not* a special case
>
>         use P.S, Q.S;  -- But no cancellation occurs here.
>                        -- because P.S and Q.S denote
>                        -- the *same* package.
>
> Package renamings would not work if they created a new set of
> declarations of the components of the package.
> We clearly want P.S.T and Q.S.T to denote the same declaration.  If
> for example, T is a type declaration, P.S.T and Q.S.T are the same
> type.

I can't think of any legitimate reason to write a use clause of a renamed package in
Ada 95 or 2005, so why do we care what happens here? In particular, why should it work
differently than all other renames?

Surely the packages could be different while still denoting the same underlying entities:
that certainly works for renaming of other entities, such as exceptions.

Nobody has made any effort to address (or even acknowledge) my other concerns. I'll put
them on the main ARG list for further discussion.

****************************************************************

From: Tucker Taft
Sent: Tuesday, May 26, 2009  8:08 PM

>> It doesn't work differently for package *names*, but it works for the
>> contents of a package if it is "use"d via two different renames.  Ada
>> is not a "name equivalent" language in the sense you imply.  It is
>> "name equivalent" only if there are no renamings in the name, and you
>> start from "Standard".
>
> Sorry, but this last sentence is clearly False. And that is what I'm
> objecting to. If you had said:
>
> It is "name equivalent" only if there are no renamings {of packages}
> in the name, and you start from "Standard".
>
> then you would have made a True statement. But why should packages get
> this special treatment, and not renames of exceptions, or generics, or
> subprograms, etc.? We have "Ada is a name equivalence language unless
> the name is a renaming of a package".

I am really confused by your world view on this one.
I suspect someone else will have to pick up the discussion.

But let me try one more time.  Clearly renaming doesn't create a new entity,
though it does represent a new declaration, and a new view, but of the same entity.
This is independent of whether it is a package or any other kind of entity that
allows renaming.

Use-package clauses name a package *entity*, and it doesn't matter through which
renaming they do so. Use-package clauses make certain *declarations* directly
visible, those are the declarations that appear in the visible part of the use'd
package entity. The declarations affected might be package (renaming) declarations,
or any other kind of declaration, and they are all treated similarly -- package
declarations aren't a special case.

The *only* special case of which I am aware relative to "use" clauses is for the
package "entity" that is named in the use clause. That seems as it should be.

Now we can debate how this integrated package thing works, but I thought our
model was that use'ing an outer package effectively does "use"s of all of the
nested integrated packages. I have also proposed that the integrated package
declarations are *not* made directly visible by "use"ing the enclosing package,
sort of "in exchange" for their contents being made directly visible. This
latter part is clearly up for debate, but doesn't seem related to your issue of
"name equivalence."

By the way, I wouldn't say Ada has "name equivalence,"
but rather it has "declaration equivalence."  That is, it really doesn't matter
how you get to the declaration, but so long as two names denote the same declaration,
directly or through a rename, you are talking about the same thing.

Anyway, I get the sense I am missing the points you have been making, so I'll let
someone else take up the discussion from here if you think I am still way off base.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, May 27, 2009  8:08 PM

...
> I am really confused by your world view on this one.
> I suspect someone else will have to pick up the discussion.

I'm just trying to figure out why some renames are different than others wrt use
clauses. Apparently the only justification is "that's just the way it is".

It doesn't pay to argue about it further, simply because we aren't likely to make
any changes in this area, and surely we're not going to get more restrictive.

> But let me try one more time.  Clearly renaming doesn't
> create a new entity, though it does represent a new
> declaration, and a new view, but of the same entity.
> This is independent of whether it is a package or any other
> kind of entity that allows renaming.

Correct.

> Use-package clauses name a package *entity*, and it doesn't
> matter through which renaming they do so.  Use-package
> clauses make certain *declarations* directly visible, those
> are the declarations that appear in the visible part of the
> use'd package entity.  The declarations affected might be
> package (renaming) declarations, or any other kind of
> declaration, and they are all treated similarly -- package
> declarations aren't a special case.

You're saying that use clauses work on entities (not declarations), but they
make declarations (not entities) visible. Yeah, *that's* consistent.

It's clear to me from trying to make sense of the ASIS semantic subsystem that
any rules based on declarations alone make no sense at all -- because Ada has
lots of anonymous items that don't have declarations (well, I suppose they're
part of some unrelated declaration, but that's more confusing than helpful) --
and it has ways for entities to have multiple declarations. That way lies
madness - and apparently that's where we are. (We'll get an opportunity to go
into gory detail on the ASIS stuff, but not today...)

> The *only* special case of which I am aware relative to "use"
> clauses is for the package "entity" that is named in the use
> clause.  That seems as it should be.

That's either too many or too few.

...
> By the way, I wouldn't say Ada has "name equivalence,"
> but rather it has "declaration equivalence."  That is, it
> really doesn't matter how you get to the declaration, but so
> long as two names denote the same declaration, directly or
> through a rename, you are talking about the same thing.

As I noted above, that way lies madness. I'm not sure if I'm the one that has
gone mad (with Jean-Pierre's help vis-a-vis ASIS), but surely *someone* is
insane here!

Getting back to the original point: to say use-clause cancelation happens all
of the time unless two package renames are involved makes no sense whatsoever.
Either the cancelation should be canceled :-) whenever the same entity is referenced,
or never. I'd prefer the latter, but the former is more compatible.

> Anyway, I get the sense I am missing the points you have been
> making, so I'll let someone else take up the discussion from
> here if you think I am still way off base.

As I said, it doesn't really matter at this point. This is clearly an insanity
inherited from Ada 83, and never thought enough of to fix (unlike most of the
other insanities of Ada 83). Doesn't pay to get too worked up over it, so I'm
happy to agree to disagree (although I've still against further expansion of
these bugs, so in the absence of a fix I'm not voting for any new forms of use clause).

****************************************************************

From: Steve Baird
Sent: Tuesday, May 26, 2009  1:27 PM

Here are the updates to the AI that were discussed during the 5/20 call.
[This is version /04 of the AI - Editor.]

****************************************************************

From: Tucker Taft
Sent: Tuesday, May 26, 2009  2:15 PM

I had intended that the use-visibility rule would 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.

****************************************************************

From: Steve Baird
Sent: Tuesday, May 26, 2009  2:42 PM

Tuck - Understood. Does the correction below fix the problem?

Randy - here's a suggested update to the update (pending Tuck's ok):
   1) Replace
        "Tuck suggests that the name of an integrated package rename
         should not itself become ..."
      with
        "Tuck suggests that the name of an integrated package (whether a
         rename or not) should not itself become ... "

    2) Add the following before the paragraph that begins
       "As an aside ,,,":

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

       If there is general agreement on this point, then
       the two alternatives described below should be
       discarded because they only address the case of
       an integrated package rename.

[This was done in version /05 - Editor.]

****************************************************************

From: Tucker Taft
Sent: Tuesday, May 26, 2009  2:55 PM

That's fine.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, May 26, 2009  7:10 PM

> Here are the updates to the AI that were discussed during the 5/20 call.

You give the following example:

> Integrated package renames also make possible a number of odd corner cases:
>
>    limited with Foo;
>    package P is
>      use package Bar renames Foo;
>    end P;

One would hope that this is illegal, because we don't allow any other "use"
clauses on limited views of packages. I don't see any reason whatsoever for this
to be different. (The problems shown in this example illustrate why that's the
case.)

----

You give as an example:

   package Pkg is
      type T is tagged ... ;

      use package Inner is
         function Not_Primitive (X : T) return T;
      end Inner;
   end Pkg;

and mention that you would like to be able to make the name Not_Primitive
visible directly in Pkg. But this is exactly one of the sorts of effects that
bothers me about this proposal. Clients cannot ignore the presence of the nested
package, because its effects re-emerge periodically. This is one of those cases:
the primitiveness changes, so for the purposes of deriving a type from T, you
have to know the *real* structure of the package.

----

Similarly, consider another example from the AI:

   with Some_Container_Generic;
   package Pkg is
      use package Inner is
          type T is private;
      private
          ...;
      end Inner;

      use package I is new Some_Container_Generic (T);
   end Pkg;

if you have a limited with of Pkg:

    limited with Pkg;
    procedure Main is
        Obj : access Pkg.T; -- Illegal!
        Obj2 : access Pkg.Inner.T; -- Yuck.
    begin

the supposedly "integrated" package reappears.

This also happens when there are use-conflicts, even if those conflicts are
within a single package specification.

----

You can also name the inner package in a use-clause, giving visibility to only
part of the supposedly "integrated" whole. This seems bad from the view of a
client, which really wants to see a real, flat view of the package.

Part of the trouble here is the name of this construct: there is nothing really
"integrated" about these packages. It's really a way to force a use-clause on a
client. If they were really "integrated", we would see none of the unusual
effects seen here.

----

I realize that some differences from a fully flat package are going to be
required (else you could just declare everything without the nested package).
But some of these just seem outright wrong.

I have to wonder if we can do better. I don't recall anymore why we switched to
use-visibility for these things; it just seems wrong for many reasons. Perhaps
there is some way to avoid that??

****************************************************************

From: Steve Baird
Sent: Wednesday, May 27, 2009  11:49 AM

...
> One would hope that this is illegal, because we don't allow any other "use"
> clauses on limited views of packages. I don't see any reason
> whatsoever for this to be different. (The problems shown in this
> example illustrate why that's the case.)
>

It's not clear what this construct means, and that's the point (in the context
of discussing whether integrated package renames are desirable). I agree that
this probably should be illegal, but that doesn't fall out from the current
wording - an explicit rule would be needed.

> ----
>
> You give as an example:
>
>    package Pkg is
>       type T is tagged ... ;
>
>       use package Inner is
>          function Not_Primitive (X : T) return T;
>       end Inner;
>    end Pkg;
>
> and mention that you would like to be able to make the name
> Not_Primitive visible directly in Pkg. But this is exactly one of the
> sorts of effects that bothers me about this proposal. Clients cannot
> ignore the presence of the nested package, because its effects
> re-emerge periodically. This is one of those cases: the primitiveness
> changes, so for the purposes of deriving a type from T, you have to know the *real*
> structure of the package.
>

I agree, although I should point out that this example came up in a "real"
context; there was a serious question about how to accomplish this effect (an
implementation-defined Not_Primitive pragma was mentioned as a possible
solution).

Nobody is pretending that this construct produces identical results to doing the
"integration" by hand (although it is interesting to note that trying to rewrite
this particular example without using this new construct gets a little messy - I
think a subtype declaration is required).

> ----
>
> Similarly, consider another example from the AI:
>
>    with Some_Container_Generic;
>    package Pkg is
>       use package Inner is
>           type T is private;
>       private
>           ...;
>       end Inner;
>
>       use package I is new Some_Container_Generic (T);
>    end Pkg;
>
> if you have a limited with of Pkg:
>
>     limited with Pkg;
>     procedure Main is
>         Obj : access Pkg.T; -- Illegal!
>         Obj2 : access Pkg.Inner.T; -- Yuck.
>     begin
>
> the supposedly "integrated" package reappears.
>

I think the problems with limited views of integrated packages and package
renames are dwarfed to the point of insignificance by the existing treatment of
limited views of instantiations and of ordinary package renames (which I am not
arguing against).

Limited views (technical term) provide a very limited view (common English) of
things.

That's ok, we've accepted that.

As the AI mentions, we do have the option of relaxing this limitation and
allowing a limited view of an integrated package to be integrated in some cases
(not for renames, not for instances).

> This also happens when there are use-conflicts, even if those
> conflicts are within a single package specification.
>
> ----
>
> You can also name the inner package in a use-clause, giving visibility
> to only part of the supposedly "integrated" whole. This seems bad from
> the view of a client, which really wants to see a real, flat view of the package.

The point is that the client has the option of seeing a flat view of the
package. If the client wants to explicitly disambiguate a name by referencing
the inner package, that's up to the client. If you want to disallow this, it
could, I suppose, be detected by some coding-standard-enforcement tool; that is
outside of the scope of the language definition.

> Part of the trouble here is the name of this construct: there is
> nothing really "integrated" about these packages. It's really a way to
> force a use-clause on a client. If they were really "integrated", we
> would see none of the unusual effects seen here.

This is a relatively lightweight solution. The fact that it is based on
use-clauses definitely does show through in some cases.

On the other hand, if this solves the "exporting a private type and a container
thereof" problem (and I think it does), then that alone is a strong argument for
including this feature.

> ----
>
> I realize that some differences from a fully flat package are going to
> be required (else you could just declare everything without the nested
> package). But some of these just seem outright wrong.
>
> I have to wonder if we can do better. I don't recall anymore why we
> switched to use-visibility for these things; it just seems wrong for many reasons.
> Perhaps there is some way to avoid that??

It's often true that as we come to see the problems with one approach in more
detail, the path that we didn't take starts looking more and more attractive.

As you noted, the early discussions of this AI were based on implicit
rename/subtype declarations and had nothing to do with use clauses.

One problem with that approach was collisions. Implicit declarations of
non-overloadable constructs would have taken some work to straighten out.

Use-visibility provided a reasonable approach to resolving these issues that was
already a well-defined part of the language,

If you think we should revive the rename/subtype approach or even pursue an
entirely new solution, either
    a) provide a reasonably specific alternative that we can discuss or
    b) get more of a consensus from the group that we want to
       at least explore some other alternative and then I'll
       try to write something up.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, May 27, 2009  9:09 PM

...
> It's not clear what this construct means, and that's the point (in the
> context of discussing whether integrated package renames are desirable).
> I agree that this probably should be illegal, but that doesn't fall
> out from the current wording - an explicit rule would be needed.

Yes, of course such a rule is needed. I've been saying that repeatedly (see my
mail of December 18th, 2008 and March 12, 2009), and you've never added the rule
to the actual AI. Please do so (or at least explain what it means to not have
it).

Besides, this is a lousy example of why it is not desirable to allow renames.
The problem is simply that you have declarations appearing in a scope with no
sane way to determine where they come from.

But that also happens for instantiations, and I no longer see much difference
between "integrated" renamed packages, and "integrated" instantiations. So the
reason *I* was objecting to renames has become OBE (can't speak for others); the
more important question for me is whether this whole idea sacrifices too much
readability. (At least readability in the absence of a fancy IDE.)

...
> Limited views (technical term) provide a very limited view (common
> English) of things.

True enough; I've been trying to explain my discomfort with this proposal with
things that are different, but they don't necessarily seem important. That means
my overall point is getting lost.

...
> > You can also name the inner package in a use-clause, giving
> > visibility to only part of the supposedly "integrated" whole. This
> > seems bad from the view of a client, which really wants to see a real, flat view of the package.
>
> The point is that the client has the option of seeing a flat view of
> the package. If the client wants to explicitly disambiguate a name by
> referencing the inner package, that's up to the client. If you want to
> disallow this, it could, I suppose, be detected by some
> coding-standard-enforcement tool; that is outside of the scope of the
> language definition.

OK, here is the crux of the problem. As a package designer, I want to *limit*
the ways that the client can refer to things. Otherwise, package maintenance
becomes much harder. For instance, with this notion of "integrated" packages, it
would be impossible to change back to a "flat" structure (because there can be
references to the "integrated" package. Nor can you change to "integrated"
packages from a "flat" structure without introducing incompatibilities. That can
be bad.

> > Part of the trouble here is the name of this construct: there is
> > nothing really "integrated" about these packages. It's really a way
> > to force a use-clause on a client. If they were really "integrated",
> > we would see none of the unusual effects seen here.
>
> This is a relatively lightweight solution. The fact that it is based
> on use-clauses definitely does show through in some cases.

Yes, but you've missed my point completely. If you had called it something else
(say "automatically used packages"), I wouldn't have quite the same objections.
The *name* "integrated packages" gives an expectation of seamless merging; that
isn't happening here, so the *name* is causing (unreasonable?) expectations.

> On the other hand, if this solves the "exporting a private type and a
> container thereof" problem (and I think it does), then that alone is a
> strong argument for including this feature.

Surely we need *some* solution to this problem, but I'm not certain this one is
better than any of the other (now rejected) ideas.

...
> As you noted, the early discussions of this AI were based on implicit
> rename/subtype declarations and had nothing to do with use clauses.
>
> One problem with that approach was collisions. Implicit declarations
> of non-overloadable constructs would have taken some work to
> straighten out.

I think such collisions should simply be illegal. Tough if that prevents
declaring two container instances this way; we don't want homographs.

> Use-visibility provided a reasonable approach to resolving these
> issues that was already a well-defined part of the language,

Yes, I know, I was a strong advocate for pursuing this solution.

> If you think we should revive the rename/subtype approach or even
> pursue an entirely new solution, either
>     a) provide a reasonably specific alternative that we can discuss or
>     b) get more of a consensus from the group that we want to
>        at least explore some other alternative and then I'll
>        try to write something up.

Well, you know I don't have time to do either of these before the Brest meeting.
But I'm definitely going to try to block progress on this one until I have time
to do (a) or someone does (b). This proposal does not "feel right" to me.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, May 27, 2009  10:06 PM

> This proposal does not "feel right" to me.

Let me add that the reasons are not that obvious and surely this is no
reflection on the author of the proposal. (Part of the reason for complaining
now is the hope that Tucker or I or someone will have an inspiration before the
next meeting, that won't happen if the proposal is thought to be "good enough".)

Anyway, my concerns are almost exclusively focused on the client's view of a
package. I don't much care how complex the creation of a specification is, or
how much change is necessary to do something in the specification, so long as
the client view is controllable. But I would like the client view to be as close
as possible to a "flat" structure with all of the interesting declarations
appearing to exist in the outermost package.

This proposal comes close but doesn't quite make it.

---

One example that I've been thinking about is the proposed generic to provide
iterators. If we do decide to define that "magic" generic, we will need to
rearrange the Ada.Containers packages a lot to use it. But that rearrangement
would seem to be incompatible in a number of ways, and limiting on
implementation strategies to boot.

To refresh, assume that we have a magic iterator generic (this is simplified for
this example, as are the following packages) and we have Steve's "integrated
packages":

   generic
       type Cursor is private;
       No_Element : in Cursor;
   package Ada.Iterator_Interfaces is
       type Basic_Iterator is limited interface;
       function First (Object : Basic_Iterator) return Cursor;
       function Next (Object : Basic_Iterator; Position : Cursor) return Cursor;
   end Ada.Iterator_Interfaces;

[Note that the exact form of this generic doesn't matter much in terms of what
rearrangements need to be done to the Ada.Containers packages.]

Now, we currently have:

   generic
      type Element_Type is private;
   package Ada.Containers.Doubly_Linked_Lists is
      type List is tagged private;
      type Cursor is private;

      Empty_List : constant List;
      No_Element : constant Cursor;

      function Is_Empty (Container : List) return Boolean;
      procedure Clear (Container : in out List);
      function Element (Position : Cursor)
         return Element_Type;
      ...
   private
      ... -- not specified by the language
   end Ada.Containers.Doubly_Linked_Lists;

In order to add Basic_Iterator visibly to type List, we'll have to rearrange
this into using at least one nested package. The simplest I can come up with is:

   with Ada.Iterator_Interfaces;
   generic
      type Element_Type is private;
   package Ada.Containers.Doubly_Linked_Lists is
      use package Cursors is
         type Cursor is private;
         No_Element : constant Cursor;
      private
         ... -- not specified by the language
      end Cursors;

      package Iterators is new
          Ada.Iterator_Interfaces (Cursors, No_Element);

      type List is new Iterators with private;

      Empty_List : constant List;
      function Is_Empty (Container : List) return Boolean;
      procedure Clear (Container : in out List);
      function Element (Position : Cursor)
         return Element_Type;
      ...
   private
      ... -- not specified by the language
   end Ada.Containers.Doubly_Linked_Lists;

Limited with incompatibilities don't matter in this case, as you can't get a
limited view of a generic unit.

Primitiveness incompatibilities are definitely in evidence, but I do have to
wonder if it matters. In particular, if you derive from type Cursor currently,
you will inherit function Element. But you will no longer inherit that routine
with this rearrangement. I don't know how significant that is (I would suggest
it is not very significant).

Naming incompatibilities don't seem to be a problem with this example. They
could be if we wanted to remove the "integrated" nested package (as someone
could have named it explicitly in a use clause or in an expanded name). That's
not likely to be an issue in this case.

Since there is only two entities (plus the inherited "=") in the nested
packages, we could just rename them and not need any special construct at all.
But we'd still have the incompatibilities. (I did not expect this result when I
started writing this message.)

But there still is a significant issue. While we are not specifying what goes
into the private parts, we do need to be able to writ them. A cursor needs a
reference to a node and to the full container (the List in this example). The
node probably could be defined in the private part of package Cursors, but we
can't define a reference to List in the private part -- it hasn't been declared
yet! And it *can't* be declared yet, because it depends on the interface that we
haven't yet created.

One way to workaround this problem is to use a Taft-amendment type in the
private part of Cursors. But we can't complete that with the type List itself;
we'd have to use a derived type. And that is obnoxious, forcing many junk type
conversions. Even using class-wide types won’t get rid of those conversions,
because they would be toward the root of the tree.

Another possible workaround would be to clutter the spec with an incomplete type
List before the nested package. But that could not be completed with the private
extension List, so we would still end up with the same problem.

In conclusion, this rearrangement works, has some client incompatibility (but it
probably isn't important), but forces a major amount of junk type conversions in
the body of the package. Of course, this is only one example, and it would be
nice to look at additional examples in the future.

****************************************************************

From: Tucker Taft
Sent: Thursday, May 28, 2009  2:12 PM

> Another possible workaround would be to clutter the spec with an
> incomplete type List before the nested package. But that could not be
> completed with the private extension List, so we would still end up with the
> same problem.

This particular problem seems fixable.  The requirement that an incomplete type
declaration be completed with a full_type_declaration seems arbitrary.  There
seems no inherent reason that it couldn't be completed with a private type or
private extension declaration.


The incomplete types produced from a "limited with" allow that, so the mechanism
will be needed in Ada 2005 to handle such a completion anyway.

> In conclusion, this rearrangement works, has some client
> incompatibility (but it probably isn't important), but forces a major
> amount of junk type conversions in the body of the package. Of course,
> this is only one example, and it would be nice to look at additional examples
> in the future.

Normally I would have expected that almost the entire package would be included
in an "integrated" package, and then this big nested package would be followed
by various generic instantiations.  But you have illustrated a case where that
doesn't work, because you want one of the types to be built on the result of a
generic instantiation.  I wonder how common that is.

How would you do it without this feature?  As you point out, the integrated
package is mostly just a short-hand for a bunch of renames, and in this case,
there aren't that many.  Hiding the nested package name automatically from
use-visibility might be a helpful advantage of the proposed feature ;-).

It does seem the ability to define an incomplete type that is completed by a
partial view would be helpful, independent of this proposal.

I wonder if your "magic iterator" generic has this problem in general, and
perhaps it needs to be *defining* a cursor type, rather than taking it as a
parameter.  Or is it the fact that we want the container to be usable as an
iterator?  I think that is probably a bad idea in general, as it is inherently
problematic to have the container carry some state about a particular iterator
over the container.  I understand the desire for a *syntax* approximating:

     for Element in Container loop
        ...
     end loop;

But I see no requirement that this means we somehow have an iterator built into
the Container itself.  Also, we would certainly want to allow multiple tasks to
iterate over a Container in parallel, I would think, or to allow nested
iterators such as:

     for Left in Container loop
        for Right in Container loop
           Try_Pair(Left, Right);
        end loop;
     end loop;

I think the above *syntax* should always presume there is an anonymous iterator
object created, and that is what carries the state of the iteration.

In any case, I wonder whether it is the strange nature of this generic that is
creating the problem, or is there a common need to be able to define in a single
package two recursively-dependent types one of which is based on a generic
instantiation of the other. I suppose this is a very hard question to answer...

Thanks for the example!

****************************************************************

From: Randy Brukardt
Sent: Thursday, May 28, 2009  2:49 PM

...
> This particular problem seems fixable.  The requirement that an
> incomplete type declaration be completed with a full_type_declaration
> seems arbitrary.  There seems no inherent reason that it couldn't be
> completed with a private type or private extension declaration.
> The incomplete types produced from a "limited with" allow that, so the
> mechanism will be needed in Ada 2005 to handle such a completion
> anyway.

Yes, I in fact wrote this up originally assuming that such completions were
allowed. But before making a fool out of myself, I looked up the actual rules
and changed this part accordingly.

It would still clutter the spec a bit with an extra type declaration that
doesn't really have anything to do with anything other than the implementation,
but not a major problem overall.

> > In conclusion, this rearrangement works, has some client
> > incompatibility (but it probably isn't important), but forces a
> > major amount of junk type conversions in the body of the package. Of
> > course, this is only one example, and it would be nice to look at
> additional examples in the future.
>
> Normally I would have expected that almost the entire package would be
> included in an "integrated" package, and then this big nested package
> would be followed by various generic instantiations.  But you have
> illustrated a case where that doesn't work, because you want one of
> the types to be built on the result of a generic instantiation.  I
> wonder how common that is.

No idea. It seems to need interfaces to make much sense, so it would mainly
come up in new code.

> How would you do it without this feature?  As you point out, the
> integrated package is mostly just a short-hand for a bunch of renames,
> and in this case, there aren't that many.
> Hiding the nested package name automatically from use-visibility might
> be a helpful advantage of the proposed feature ;-).

I was surprised to find out that it doesn't seem to matter much either way; the
key is to use the nested package. Making it "integrated" is just icing.

> It does seem the ability to define an incomplete type that is
> completed by a partial view would be helpful, independent of this
> proposal.

Yes, I think so.

> I wonder if your "magic iterator" generic has this problem in general,
> and perhaps it needs to be *defining* a cursor type, rather than
> taking it as a parameter.

I don't know how that could work, given that container cursors include a
reference to the container object. I suppose the entire thing could be created
as a mix-in generic (adding to the container directly), but that seems annoying
(isn't that exactly the sort of thing that interfaces were created to avoid?).

> Or is it the fact that
> we want the container to be usable as an iterator?  I think that is
> probably a bad idea in general, as it is inherently problematic to
> have the container carry some state about a particular iterator over
> the container.

I strongly agree with this, but you need to convince Ed. :-) Maybe the rest of
your message will help.

> I understand the desire for a *syntax* approximating:
>
>      for Element in Container loop
>         ...
>      end loop;

I had proposed
    for Element in Container.Iterator loop
       ...
    end loop;
(where "Iterator" is a function returning an anonymous iterator object).
Since we're using that same sort of model for accessors (there is an "extra"
discriminant reference in those), I don't see the problem. But of course, I
was always happy with this formulation, it is other people that were not.

> But I see no requirement that this means we somehow have an iterator
> built into the Container itself.  Also, we would certainly want to
> allow multiple tasks to iterate over a Container in parallel, I would
> think, or to allow nested iterators such as:
>
>      for Left in Container loop
>         for Right in Container loop
>            Try_Pair(Left, Right);
>         end loop;
>      end loop;
>
> I think the above *syntax* should always presume there is an anonymous
> iterator object created, and that is what carries the state of the
> iteration.

With the accessor proposal, you have to write a single extra selection; that
seems fine to me for iterators, too. Since it would not be surprising to use
both of them together, it would actually be kinda weird to have simpler syntax
for the iterator and not the accessor:

    for Cursor in Container.Iterator loop
        Container.Accessor(Cursor).Element.Component := 10;
    end loop;

> In any case, I wonder whether it is the strange nature of this generic
> that is creating the problem, or is there a common need to be able to
> define in a single package two recursively-dependent types one of
> which is based on a generic instantiation of the other.  I suppose
> this is a very hard question to answer...

I would expect a similar problem any time that you wanted to define an interface
that needs customization with some properties. But it is hard to tell for sure,
other than to say that designers are clever and come up with structures that no
one expects.

****************************************************************

From: Bob Duff
Sent: Wednesday, June 17, 2009  4:16 PM

> Append to the existing !problem section
>
> 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)

The Pkg.I part seems clear to me.  If I declare an array-of-T at that point, the
array ops are visible to clients without any horsing around.  If I declare a
Vector or Linked_List of T, I want the same.

The "array" is the canonical container abstraction.  We should strive to make
other containers as much like it as possible.

>...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.
>
> -------
>
> In !discussion section, append to the discussion item beginning with
>
>     If it is decided that integrated package renames are not wanted, it
>     would be easy to remove them from the proposal.

For what it's worth, I am like the "renames" part of the proposal.
I don't buy the "it could be misused" argument.  Yes, it could.
But it can also be used well.  Just like many other features of Ada.

There may be issues with interactions with "limited with".  We need to deal with
that, but it doesn't kill the idea, for me.

> Append:
>
>     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.
>
>     Integrated package renames also make possible a number of odd corner cases:
>
>       limited with Foo;
>       package P is
>         use package Bar renames Foo;
>       end P;
>
>       package Outer is
>         package Inner is
>            use package Outer_Rename renames Outer;
>         end Inner;
>       end Outer;
>
>     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
                          ^^^^
needed

>     would be straightforward. This would include:
>        - eliminating the wording changes in 8.5.3
>        - replacing "integrated package or package renaming" with
>          "integrated package" throughout
>        - eliminating references to integrated package renamings
>          in the change appended after 8.4(11)
>
> --------
>
> Append a new !discussion grocery-list item after the

"grocery-list"?

> "if integrated package renames are not wanted" item:
>
>     Tuck suggests that the name of an integrated package rename
>     should not itself become "use"-visible when the enclosing package is "use"d.
>
>     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 a:
>            "use package <something> renames Ada.IO_Exceptions;"
>          in Text_IO, Sequential_IO, and Direct_IO.
>
>          However, what should the <something> be?  Well, most natural would be:
>            "use package IO_Exceptions renames Ada.IO_Exceptions;"
>
>          but now suppose you have:
>
>             with Ada.IO_Exceptions;
>             with Ada.Text_IO;
>         use Ada;
>         procedure What_Fun is
>            use Text_IO;
>              -- oops, IO_Exceptions suddenly disappears
>         begin
>             ...
>         exception
>             when IO_Exceptions.Name_Error =>
>                 -- oops, this doesn't compile any more!
>         end What_Fun;
>
>     If it is decided that this is what we want, then corresponding
>     wording would probably be fairly straightforward (as long as
>     we don't also require elegance, in which case the problem
>     may be overconstrained).

For what it's worth, I agree with Tucker on this point.

>     As an aside, note that the above example would be allowed if
>     "IO_Exceptions.Name_Error" were replaced with "Name_Error".
>
>     Another solution would be to allow anonymous integrated package
>     renames, as in
>        use package <> renames Ada.Io_Exceptions;
>     This would be equivalent to
>        use package Some_Identifier_That_Occurs_Nowhere_Else_In_The_Program
>          renames Ada.Io_Exceptions;
>     Anonymous non-renames seem like a bad idea, but perhaps anonymous
>     integrated renames would be ok?

Probably OK.

>     A third approach to this problem would be to add a name
>     resolution preference rule: if a package rename has the
>     same simple name as the renamed entity (which might or
>     might not itself be a rename), then prefer the renamed (and
>     similarly through chains of renames as long as the simple name
>     remains unchanged).
>     This would not introduce the sort of Beaujolais effects that
>     are typically associated with preference rules, but it does
>     seem that treating a simple-name-preserving rename differently
>     than a simple-name-nonpreserving rename might have some
>     peculiar consequences (e.g., there might be some odd interactions
>     with formal packages). This is probably a bad idea.

Why is it a bad idea?

In fact, why not extend it -- if name resolution produces a whole bunch of
interpretations that all mean the same thing, why not say "pick one at random"?

****************************************************************

From: Bob Duff
Sent: Wednesday, June 17, 2009  4:17 PM

> OK, here is the crux of the problem. As a package designer, I want to
> *limit* the ways that the client can refer to things. Otherwise,
> package maintenance becomes much harder. For instance, with this
> notion of "integrated" packages, it would be impossible to change back to a "flat"
> structure (because there can be references to the "integrated"
> package. Nor can you change to "integrated" packages from a "flat"
> structure without introducing incompatibilities. That can be bad.

I agree with Randy, here.  It doesn't kill the idea, for me, but it sure would
be nice if we could make this stuff more invisible.

The whole point is to make clients see a possibly-different structure than the
implementation of the abstraction.

>...This proposal does not "feel
> right" to me.

Well, to me it feels like "on the right track, but more work needed".

****************************************************************

From: Bob Duff
Sent: Wednesday, June 17, 2009  4:17 PM

> It's often true that as we come to see the problems with one approach
> in more detail, the path that we didn't take starts looking more and
> more attractive.

Yeah.  And then we fail to solve real user-painful problems, because every
proposed solution has some obscure language-lawyer problems.

Sigh.

****************************************************************

From: Bob Duff
Sent: Wednesday, June 17, 2009  4:16 PM

> You give as an example:
>
>    package Pkg is
>       type T is tagged ... ;
>
>       use package Inner is
>          function Not_Primitive (X : T) return T;
>       end Inner;
>    end Pkg;
>
> and mention that you would like to be able to make the name
> Not_Primitive visible directly in Pkg. But this is exactly one of the
> sorts of effects that bothers me about this proposal. Clients cannot
> ignore the presence of the nested package, because its effects
> re-emerge periodically. This is one of those cases: the primitiveness
> changes, so for the purposes of deriving a type from T, you have to know the *real* structure of the package.

How can that cause trouble?  I mean, when you call a procedure dispatchingly,
you get an error if it's not dispatching.

****************************************************************

From: Randy Brukardt
Sent: Thursday, June 18, 2009  11:27 AM

> How can that cause trouble?  I mean, when you call a procedure
> dispatchingly, you get an error if it's not dispatching.

Well, when writing (or debugging) your program, you will want to know whether or
not something is inherited. That's pretty important for *static* calls (as well
as dispatching calls), because calling Not_Primitive for an object of type Der_T
isn't going to work. Sure, you'll get an error if it doesn't work, but
compilation is hardly the time to find out that your design doesn't work. (And
it may be hard to figure out *why* you are getting an error from the call.)

It's even worse if you are use-adverse (like me) and name the routine with a
full expanded name. What that name is could change dramatically.

****************************************************************

From: Bob Duff
Sent: Thursday, June 18, 2009  1:37 PM

> Well, when writing (or debugging) your program, you will want to know
> whether or not something is inherited. That's pretty important for
> *static* calls (as well as dispatching calls), because calling
> Not_Primitive for an object of type Der_T isn't going to work. Sure,
> you'll get an error if it doesn't work, but compilation is hardly the
> time to find out that your design doesn't work.

Well, I can't get too excited about errors that are detected at compile time.

>... (And it may be hard to figure out *why* you are getting  an error
>from the call.)

True, it can.  That's annoying.  But it's still typically orders of magnitude
cheaper to fix than a bug that escapes into customer's hands.

> It's even worse if you are use-adverse (like me) and name the routine
> with a full expanded name. What that name is could change dramatically.

Well, I suppose if you're use-averse, you won't use "use package" much.

It's unfortunate that the Ada world is split into "use haters" and "use lovers",
but I don't see any solution to that problem.  (I'm somewhere in between, by the
way, and I change my mind toward either end of the spectrum, back and forth over
the years.)

****************************************************************

From: Randy Brukardt
Sent: Thursday, June 18, 2009  2:14 PM

We won't have any choice. "use package" (or whatever we come up with) will be
used in commonly used libraries (possibly including language-defined ones).
Ignoring it is somewhat of an option, but having the possibility of multiple
views harms maintenance and has an effect on compatibility.

I'd rather see a solution that "collapsed" the package completely so that the
clients have no visibility at all on the fact that nested packages are used. To
do that safely, we'd have to have a mechanism for preventing conflicts (one way
would be to make conflicts illegal, but that would be limiting), so as to avoid
the hiding problem that Erhard pointed out.

Maybe we need to go back to the <> package and look at other ways to eliminate
the hiding problem. Tucker wants to hide the name anyway, so it seems that the
package name is the least important part of the mechanism.

****************************************************************

From: Steve Baird
Sent: Friday, June 19, 2009  10:40 AM

>> Append a new !discussion grocery-list item after the
>
> "grocery-list"?
>

I think Randy once observed that some of my !discussion sections read like a
grocery list.

>>     A third approach to this problem would be to add a name
>>     resolution preference rule: if a package rename has the
>>     same simple name as the renamed entity (which might or
>>     might not itself be a rename), then prefer the renamed (and
>>     similarly through chains of renames as long as the simple name
>>     remains unchanged).
>>     This would not introduce the sort of Beaujolais effects that
>>     are typically associated with preference rules, but it does
>>     seem that treating a simple-name-preserving rename differently
>>     than a simple-name-nonpreserving rename might have some
>>     peculiar consequences (e.g., there might be some odd interactions
>>     with formal packages). This is probably a bad idea.
>
> Why is it a bad idea?
> In fact, why not extend it -- if name resolution produces a whole
> bunch of interpretations that all mean the same thing, why not say "pick one at random"?
>

Maybe you are right. This sounds like a fairly major change that would have to
be looked at very carefully. We'd want to preserve the "implicit rename" model
for the binding of generic actuals to formals.\ Do you think this is worth
looking into more closely?

Bob Duff wrote:
> Randy Brukardt wrote:
>
>> OK, here is the crux of the problem. As a package designer, I want to
>> *limit* the ways that the client can refer to things. Otherwise,
>> package maintenance becomes much harder. For instance, with this
>> notion of "integrated" packages, it would be impossible to change back to a "flat"
>> structure (because there can be references to the "integrated"
>> package. Nor can you change to "integrated" packages from a "flat"
>> structure without introducing incompatibilities. That can be bad.
>
> I agree with Randy, here.  It doesn't kill the idea, for me, but it
> sure would be nice if we could make this stuff more invisible.

One way to achieve this would be to allow anonymous packages even in the
non-rename case, as in

    package Outer is
        use package <> is
           ...;
        end <>;
    end Outer;

I don't think this interacts well with the use-visibility-based approach that we
have been discussing. There are times when use-visibility doesn't get you what
you want and you need the fallback mechanism of explicit qualification. This
construct would remove that option.

On the other hand, it sounds like removing the option of explicit qualification
is exactly what you and Randy want. It preserves the desired "flat" interface.

I had lunch with Pascal Leroy yesterday and we discussed this AI briefly. He
didn't claim to have looked at this one in depth, but he did observe that the
implicit-rename-declaration approach that was being considered initially seemed
more intuitive than the current approach that is based on use-visibility.

Do you think the rename-based approach would somehow help with this problem -
making these inner packages invisible while still allowing the user to name
everything that needs naming. As far as I can see the answer is "no", but I
thought I would raise the question.

****************************************************************

From: Tucker Taft
Sent: Friday, June 19, 2009  11:40 AM

The implicit rename and the use-visibility differ primarily only when there is a
conflict.  Implicit rename suffers from Beaujolais if you allow conflicts, while
use-visibility doesn't. I don't think we want to introduce Beaujolais effects,
so I presume we are talking a model where conflicts are illegal.

Perhaps a compromise might say that if you give a name, then conflicts are
permitted (and use-visibility rules apply), while if you don't give a name, then
conflicts are illegal, so it is more like the implicit rename model.

I suppose the other area of difference is primitiveness of operations.  I
thought it was a feature that you could get non-primitive operations to be
directly visible, essentially like those declared in the body. Perhaps the same
rule would apply: if you give a name, then the subprograms are *not* primitive
of a type in the enclosing scope, whereas if you use "<>" then the subprograms
*do* become primitives of such types.

****************************************************************

From: Tucker Taft
Sent: Wednesday, June 24, 2009  12:59 PM

Any comments on this thought of having "use package <> ..." follow renaming
semantics (with no conflicts permitted), and "use package Integrated ..." follow
transitive "use-visibility" semantics (with conflicts resolved in the use-ish
way, and a name available to disambiguate)?

****************************************************************

From: Randy Brukardt
Sent: Wednesday, June 24, 2009  1:10 PM

I have to wonder if we *really* need both. But if we do, the semantics you
suggest seem correct.

I'm pretty convinced that we need the nameless version because of all of the
reasons that have been previously noted about compatibility, the client view,
name space pollution, etc.

I'm less convinced that we need the named version if we have the nameless
version (because of those same reasons mentioned above), but I suppose there
might be significant use cases in its favor. It surely would be annoying if some
maintenance far away was to make a program illegal (by adding a conflict) and
there being no good way to avoid the problem.

BTW, if we do this, do we "fix" Text_IO to have
    use package <> renames Ada.IO_Exceptions; instead of the batch of individual
    renames of exceptions??

****************************************************************

From: Tucker Taft
Sent: Wednesday, June 24, 2009  1:40 PM

> I have to wonder if we *really* need both. But if we do, the semantics
> you suggest seem correct.

Good.  That's a start.

...
> BTW, if we do this, do we "fix" Text_IO to have
>     use package <> renames Ada.IO_Exceptions; instead of the batch of
> individual renames of exceptions??

Yes, that would make sense.

****************************************************************

From: Steve Baird
Sent: Wednesday, June 24, 2009  2:45 PM

I like the idea of guaranteeing that the name
    Enclosing_Package.Some_Entity
will resolve in precisely the case where we are taking away the fallback option of using the name
    Enclosing_Package.Named_Integrated_Package.Some_Entity
.

There are, however, the usual problems with having two very similar complex
constructs which are different in subtle but important ways.

This approach (deliberately) spoils the equivalence between
    use package <> ... ;
and
    use package An_Identifier_That_Occurs_Nowhere_Else ... ; , which seems
    potentially confusing.

Could we revisit the approach of allowing named and anonymous integrated
packages while unconditionally using "rename" semantics, perhaps allowing
collisions between renames (including constraintless subtypes) which denote the
same thing? In other words, throw out the whole use-clause-based approach?

When we first explored that approach, the problems with collisions looked pretty
bad. If, however, the alternative is the one you suggest (if it's named, use one
complicated model; if anonymous, use another), then maybe it is time to have
another look to see if those collision problems were really that bad.

--------

Would anonymous packages be limited to renames and instances? Perhaps only
renames?

I don't want to see "package body <> is".

--------

There may be problems with the rename approach and disallowing conflicts in the
case of an integrated instantiation. I'm thinking about child units of the
instantiated generic.

    generic
    package G1 is
    end G1;

    with G1;
    package Pkg is
       package <> is new G1;
       G2 : Integer;
    end Pkg;

    generic
    package G1.G2 is
    end G1.G2;

    with G1.G2;
    with Pkg;
    package Troublemaker is
       -- what is the story on Pkg.G2 here ?
    end Troublemaker;

Perhaps you only get implicitly declared renames of the items which are visible
in the integrated package spec at the point of the integrated package's
declaration.

--------

For anonymous packages, the <> identifier tells us everything we need to know
and the word "use" is redundant.

Would it make matters clearer or more confusing if we took advantage of this and
dropped the word "use" so that the syntax would be, for example,
    package <> renames Ada.IO_Exceptions; instead of
    use package <> renames Ada.IO_Exceptions; ?

If we decide that anonymous packages get "rename" rather than "use" semantics,
this might add weight to the argument for dropping the word "use" in that case.

If we decide that we are not going to support named integrated packages at all,
then it seems clear to me that there is no need for the word "use" in the
syntax.

****************************************************************

From: Tucker Taft
Sent: Wednesday, June 24, 2009  3:07 PM

I agree that we could drop the "use"
for the renaming-based semantics:

    package <> renames ...;

and perhaps

    package <> is new Gen_Pkg(...);

I had forgotten the problem of "package body <> is"
in generalizing this to handle integrated, non-rename, non-instance packages.  I
would hate to give up on the "normal" nested package case, as that was our
technique for solving the instantiating-with-private-type problem. I suppose we
could allow at most one such nested package, so the "package body <> is" would
be unambiguous.

Round and round we go... ;-)

****************************************************************

From: Steve Baird
Sent: Wednesday, June 24, 2009  4:07 PM

> I would hate
> to give up on the "normal" nested package case, as that was our
> technique for solving the instantiating-with-private-type problem.

I agree.

I would have to hear a very persuasive argument before I would be interested in
any design alternative for integrated packages that cannot be used to solve that
problem.

> I suppose we could allow at most one such nested package, so the
> "package body <> is" would be unambiguous.

Yuck. Requiring that the anonymous package cannot require
a body is also no good.

****************************************************************

From: Randy Brukardt
Sent: Thursday, June 25, 2009  9:38 PM

> > I suppose we could allow at most one such nested package, so the
> > "package body <> is" would be unambiguous.
>
> Yuck. Requiring that the anonymous package cannot require a body is
> also no good.

I'm not sure I understand "yuck" in this context. It seems that it makes sense
to allow only one anonymous package (of any kind) per scope, and thus there
couldn't be any confusion about which one has the body. That also would greatly
reduce the possibilities for conflicts and surely simplify the implementation of
checking for conflicts.

It's not like you could have a whole bunch of anonymous instances anyway: with
the "no conflicts" model, you are quickly going to hit some brick wall. For
instance, it would not be possible to have more than one anonymous instance of a
predefined container, because they all contain a constant No_Element (which is
not overloadable).

And it surely is obvious that you can only have one anonymous regular package.

So it might make sense to simply allow only one per scope to avoid confusion.

I doubt that this would be a major hardship, at least for the relatively simple
uses that we've envisioned. We're trying to be able to add a container to the
visible part of a package, not necessarily a whole flock of them.

Still, I suppose this makes it clear why we would want to continue to support
the named version as well -- the anonymous version would be limited in
applicability (but preferable if it could be used).

P.S. It's wonderful that no idea for fixing the instantiating-with-private-type
problem works for long, unless it is hard enough to use that everyone [other
than me and Brad :-)] rejects it. :-(

****************************************************************

From: Steve Baird
Sent: Thursday, June 25, 2009  9:59 PM

> I'm not sure I understand "yuck" in this context.

A rule that allows one "special" construct just seems a bit ugly to me. If we
are going to go down this route, I'd rather consider something equivalent to
(but hopefully better looking than)
    package <X> is
    end <X>;

    package <Y> is
    end <Y>;
so that the two (or more) anonymous packages cannot be named by an identifier,
but their completions can be disambiguated.

If we do decide to allow package bodies for anonymous packages, we still should
not allow such bodies to be separate; that would have too much impact on tools,
file naming conventions, etc.

****************************************************************

From: Randy Brukardt
Sent: Thursday, June 25, 2009  10:21 PM

You mean as in subunits and separate compilation? I think that follows from the
fact that we don't allow much for subunits: no overloading, no operators, no
name conflicts. I don't think we'd need to say anything at all, since we'd need
to *add* syntax to allow anonymous stubs -- and I can't imagine any reason for
doing that.

****************************************************************

From: Ed Schonberg
Sent: Friday, June 26, 2009  8:45 AM

> It's not like you could have a whole bunch of anonymous instances
> anyway:
> with the "no conflicts" model, you are quickly going to hit some brick
> wall.
> For instance, it would not be possible to have more than one anonymous
> instance of a predefined container, because they all contain a
> constant No_Element (which is not overloadable).

But a rule that says "you can only have one package"  will immediately strike
users as arbitrary. Why should I be able to define a single container in a spec?

> And it surely is obvious that you can only have one anonymous regular
> package.

Then that dooms anonymous packages.

>
> So it might make sense to simply allow only one per scope to avoid
> confusion.
>
> I doubt that this would be a major hardship, at least for the
> relatively simple uses that we've envisioned. We're trying to be able
> to add a container to the visible part of a package, not necessarily a
> whole flock of them.
>
> Still, I suppose this makes it clear why we would want to continue to
> support the named version as well -- the anonymous version would be
> limited in applicability (but preferable if it could be used).
>
>            Randy.
>
> P.S. It's wonderful that no idea for fixing the
> instantiating-with-private-type problem works for long, unless it is
> hard enough to use that everyone [other than me and Brad :-)] rejects
> it. :-(

If the central purpose of this AI is to ease the use of containers, then I think
AI05-74 (3)  namely deferred freezing rules for  instantiations deserves another
look.  It is a minimal change,   Discussion on it was sidetracked by other
concerns, but I have not seen crippling arguments against it. Steve has proposed
a pragma to prevent contract issues, what are the big objections to this?

****************************************************************

From: Tucker Taft
Sent: Friday, June 26, 2009  9:02 AM

My objection to Steve's proposal is precisely because it relies on a pragma.  I
believe whatever we do deserves some kind of distinguishing syntax.

Note that my suggestion was that we would only allow at most one integrated,
anonymous non-instance, non-rename package. There seems no difficulty allowing
any number of anonymous instances/renamings, as these don't need bodies. Also,
there seems no difficulty in allowing any number of named non-instance,
non-rename integrated packages.

Allowing only one "normal" nested package to be anonymous seems pretty
reasonable.  The only reason for making a nested package anonymous and
integrated seems to be to provide for freezing uses of private types within the
enclosing package.  It doesn't seem like you would need more than one such
anonymous nested package in typical scenarios.

****************************************************************

From: Steve Baird
Sent: Friday, June 26, 2009  9:32 AM

> But a rule that says "you can only have one package"  will immediately
> strike users as arbitrary.

I agree.

> Allowing only one "normal" nested package to be anonymous seems pretty
> reasonable.  The only reason for making a nested package anonymous and
> integrated seems to be to provide for freezing uses of private types
> within the enclosing package.  It doesn't seem like you would need
> more than one such anonymous nested package in typical scenarios.

What about a package that wants to export two private types, as in

    package Pkg is
       package <anonymous 1> is
           type T1 is private;
           -- primitive operations of T1;
       end <anonymous 1>;

       package T1_Containers is new Some_Container_Generic (T1);

       package <anonymous 2> is
          type T2 is private;
          -- primitive operations of T2, perhaps
          -- involving parameters of type T1_Container.Some_Type
       end <anonymous 2>;

       package T2_Containers is new Some_Container_Generic (T2);
    end Pkg;

?

****************************************************************

From: Tucker Taft
Sent: Friday, June 26, 2009  12:22 PM

I believe the following would work:

    package Pkg is

       package <> is
          package <> is
              type T1 is private;
              -- primitive operations of T1;
          end <>;

          package T1_Containers is new Some_Container_Generic (T1);
          type T2 is private;
          -- primitive operations of T2, perhaps
          -- involving parameters of type T1_Container.Some_Type
       end <>;

       package T2_Containers is new Some_Container_Generic (T2);
    end Pkg;

I believe it is possible to show that by nesting package <>, you can achieve
whatever you want.

Of course, this is now the moral equivalent of allowing multiple visible parts,
separated by private/end-private.

****************************************************************

From: Randy Brukardt
Sent: Friday, June 26, 2009  12:25 PM

> If the central purpose of this AI is to ease the use of containers,
> then I think AI05-74 (3)  namely deferred freezing rules for
> instantiations deserves another look.  It is a minimal change,
> Discussion on it was sidetracked by other concerns, but I have not
> seen crippling arguments against it. Steve has proposed a pragma to
> prevent contract issues, what are the big objections to this?

I agree with Tucker that we don't want something so fundamental to be a pragma.
Syntax would be preferred.

Steve also had a number of "Baird cases" which complicated the model
considerably (just as in anonymous packages, use package, and all of the other
ideas that we've looked at).

Finally, there is nothing "minimal" about this change. It would be an
implementation earthquake in Janus/Ada (since we share both the spec and body of
generics, and depend heavily on freezing to prevent problems). And it would add
some conceptual complexity to generics (now there would be two different sets of
freezing rules for them)

I continue to prefer a version of the "forward instantiation" (probably
exporting limited views) as the best solution, but I admit that we've never
found a syntax which makes sense both from the client view (where the forward
instance looks like a normal instance) and from the local package view (where
the forward instance is special). Note that the proposed extension of uses of
incomplete types would also have the effect of making this idea much more
powerful.

Brad has been exploring variations on this theme, perhaps he's found the perfect
solution while we weren't paying attention.

****************************************************************

From: Robert Dewar
Sent: Friday, June 26, 2009  12:34 PM

> Finally, there is nothing "minimal" about this change. It would be an
> implementation earthquake in Janus/Ada (since we share both the spec
> and body of generics, and depend heavily on freezing to prevent
> problems). And it would add some conceptual complexity to generics
> (now there would be two different sets of freezing rules for them)

I think we should get an estimate of implementation impact from multiple
implementations before we decide on this feature. I am dubious, seems like the
motivation here comes from the designers rather than users, but I may be wrong
on this, do we have cases of large scale users complaining about this missing
functionality?

> I continue to prefer a version of the "forward instantiation"
> (probably exporting limited views) as the best solution, but I admit
> that we've never found a syntax which makes sense both from the client
> view (where the forward instance looks like a normal instance) and
> from the local package view (where the forward instance is special).
> Note that the proposed extension of uses of incomplete types would
> also have the effect of making this idea much more powerful.
>
> Brad has been exploring variations on this theme, perhaps he's found
> the perfect solution while we weren't paying attention.

I sure share the feeling that we could find some better solution here, but i
realize the search has not been fruitful so far.

****************************************************************

From: Ed Schonberg
Sent: Friday, June 26, 2009  12:51 PM

> I agree with Tucker that we don't want something so fundamental to be
> a pragma. Syntax would be preferred.

I don't understand this comment: if a pragma is sufficient, then it is NOT a
fundamental change, and there is very little to add to the RM.  Looks like a
plus to me.

> Steve also had a number of "Baird cases" which complicated the model
> considerably (just as in anonymous packages, use package, and all of
> the other ideas that we've looked at).

I trust that Steve will provide other admirably  byzantine examples on any
solution, but the ones I have seen are no worse than for integrated packages.

> Finally, there is nothing "minimal" about this change. It would be an
> implementation earthquake in Janus/Ada (since we share both the spec
> and body of generics, and depend heavily on freezing to prevent
> problems). And it would add some conceptual complexity to generics
> (now there would be two different sets of freezing rules for them)

Sorry, implementation difficulties are minor objections if we can get the
language right. The change in freezing rules will add a few lines to 13.14. In
comparison, integrated packages (named and anonymous) will require plenty of
text in the RM and AARM to explain why they are there, when they should be used,
why they are preferable (perhaps) to child units, etc.

> I continue to prefer a version of the "forward instantiation"
> (probably exporting limited views) as the best solution, but I admit
> that we've never found a syntax which makes sense both from the client
> view (where the forward instance looks like a normal instance) and
> from the local package view (where the forward instance is special).
> Note that the proposed extension of uses of incomplete types would
> also have the effect of making this idea much more powerful.
>
> Brad has been exploring variations on this theme, perhaps he's found
> the perfect solution while we weren't paying attention.

OK, worth looking at in more detail.

****************************************************************

From: Robert Dewar
Sent: Friday, June 26, 2009  1:05 PM

> Sorry, implementation difficulties are minor objections if we can get
> the language right. The change in freezing rules will add a few lines
> to 13.14. In comparison, integrated packages (named and anonymous)
> will require plenty of text in the RM and AARM to explain why they are
> there, when they should be used, why they are preferable (perhaps) to
> child units, etc.

We have *never* taken the position that implementation difficulties are to be
ignored, and we shouldn't start now. I would like to see at the minimum an
analysis from AdaCore, Tuck, and Rational on forseen implementation
difficulties, given this is a non-critical feature. I say it is non-critical,
since I don't see its absence as having a significant effect on Ada adoption.

To me, at this stage, EVERY proposal for language change should include an
analysis of impact on implementations.

****************************************************************

From: Randy Brukardt
Sent: Friday, June 26, 2009  3:48 PM

> > I agree with Tucker that we don't want something so fundamental to
> > be a pragma. Syntax would be preferred.
>
> I don't understand this comment: if a pragma is sufficient, then it is
> NOT a fundamental change, and there is very little to add to the RM.
> Looks like a plus to me.

I don't understand this comment: there is a massive amount of semantic change
(at a minimum concerning freezing and elaboration) behind this difference. All
of this change clearly violates good taste in pragmas. You could argue that
there are a number of existing pragmas that also violate this good taste, but I
don't think that two wrongs make a right. Just because we screwed up in the past
does not mean that we should do so again.

Note that we considered and rejected pragma-based solutions in a number of other
areas; this doesn't seem that different to me.

> > Steve also had a number of "Baird cases" which complicated the model
> > considerably (just as in anonymous packages, use package, and all of
> > the other ideas that we've looked at).
>
> I trust that Steve will provide other admirably  byzantine examples on
> any solution, but the ones I have seen are no worse than for
> integrated packages.

That's possible; I was just skimming the e-mail in the AI, and it showed a
number of new interactions that would have to be addressed (presumably with
additional rules).

> > Finally, there is nothing "minimal" about this change. It would be
> > an implementation earthquake in Janus/Ada (since we share both the
> > spec and body of generics, and depend heavily on freezing to prevent
> > problems). And it would add some conceptual complexity to generics
> > (now there would be two different sets of freezing rules for them)
>
> Sorry, implementation difficulties are minor objections if we can get
> the language right. The change in freezing rules will add a few lines
> to 13.14. In comparison, integrated packages (named and anonymous)
> will require plenty of text in the RM and AARM to explain why they are
> there, when they should be used, why they are preferable (perhaps) to
> child units, etc.

Robert made the point about implementation better than I could have.

I think you are dreaming if you think that only "a few lines [in] 13.14" are
needed here. No significant proposal, no matter how apparently simple, ends up
that easy. In this case, we surely will have to make changes in the elaboration
rules for instances, define the syntax (or pragma) that enables these semantic
changes, and add additional rules to fix the interactions that Steve pointed
out. We may also want to use the new feature in some of the existing predefined
packages. I would be very, very surprised if the number of changes were less
than those needed in Steve's latest draft of AI05-135 (which seems to cover
everything required for "integrated packages" with the exception of use in
existing predefined packages). In any case, explaining "why they are there" and
especially "why they are preferable" belongs in textbooks (and the AI), not the
standard and is pretty much irrelevant to any discussion of the size of a change
to the language.

****************************************************************

From: Brad Moore
Sent: Saturday, June 27, 2009  5:35 PM

> If the central purpose of this AI is to ease the use of containers,
> then I think AI05-74 (3)  namely deferred freezing rules for
> instantiations deserves another look.  It is a minimal change,
> Discussion on it was sidetracked by other concerns, but I have not
> seen crippling arguments against it. Steve has proposed a pragma to
> prevent contract issues, what are the big objections to this?

My concern regarding the pragma approach is that I think we should avoid putting
things (pragmas) in the "server" (the generic package), that makes assumptions
about how the "client" will want to use the package. If we went with this
approach, then I envision the next incarnation of the Ada style guide (hopefully
we will see someday) would be modified to say, "Use this new pragma everywhere
on every new generic if at all possible, and do not declare variables or
expressions in the generic specs, unless you can provide strong justifications,
otherwise you may be limiting the reuse possibilities for your generic code."

This also seems like a maintenance problem. If the maintenance of a generic
package needs to add a variable declaration or expression to the package, (and
thereby remove the special pragma) then this could break clients, which may not
notice the change until the next time a build for a particular program is
executed. By then other clients may be dependent on the newer version of the
generic code.

Basically, I don't think we want to go there.

My thoughts were that it is better to not change the way generics work. (i.e.,
no restrictions on declaring variables or expressions), and instead put any
restrictions needed to prevent problems in the client. This is why I do not have
any such pragma in my most recent proposal. (It isn't in my most recent version
of AI05-0074-4 either, though earlier incarnations did have it, as I originally
"borrowed" the idea from AI05-0074-3)

I haven't thought too much about whether AI05-0074-3 could be reworked, in a
manner similar to AI05-0074-5? to eliminate the pragma, though I think
*something* (whether it be syntax or pragma) is needed to distinguish between
this usage and a normal instantiation.

****************************************************************

From: Robert Dewar
Sent: Saturday, June 27, 2009  5:42 PM

> This also seems like a maintenance problem. If the maintenance of a
> generic package needs to add a variable declaration or expression to
> the package, (and thereby remove the special pragma) then this could
> break clients, which may not notice the change until the next time a
> build for a particular program is executed. By then other clients may
> be dependent on the newer version of the generic code.

I don't really see this point. ANY change to ANY package may break clients, and
surely you don't go changing a generic spec without a lot of discussion and
testing if it is in general use.

****************************************************************

From: Randy Brukardt
Sent: Saturday, June 27, 2009  6:08 PM

As a pragma, I agree with Brad, simply because this pragma would violate "good
taste in pragmas". We recently added some discussion to the AARM to explain what
good taste is (see 2.8(1.a/3) or AI05-0100-1 if you don't have the draft 7 AARM
handy). In particular, removing a pragma from a legal program should not make
the program illegal, and this proposed pragma would have that effect. (Adding a
pragma can make a legal program illegal, however.)

If we are talking about syntax instead, however, I agree with Robert. It would
be amazing to make major changes to the syntax of a package specification
(generic or not) and expect clients to be unaffected. So I don't find this point
to be very compelling.

The style guide issue doesn't bother me much, either; it seems to be a good
practice to avoid this stuff in the specification anyway (it causes too much
coupling), so a style requiring that doesn't seem that terrible. There is plenty
of stuff that Ada allows you to do that you should really avoid.

I definitely agree that there needs to be syntax somewhere to distinguish this
special case from the more normal rules, for compatibility if for no other
reason. (Whatever special case we decide on.)

****************************************************************

From: Robert Dewar
Sent: Saturday, June 27, 2009  6:19 PM

> As a pragma, I agree with Brad, simply because this pragma would
> violate "good taste in pragmas". We recently added some discussion to
> the AARM to explain what good taste is (see 2.8(1.a/3) or AI05-0100-1
> if you don't have the draft 7 AARM handy). In particular, removing a
> pragma from a legal program should not make the program illegal, and
> this proposed pragma would have that effect. (Adding a pragma can make
> a legal program illegal,
> however.)

Well i can't get too excited about that, since we already have pragmas that are
in bad taste from this point of view. I don't really mind if these are language
defined pragmas, actually come to think of it I don't mind at all. Language
definitions should not be in the business of defining what is "good taste" in
any case, so anything like that in the standard is going to be ignored by me
anyway. We design pragmas to be useful, not to meet some committee's idea of
what is good taste :-) :-) If you think a pragma is in bad taste, you don't have
to use it!

> If we are talking about syntax instead, however, I agree with Robert.
> It would be amazing to make major changes to the syntax of a package
> specification (generic or not) and expect clients to be unaffected. So
> I don't find this point to be very compelling.

OK, well new syntax is fine by me too, though of course it is always more
troublesome in practice.

****************************************************************

From: Randy Brukardt
Sent: Saturday, June 27, 2009  6:46 PM

> Well i can't get too excited about that, since we already have pragmas
> that are in bad taste from this point of view. I don't really mind if
> these are language defined pragmas, actually come to think of it I
> don't mind at all. Language definitions should not be in the business
> of defining what is "good taste" in any case, so anything like that in
> the standard is going to be ignored by me anyway. We design pragmas to
> be useful, not to meet some committee's idea of what is good taste
> :-) :-) If you think a pragma is in bad taste, you don't have to use
> it!

That's not really true for language-defined pragmas. Pragma Import is a pragma
in bad taste, but it's pretty much impossible to avoid using it (as much as I'd
like to). Imagine trying to write Claw without using pragma Import! :-)

> > If we are talking about syntax instead, however, I agree with Robert.
> > It would be amazing to make major changes to the syntax of a package
> > specification (generic or not) and expect clients to be unaffected.
> > So I don't find this point to be very compelling.
>
> OK, well new syntax is fine by me too, though of course it is always
> more troublesome in practice.

It can't be that much more troublesome, if you've already managed to implement
conditional expressions. :-) :-)

Seriously, syntax has a bit more impact on tools than a pragma would, but
otherwise it isn't much different. I prefer either to just changing the
semantics of something, which leads to all kinds of complications both in
implementation and in use.

****************************************************************

From: Robert Dewar
Sent: Saturday, June 27, 2009  6:50 PM

> As a pragma, I agree with Brad, simply because this pragma would
> violate "good taste in pragmas". We recently added some discussion to
> the AARM to explain what good taste is (see 2.8(1.a/3) or AI05-0100-1
> if you don't have the draft 7 AARM handy). In particular, removing a
> pragma from a legal program should not make the program illegal

This really isn't vaguely true for existing pragmas!

For example, removing pragma Pack often makes a program illegal.

Removing a pragma Import almost certainly makes a program illegal.

Removing a pragma Convention can easily make a program illegal

Removing a pragma Pure, Preelaborate, or any of the other categorization pragmas
can make a program illegal.

Removing a pragma Elaborate can make a program illegal same of course with
Elaborate_All and Elaborate_Body.

Removing a pragma Atomic or Volatile can make a program illegal.

There aren't that many pragmas defined in the RM, and as we see many of them are
in "bad taste" :-)

Once we have done such a bad job of following our own bad taste rules, I can
hardly get upset at adding one more.

And since the language is so free in adding these bad taste pragmas (note that
most of these were added in Ada 95), I see no reason for implementors to feel
bound to stricter standards.

I guess to me, it is MUCH worse when removing a pragma can cause the progam to
become erroneous, or malfunction in mysterious ways. Ilegality is a nice outcome
of improperly removing a pragma compared to these alternatives!

Notionally if an implementation has only "good taste" pragmas, then you can
remove them all or ignore them all, and the program is still legal. But so what?
Pragmas are not there for amusement purposes, almost certainly they are
important to the correct functioning of the program. If you have a GNAT program
that uses pragma Weak_External, sure you can remove it and the compiler will
consider the program legal, but good luck at link time :-) And if you remove a
pragma Wide_Character_Encoding, it will be quite surprising if you can still
compile your source :-)

[Most of the rest of the pragmas thread can be found in AI05-0163-1. - Editor.]

****************************************************************

From: Robert Dewar
Sent: Saturday, June 27, 2009  6:59 PM

> It can't be that much more troublesome, if you've already managed to
> implement conditional expressions. :-) :-)

I am not concerned with implementation difficultioes, obviously it does not
matter two hoots to the implementation whether something is syntax or pragmas,
to an implementation, a pragma *is* syntax.

I was concerned about incompatibilities, certainly for instance introducing new
keywords has serious impacts. And new syntax is far more likely to cause trouble
with tools like pretty printers, syntax oriented editors, ASIS etc.

> Seriously, syntax has a bit more impact on tools than a pragma would,
> but otherwise it isn't much different. I prefer either to just
> changing the semantics of something, which leads to all kinds of
> complications both in implementation and in use.

Definitely I agree on that, the change to returning limited types caused chaos
for our users, and delayed many of them in moving to Ada 2005.

****************************************************************

From: Brad Moore
Sent: Sunday, June 28, 2009  12:51 AM

> If we are talking about syntax instead, however, I agree with Robert.
> It would be amazing to make major changes to the syntax of a package
> specification (generic or not) and expect clients to be unaffected. So
> I don't find this point to be very compelling.
>
> The style guide issue doesn't bother me much, either; it seems to be a
> good practice to avoid this stuff in the specification anyway (it
> causes too much coupling), so a style requiring that doesn't seem that
> terrible. There is plenty of stuff that Ada allows you to do that you should really avoid.

I agree that both these points are not serious, show-stopper type problems. We
could certainly live with them if we had to. I guess my point is that regardless
how serious these are, they can still be viewed as being negatives. If we can
achieve more or less the same thing without the negatives, then that may be even
more desirable.

****************************************************************

From: Brad Moore
Sent: Sunday, June 28, 2009  12:33 PM

> I agree with Randy that we should avoid using pragmas that make things
> legal that would otherwise be illegal (ignoring representational issues).
> Yes we have some such pragmas now, but there are few, and it was back
> in Ada 9X that we established this principle and did our best to stick
> with it.
> I don't like to see us slipping backwards now.

I also think there is something to be said for having the distinguishing syntax
(or pragma if we must) at the site of where we want the benefits of that syntax.
i.e., close to the instantiation in the unit that wants to instantiate a generic
using a private type, rather than in the generic unit being instantiated.

For example, I still see a maintenance problem. If a client discovers a need to
instantiate some existing generic using a private type, modifying the generic to
add the pragma may not be an option, if the generic is in a unit supplied by a
3rd party vendor, or if removing any existing declarations or expressions in the
generic would break too many other clients.

****************************************************************

From: Robert Dewar
Sent: Sunday, June 28, 2009  12:43 PM

makes sense to me!
though the devil is in the details for something like this.

****************************************************************

From: Brad Moore
Sent: Friday, July 10, 2009  10:47 AM

I have another approach for addressing the private type instantiation issue.

On the surface, it appears to have a lot of the desirable qualities of the
integrated packages solution, but without some of the not so desirable
qualities.

I think it is the implicitness of the integrated package solution that is
generating some uneasiness. It is the implicitness that led us to look (so far
unsuccessfully) at the anonymous package idea as a means of avoiding conflicts.

I also think it is desirable if we can make it more explicit about which
services we want to export from the instantiation.

What if instead we allowed type renames to solve this issue?

The idea is that the type rename would export all operations involving that type
from the inner package (or instance).

For enumeration types, this would export all the literals of the enumeration.

This gives the client the ability to provide a name for the type, thus avoiding
conflicts, and eliminates the need to look at the equivalence of the anonymous
packages idea.

If you want to export a subprogram that involves more than one type declared in
the inner package, (or instance), then you would need to also declare a type
rename for those other types. (or otherwise be required the name to be qualified
to reference the  inner type).

eg.

with Ada.Containers.Doubly_Linked_Lists;
with Ada.Containers.Vectors;
package P is

   package Nested is
      type T is private;
   private
      type T is ...;
   end Nested;

   type R renames Nested.T; -- R makes T available outside Nested

   package Lists is new Ada.Containers.Doubly_Linked_Lists (R);

   -- Make the Lists services directly available in package P;
   type List renames Lists.List;
   type Iterator renames Lists.Cursor;
   No_List_Element renames Lists.No_Element;

   -- Another instantiation without any conflicts
   package Arrays is new Ada.Containers.Vectors
      (Index_Type => Natural, Element_Type => R);
   type Array renames Arrays.Vector;
   type Array_Cursor renames Arrays.Cursor;
   No_Array_Element renames Arrays.No_Element;

end P;

with P;
procedure Q is
  My_List : P.List; -- Really is P.Lists.List
  My_Cursor : P.Iterator; -- Really P.Lists.Cursor
  My_R : P.R;  -- Really P.Nested.T
begin
  My_List.Append (My_R); -- Really P.Lists.Append
  My_Cursor := My_List.First;
end Q;

The integrated package idea also would export object declarations and exception
declarations.

This solution probably wouldn't export object declarations, and would not export
exception declarations since those are not tied to type declarations, but having
to explicitly rename those might be considered a good thing.

Is this idea worth developing further?

****************************************************************

From: Steve Baird
Sent: Friday, July 10, 2009  12:05 PM

> What if instead we allowed type renames to solve this issue?
>
> The idea is that the type rename would export all operations involving
> that type from the inner package (or instance).
>

This would certainly be a heck of a lot simpler than integrated packages.

It is less general, but if it is powerful enough to solve the problems that
integrated packages were intended to solve, then that's all we need.

Having two similar-but-slightly-different constructs in the language (i.e.
"subtype S is Pkg.T;" vs. "type S renames Pkg.T;") may be confusing to some
users at first, but is this any worse in this respect than subtypes vs. derived
types or qualified expressions vs. type conversion?

> Is this idea worth developing further?

I think so.

The first question that comes to my mind is whether there are problems that need
solving for which (some version of) integrated packages provide a solution and
this proposal does not.

****************************************************************

From: Ed Schonberg
Sent: Friday, July 10, 2009  12:20 PM

> Having two similar-but-slightly-different constructs in the language
> (i.e. "subtype S is Pkg.T;" vs. "type S renames Pkg.T;") may be
> confusing to some users at first, but is this any worse in this
> respect than subtypes vs. derived types or qualified expressions vs.
> type conversion?

In fact, three constructs:

subtype S is Pkg.T;

type T is new Pkg.T;  -- with null record when needed

type T renames Pkg.T;  --  whose semantics is not that different from the
                       --  previous one.

****************************************************************

From: Randy Brukardt
Sent: Friday, July 10, 2009  1:50 PM

> It is less general, but if it is powerful enough to solve the problems
> that integrated packages were intended to solve, then that's all we
> need.

Wasn't that the original idea that eventually led to the integrated package
idea? I thought we previously explored that possibility.

I recall that Bob Duff was very much against it, claiming that there is lots of
other stuff (like exceptions, and sometimes enumeration types) that need to come
along with the primitive operations of a type. That's why we eventually
gravitated to a package-based solution.

Of course, it's worthwhile to look back at other solutions, because we still
aren't happy with what we've got. But I'd expect the basic objections to remain.

****************************************************************

From: Steve Baird
Sent: Friday, July 10, 2009  2:11 PM

What may have changed is the magnitude of the objections to the other available
alternatives.

If we conclude that integrated packages are a complicated mess (and I am not
quite ready to concede that point), then alternatives that we originally
discarded may start looking better.

****************************************************************

From: Brad Moore
Sent: Friday, July 10, 2009  5:29 PM

> The first question that comes to my mind is whether there are problems
> that need solving for which (some version
> of) integrated packages provide a solution and this proposal does not.

Well I can think of one other problem this would solve that the integrated
packages solution does not solve.

The issue about not being able to derive from a synchronized tagged when you
want a primitive subprogram that returns an access to an element of the
instantiation.

With the ability to rename a type, you would not need to derive a new type. I
think. Hopefully we would be allowed to complete an incomplete type with a
renamed type.

e.g.

   with Generic_Synchronized_List_Package;

   package Pkg is
      type List_Type;

      package Nested is
        type T is private;
      private
        type T is
          record
            List : access List_Type;
          end record;
      end Nested;

      type R renames Nested.T;

      package I is new Generic_Synchronized_List_Package (R);

      -- type List_Type is new I.List with null record;
      -- ERROR Cannot derive if I.List is a synchronized tagged type

      type List_Type renames I.List; -- This should work, hopefully

   end Pkg;

****************************************************************

From: Tucker Taft
Sent: Friday, July 10, 2009  9:09 PM

The problem I see is that a package involves more than a type and its
operations.  A package defines nested generics, exceptions, objects, etc.  As it
is now, when you use the idiom of instantiating a package and then defining a
derived type to get the operations to be direct components of the outer package,
you have to know that the nested generics, etc., are not direct components, but
still require the extra level of selection.  In some way the renaming would
help, in that you could use the nested generics and the objects without having
to throw in some conversions to "undo" the type derivation.  But that is really
only solving half of the problem.

I really think the ability to "integrate" a generic instantiation has a lot of
value on its own.

Being able to "integrate" an arbitrary package seems useful, but less so.  Being
able to integrate a directly declared nested package is definitely just a
"trick" in my view, and I have become reinterested in the "end private" approach
as preferable to the "package <> is ... end <>;"

****************************************************************

From: Steve Baird
Sent: Thursday, October 29, 2009  7:40 PM

I have an action item from Brest to do something with this AI, so here we go.

Based on the discussions since Brest, it seems that we have two major questions
to resolve:

   1) Anonymous vs. named integrated packages. Should the
      non-integrated view of an integrated package be
      nameable? Should we support both ways?

   2) Implicit rename declarations vs. use-visibility.
      Do we want to (in some cases, at least) go with
      implicit renames, possibly with the addition of
      some rules to allow collisions between homographic
      renames of the same thing?

As with any AI, there is also the question of "should we do nothing?". Doing
nothing could only make sense if we adopt some other solution to the early
instantiation problem.

The current writeup of the AI has named integrated packages and use-visibility.

As an alternative, I'll sketch out the opposite combination, anonymous
integrated packages with implicit renames.

I would like to reach a consensus regarding which direction we want to proceed
with this one.

I'm leaning towards named packages (when you make something anonymous, you
discover later that you want to name it) with implicit rename declarations.

========

!proposal
A package or package rename which is declared immediately within the visible
part of an enclosing package may be declared with a non-identifier in place of
the package identifier. This may be either "<>" or a bracketed identifier such
as "<Foo>". 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. The integrated package itself is anonymous and
cannot be named, even from within itself.

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 <>;
      package <> is new Some_Container_Generic (T);
      - exports type Valise
   end Pkg;

   with Pkg;
   package Client is
       X : Pkg.T;
       Y : Pkg.Valise;
   end Client;

Two integrated packages declared within the same declarative region are required
to have distinct non-identifiers unless at least one of the two declares a
package rename or an instance of a generic package. This is needed in order to
map a package body to its corresponding specification. The body for one of these
guys cannot be a separate subunit.

For each visible declaration in the visible part of an integrated package, there
is an implicit rename declaration renaming that declaration immediately
following the declaration of the integrated package. A type or subtype
declaration is "renamed" via a constraintless subtype declaration. No rename is
generated for an incomplete type declaration. Renames are generated for
enumeration literals. Renames are generated for (visible) implicitly declared
declarations. Renames of subprograms preserve default parameter values. A
package rename may be integrated, in which case renames/subtypes are generated
for the visible declarations of the renamed package. The dynamic semantics of a
package declaration (e.g., its elaboration and finalization) are unaffected by
whether or not it is integrated.

Immediately after the implicit declarations associated with an integrated
package, a check for violations of the no-homographs rule in the enclosing
declarative region is performed. If a pair of illegal homographs is detected
such that exactly one of the two is among the set of just-added implicit
rename/subtype declarations, then that one is cast into the pit of darkness,
never to be seen again (thereby averting the illegal homograph collision). If an
implicit rename/subtype declaration survives this test, then a subsequent
homograph conflict involving that declaration is a hard error.

   package P1 is
      Foo : Integer;
      package <> is
         Foo : Float;
      end <>;
      -- ok; P1.Foo is of type Integer
   end P1;

   package P2 is
      package <> is
         Foo : Float;
      end <>;
      Foo : Integer; -- illegal
   end P2;

   package P3 is
      package <1> is
         Foo : Integer;
      end <1>;
      package <2> is
         Foo : Float;
      end <2>;
      -- ok; P3.Foo is of type Integer
   end P1;

An integrated package is treated like an unnamed block statement for purposes of
Ada.Tags.Expanded_Name and friends.

Renames are generated only for the declarations that are visible at the point of
an integrated package rename declaration. Thus,

    package P is
       X : Integer;
    end P;

    package P.Child
       ...;
    end P.Child;

    with P;
    package Q is
       package <> renames P;
       -- implicitly declares Q.X
    end Q;

    with P.Child;
    with Q;
    package Q_Client is
       Y : Integer renames Q.X; -- ok
       package Goof renames Q.Child; -- illegal
    end Q_Client;

!discussion

Is there any reason to allow/disallow an integrated package declared immediately
within another integrated package?

There was discussion earlier of some sort of relaxed homograph checking mode
which would allow homographic renames if they renamed the same thing. It appears
that the "cast them into the pit of darkness" mechanism has eliminated the need
for this. Do folks agree? The "renames the same thing" test might be useful in
helping a compiler decide whether to emit a warning message about a discarded,
but that's not part of the language definition. Alternatively, the rule stated
above could be tightened up so that package P3 above would be illegal, but we
would still allow

    package P4 is
       package <1> is
          C_E : exception renames Constraint_Error;
       end <1>;
       package <2> is
          C_E : exception renames Constraint_Error;
       end <2>;
       -- ok: P4.C_E denotes Constraint_Error
    end P4;

The idea is that a declaration would be discarded (thereby averting an illegal
homograph collision) only if the declaration that it conflicts with denotes the
same thing (after looking through renames), as well as perhaps passing other
tests (e.g., default parameters agree for a subprogram rename). This would
result in less discarding, more homograph collisions, and perhaps more readable
code.

We probably want to disallow integrated renames of enclosing packages, just
because they add complexity without adding utility.

A limited view of a package doesn't see integrated packages at all; if it's good
enough for instances ...

****************************************************************

From: Tucker Taft
Sent: Thursday, October 29, 2009  8:28 PM

The idea of putting the identifier inside "<>" is very clever.  It provides some
additional interesting alternatives.  In particular, it allows us to establish
special rules for these identifiers. For example, we considered allowing them to
be usable in expanded names, but never become directly "use" visible.

****************************************************************

From: Randy Brukardt
Sent: Thursday, October 29, 2009  8:57 PM

...
> There was discussion earlier of some sort of relaxed homograph
> checking mode which would allow homographic renames if they renamed
> the same thing. It appears that the "cast them into the pit of
> darkness" mechanism has eliminated the need for this.

I would agree, but I don't think the "pit of darkness" model works in all cases.

For instance, if you have two containers of different kinds, you're going to
want to somehow get at both cursor types. But its quite possible that other
operations that you care about wouldn't conflict, or would be redefined.

So I think there needs to be a shorthand which allows renaming items that
otherwise would end up in the "pit", without having to rename the entire
contents of a potentially large package. (We talked about this privately, but
since it has disappeared and it is a critical part of the model, IMHO.)

For instance, consider something like:

    package Test is
        package <> is
           type T is private;
           ...
        end <>;

        package <> is new Ada.Containers.Vector (T, Natural);
        package <> is new Ada.Containers.Map (T, String);
    end Test;

Here, the second type Cursor would disappear (or become illegal), and both
probably is not what you want. Which would then force you back to the same old
solutions that don't work very well.

But if you could say something like:
    renames Cursor => Map_Cursor, No_Cursor => Map_No_Cursor,

Then the problem goes away (everything else you want is overloadable).

    package Test is
        package <> is
           type T is private;
           ...
        end <>;

        package <> is new Ada.Containers.Vector (T, Natural);
        package <> is new Ada.Containers.Map (T, String)
           renames Cursor => Map_Cursor, No_Cursor => Map_No_Cursor;
    end Test;

It also means that you can use a stricter legality model such as the alternative
you outlined (which seems much less error prone - I don't like the idea that
moving a declaration could cause something unrelated [and not clearly declared]
to become invisible - isn't that a form of Beaujolais??).

Other thoughts: perhaps we should require an identifier in the <>? One could
imagine that identifier being available in local expanded names (that is, in the
package body). And that would eliminate any problem with body matching and the
like -- you could have as many of these as you want.

---

> I'm leaning towards named packages (when you make something anonymous,
> you discover later that you want to name it)

I don't mind the idea of naming them, so long as the name is *never* visible
outside of the package itself. Otherwise, you bring up all of the problems of
controlling the client view (and the impossibility of maintenance that changes
that view).

****************************************************************

From: Brad Moore
Sent: Saturday, October 31, 2009  7:23 PM

> But if you could say something like:
>     renames Cursor => Map_Cursor, No_Cursor => Map_No_Cursor,
>
> Then the problem goes away (everything else you want is overloadable).
>
>     package Test is
>         package <> is
>            type T is private;
>            ...
>         end <>;
>
>         package <> is new Ada.Containers.Vector (T, Natural);
>         package <> is new Ada.Containers.Map (T, String)
>            renames Cursor => Map_Cursor, No_Cursor => Map_No_Cursor;
>     end Test;


I had been thinking about this over the summer and arrived at something very
similar to this as well. The idea of being able to supply renames, for types,
enumerations, objects, etc to eliminate conflicts for anonymous packages.

Another issue with generics in general that is addressed by this approach:

I was also thinking that the names in a generic package have to be generic, but
when you want to instantiate a generic, it would be nice to supply names that
are more specific, so that the client can use names that more closely fit the
abstraction.

For example, instead of List, you might want to see Grocery_List, or
List_Of_Ingredients.

I arrived at a syntax for generating renames for a package. The idea was to use
the <> as a place holder in the renames. This placeholder represents the
original name from the package you are integrating.

You could give renames for specific entities, or you could also apply this "wild
card" approach.

For the containers example, I might use:


      package Test is
          package <> is
             type T is private;
             ...
          end <>;

          package <> is new Ada.Containers.Doubly_Linked_List (T)
             with renames (Empty_List => Empty_Grocery_List,
                           No_Element => No_Grocery_Element,
                           Others => Grocery_<>);

          package <> is new Ada.Containers.Doubly_Linked_List (T)
            with renames (Empty_List => Empty_Ingredient_List,
                          No_Element => No_Ingedient,
                          Others => <>_Of_Ingredients);

          X : List_Of_Ingredients;
          Y : Grocery_List;

      end Test;

In this model, I was thinking that there should be no pit of despair.
Conflicts should not be allowed period, as hopefully this mechanism would
provide sufficient flexibility to eliminate all conflicts.

With this scheme, we probably would want to avoid using "renames" to do a
package renames, because you might end up with two "renames" in the same
declaration. In that case, I would suggest we not use the "renames" for the
package renames, but just eliminate the word "new", as in

          package P is
             type T is null record;
          end P;

          with P;
          package Q is
             package <> is P
                with renames (Others => Cup_Of_<>ea);
          end Q;

I think this helps, but ideally we could reduce the usage of <> as well.

Perhaps "Use" could be used for the anonymous package rename, and reserver the
<> for the rename wildcards. Or (dare I say) add a new reserved word such as
"blend" which implies you are integrating something, and hopefully a word like
blend is not too likely to conflict with existing usage.

eg.

      package Test is
          blend package foo is
             type T is private;
             ...
          end foo;

          blend new Ada.Containers.Doubly_Linked_List (T)
             with renames (Empty_List => Empty_Grocery_List,
                           No_Element => No_Grocery_Element,
                           Others => Grocery_<>);

          -- or is "use" preferable?
          use new Ada.Containers.Doubly_Linked_List (T)
            with renames (Empty_List => Empty_Ingredient_List,
                          No_Element => No_Ingedient,
                          Others => <>_Of_Ingredients);

          X : List_Of_Ingredients;
          Y : Grocery_List;

      end Test;

****************************************************************

From: Tucker Taft
Sent: Saturday, October 31, 2009  8:03 PM

Wouldn't it be simpler if you could just use a regular rename?
E.g.:

    package <T_Maps> is new Ada.Containers.Maps(T, Natural);
    subtype Map_Cursor is T_Maps.Cursor;
    No_Cursor : Map_Cursor renames T_Maps.No_Cursor;

It seems like allowing the name to be used in certain circumstances, at least
inside the package, is simpler than inventing more new syntax, such as for
renaming.

****************************************************************

From: Randy Brukardt
Sent: Saturday, October 31, 2009  11:13 PM

True, but that means that you have to *allow* what Steve called the "pit of
despair", essentially names that are hidden from all visibility. As Brad
mentions, that rule is better off not existing. The problem is that maintenance
that added one or more declarations on one of the generic packages could cause
declarations in some unrelated anonymous instance far away to disappear and
cause errors. ("unrelated" other than accidental proximity.)

The whole reason that I am pushing for these "integrated packages" to be
anonymous is to avoid maintenance hazards. It doesn't help much to push the bump
around (in that case, we're better off just living with the problems and the
imperfect solutions).

****************************************************************

From: Tucker Taft
Sent: Sunday, November 1, 2009  10:02 AM

Isn't this the same thing that happens with "use" visibility, namely that if you
change one package spec, other packages also "use"d in the same scope will
suddenly lose declarations? I don't see why this problem is any worse.  Perhaps
you could give a more concrete example to explain the problem.

I also couldn't tell from your response why the proposal for using "regular"
renames was related to this issue of "despair."

****************************************************************

From: Brad Moore
Sent: Sunday, November 1, 2009  11:11 AM

I think the "regular" renames proposal almost works, but not quite.
For this to work comparable to the renaming idea, I am thinking that;

1) If there are conflicts, all conflicting names are thrown into the pit of
despair, not just the 2nd occurrence.

2) To get the code to compile, all conflicts need to be resolved by "fishing"
things out of the pit of despair using renames, until there are no conflicts.
Once you are down to a conflict between two uses, fishing one of the uses out of
the pit, brings the remaining use out of the pit as well, because there no
longer would be a conflict.

3) To fish a type name out of the pit of despair, would require a type rename. A
subtype declaration doesn't cut it, because that doesn't fish out all the other
things associated with the type. Unfortunately, type renames do not exist today.
That is the missing piece of the puzzle I think.

So I think you could accomplish the same ends using the "renaming approach" if
we find a way to do type renames, or you could go with an approach along the
lines of what Randy and I are suggesting, which gives you another way to get
type renames.

****************************************************************

From: Tucker Taft
Sent: Sunday, November 1, 2009  11:33 AM

I don't understand why a subtype declaration wouldn't work. Are you saying the
type's primitive operations are somehow tied to whether the type's name
conflicts?  That seems weird.

****************************************************************

From: Brad Moore
Sent: Sunday, November 1, 2009  12:17 PM

Maybe (more likely) I am not understanding something about the regular renaming
idea.

I was thinking that a subtype declaration would not count as a substitute for a
type rename, because it doesn't give you things like enumeration literals,
exceptions, class-wide operations. It's the same reason why we sometimes derive
a new type (as a kludge) rather than use a subtype declaration. You could create
renames for all of those as well, (or deriving new types) but then you might as
well be doing the package integration all by hand at that point. It seems to me
that once you start deriving new types, you no longer are integrating a package,
but creating a new one.

****************************************************************

From: Tucker Taft
Sent: Sunday, November 1, 2009  1:01 PM

Well maybe *I'm* missing something, but I presumed that everything in the
"integrated" package was made visible in the enclosing scope, unless there was
some kind of conflict.  So all of those enumeration literals, exceptions, etc.,
have already been made visible in the enclosing scope, even if the type name
happens to conflict.  So a subtype declaration for the type name is all you need
to do.  All of the other things, presuming they didn't conflict, are already
there, even if their type isn't directly nameable.

****************************************************************

From: Brad Moore
Sent: Sunday, November 1, 2009  1:23 PM

True, but I am thinking conflicts for other things could end up being quite
common. Suppose you have a package that wants to instantiate the same generic
with two different types. The whole 2nd instance would end up being in the pit
of despair, correct? Or suppose you have a set of container libraries that have
similar names for objects (Like Cursor, No_Element, etc) so they can be used
more interchangeably. (Like our standard containers) Two Container
instantiations in the same package, even if they are different containers could
end up conflicting quite a bit.

I was thinking after I sent my last email that I should have included an
example. So here it is.


generic
    type F is tagged private;
package P is
    -- Enumeration Literals
    type E is (This, That, Other_Thing);

    type T is new F with null record;
    function Process (Item : T) return Boolean;

    -- Classwide Operation
    function Compare (L, R : T'Class) return Boolean;

    -- Exception
    Red_Alert : exception;

end P;


-- My understanding of the renames approach

with P;
package Q is
   type T1 is null record;
   type T2 is null record;

   package <> is new P(T1);
   package <Foo> is new P(T2);
   -- At this point all of the second instance is in the pit of despair,
   -- correct?
   subtype Foo_T2 is Foo.T; -- This gives me T, but about T'Class
   type Foo2_T2 is new Foo.T with null record;
    -- OK, now I have T'Class but had to derive a new type.
    -- I dont really have Foo.T

   type Foo_E is new Foo.E;
   Foo_Red_Alert : exception renames Foo.Red_Alert;

   -- The more declarations in P, the more renames we need.
end Q;


-- The approach I was suggesting.

Or if you go with what I was suggesting, this becomes the following; Note that
the following scales better than the above. The more declarations in P, might
not involve adding any more declarations to the following

with P;
package Q is
   type T1 is null record;
   type T2 is null record;

   use new P(T1);
   use new P(T2) with renames (Others => Foo_<>); end Q;


-- Example usage
with Q;
procedure Main is
   X : Q.T;
   Y : Q.Foo_T;
   Z : Q.Foo_E;
begin
   case Z is
      when Q.This =>
        null;
      when Q.That =>
        null;
      when Q.Other_Thing =>
        null;
   end case;
end

Hmmm. Would the enumeration literals resolve correctly to the correct version? I
am thinking they would because Z is of a specific type.

****************************************************************

From: Tucker Taft
Sent: Sunday, November 1, 2009  1:49 PM

This feels a bit like we are just "making stuff up."
I think we should be looking for minimal syntax and semantic invention here.

But back to our specific issue:

I presume that things that are overloadable would not be considered conflicts,
in the same way they don't conflict as far as use-visibility.  Since we are
trying to do away with having to use a type derivation and all the confusion
that creates, the only thing that would ever need renaming that is *not*
overloadable, among those things provided by a derived type, is the type name
itself.  You currently don't get exceptions, generics, etc. when you do a type
derivation, so I believe my claim that a subtype declaration is just as good as
a type "renaming" in this context is correct.

And the integrated package is clearly better than type derivation because you
*do* get exceptions, generics, etc., presuming they don't conflict. But if we
start doing wholesale renaming of the entire contents to deal with conflicts of
non- overloadables, then why bother?  Using a subpackage name is probably just
as convenient.

I would say having two integrated instances of the same package in the same
scope is not the primary purpose of this feature, and presuming you have some
sort of a name for the integrated subpackages that can at least be used locally,
then selective, "targeted" renaming is adequate to deal with that case.
Wholesale renaming just doesn't make sense to me.

****************************************************************

From: Randy Brukardt
Sent: Monday, November 2, 2009  6:03 PM

> Isn't this the same thing that happens with "use" visibility, namely
> that if you change one package spec, other packages also "use"d in the
> same scope will suddenly lose declarations?
> I don't see why this problem is any worse.  Perhaps you could give a
> more concrete example to explain the problem.
>
> I also couldn't tell from your response why the proposal for using
> "regular" renames was related to this issue of "despair."

It is similar to the problem of "use" visibility, but it is worse because it is
forced on clients by the design of the packages (rather than by their own use of
"use").

Something I just realized this morning in thinking about this question (which I
read last night but didn't answer due to the lateness of the hour) is that a
major reason that I am mostly use-adverse is the maintenance hazard that "use"
causes. That is, adding a declaration somewhere can make something unrelated
disappear. I hadn't realized until today that this is why I don't mind "use"
clauses of overloadable entities as much (especially operators and enumeration
literals) -- they are far less likely to run into this "maintenance
disappearance" because it only happens when the profiles are identical. (And
that's pretty weird.) For non-overloadable entities, it happens even when the
two items could never be confused by a human (such as an exception and a
function).

Currently, programmers can decide how much of this maintenance hazard they are
willing to risk, by choosing how much to use "use" clauses and directly visible
names, and how much to use fully-qualified names (FQNs). Even when you do have a
use clause, you can avoid the maintenance hazard by using an FQN.

But that isn't true if you have Steve's "pit of despair", any version. The name
disappears even when you do use an FQN, since the integrated package name isn't
available for use (and that itself is important for maintenance, so that clients
cannot depend on whether an integrated package is used, or a set of direct
declarations, or a set of renames of a nested package -- they all work the same
to a client -- allowing the implementation to be changed if necessary).

Let me try to give a simple example:

    generic
    package G1 is
       Foo : Integer;
       --Bar : Integer; -- (1)
    end G1;

    with G1;
    package Test is
        package <I1> is new G1;
        package <N1> is
            Bar : Float; -- (2)
        end <N1>;
    end Test;

    with Test;
    procedure Main is
        function Is_Groddy (I : Integer) return Boolean is ...
        function Is_Groddy (F : Float) return Boolean is ...
    begin
         if Is_Groddy (Test.Bar) then -- (3)
             ...
    end Main;

As written, (3) resolves to the float Bar declared at (2).

Let's look at what happens if the declaration of Bar at (1) is added.

With Steve's original proposal, which is order-based, the Bar at (1) becomes
automatically renamed because of the integrated package <I1>. Then, because a
homograph already exists when integrating <N1>, the Bar at (2) is cast into the
pit of despair (which really means it is hidden from all visibility, or even
more simply, it isn't declared). The problem here is that we have a first-class
Beaujolias effect: the call at (3) changes silently from using object (2) to
using object (1). (Of course, it is more likely to cause some sort of error, but
I wanted to show the worst case.) I believe that is unacceptable, so I won't
spend any more time on Steve's first idea.

Another idea is to revert to use-like visibility for integrated packages. That
is, *both* names Bar are tossed into the pit of despair and neither is visible
in Test (this has strange semantics, because after <I1> and before <N1>, there
is a point where Bar is directly visible in Test, and then is later disappears).
That makes the name Test.Bar at (3) illegal, because there are two homographs
meaning that neither is visible. I find this obnoxious, because the change is
completely unrelated to the package where the error occurred. The writer of this
code doesn't care at all about the <I1> potion of Test; moreover the maintainer
of G1 probably doesn't know that users of Test will be impacted by a seemingly
unrelated change. Also note that the writer of Main tried to avoid exactly this
sort of effect by not using a use-clause -- yet they end up with one of the
worst side-effects of use clauses simply because some other author used
integrated packages.

Note that in this case there is no obvious repair. We can't easily change
anything to make Bar properly visible. If we have Tucker's suggested local names
for these packages, we could rename the two Bars to something else, but of
course that would force all of the clients to be changed. I suppose with a
complex enough definition of what happens to these homographs we might be able
to allow an explicit renaming to Bar (that is Bar : Float renames N1.Bar;), but
that seems pretty complex to me.

The rule I was advocating was that if there are conflicting homographs, then the
program is simply illegal. Steve notes that is necessary anyway when there are
explicit declarations of things, so I'm actually suggesting a simpler rule: no
conflicts. Then the maintenance hazard is at least closer to the original cause.

In that case, adding Bar to G1 would make package Test illegal.

Now, we need a way to work around that restriction when it unavoidably happens
(such as when two different containers are instantiated). That's why I suggested
supporting renaming as part of integrated packages. If you had added Bar to G1,
all you would need to do to make Test legal again (and not change any of Test's
clients) would be to add an appropriate rename. Using the syntax that Brad
suggested (a bit better than mine):

    with G1;
    package Test is
        package <I1> is new G1
            with renames Bar => Soap_Bar;
        package <N1> is
            Bar : Float;
        end <N1>;
    end Test;

And now there aren't any homographs and the program is legal. In addition, no
clients need to change.

Note that this renaming facility is mainly aimed at non-overloadable entities,
so we don't need any profile information.

This also means that the name <N1> does not need to be visible outside of the
package <N1> itself, which seems to be a simpler rule to me than trying to allow
it to be used in its parent unit (only). It avoids having to answer the question
as to whether N1 is visible in a child of Test, for instance.

Anyway, much food for thought. I've got to get all of the work done to prepare
for this meeting, so I can't spend any more time discussing this until I see you
on Thursday.

****************************************************************

From: Randy Brukardt
Sent: Monday, November 2, 2009  7:35 PM

> But that isn't true if you have Steve's "pit of despair", any version ...

Steve points out that the correct term is "pit of darkness". I apparently was
too tired on Saturday night to actually remember the proper term. "despair" is
probably a bit much for this issue (although it does seem appropriate in some
ways :-). Sorry about any confusion.

****************************************************************

Questions? Ask the ACAA Technical Agent