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

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

!standard 4.1.3(12)          09-05-26 AI05-0135-1/04
!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 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 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).
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?
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: 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: Randy Brukardt
Sent: Tuesday, May 26, 2009  6:38 PM

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

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

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

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

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

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

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


Questions? Ask the ACAA Technical Agent