Version 1.2 of ai12s/ai12-0215-2.txt

Unformatted version of ai12s/ai12-0215-2.txt version 1.2
Other versions for file ai12s/ai12-0215-2.txt

!standard 12.9(0)          19-09-24 AI12-0215-2/01
!class Amendment 19-09-24
!status Hold 13-0-0 20-09-09
!status work item 19-09-24
!status received 19-09-16
!priority Low
!difficulty Hard
!subject Implicit instantiations
!summary
*** TBD.
!problem
Declaring a stand-alone object of a generic type can be unnecessarily verbose, requiring the introduction of extra declaration and name (with the extra cognitive overhead of such declarations).
This is particularly noticable for the containers, where declaring a simple one-time use Vector object is much more verbose than the equivalent array:
Single_Arr : array (Small_Int) of Float;
type Single_Vect_Inst is new Ada.Containers.Vectors (Small_Int, Float); Single_Vect : Single_Vect_Inst.Vector;
There should be a short-hand for simple generic objects.
Similarly, instances of signature packages and interface packages often only need to be created to be passed to a single (outer) instance. Again, we're introducing an extra declaration and name (with the extra cognitive overhead of such declarations).
!proposal
(See wording.)
!wording
12.9 Unnamed Generic Instances
In certain contexts (described below) where the name of an instance of a generic unit might occur, an unnamed_instance may be provided instead. This is equivalent to declaring a named instance immediately before the enclosing declaration of the unnamed_instance and then replacing the unnamed_instance with a direct_name denoting the named instance. For example,
My_Float_Vector : new Ada.Containers.Vectors (Positive, Float).Vector;
is equivalent to
package Identifier_123 is new Ada.Containers.Vectors (Positive, Float); My_Float_Vector : Identifer_123.Vector;
where Identifier_123 is some implementation-defined identifier that occurs nowhere else in the program.
Syntax
unnamed_instance ::= new generic_unit_name [generic_actual_part] unnamed_instance_name ::= unamed_instance name ::= unnamed_instance_name
TBD: The syntax we want is clear; the question is how best to express it in the grammar. for example, do we want to describe the contexts in which an unnamed_instance is permitted using syntax rules or legality rules? This is just a presentation question - the answer would not have any effect on the language or on any implementation. I suggest saying that an unnamed_instance_name is a name and then imposing restrictions on the contexts in which such a name can occur via legality rules (as opposed to trying to express those restrictions via syntax rules).
Static Semantics
An unnamed_instance which is an unnamed_instance_name is a name which denotes an instantiation of a generic unit that is implicitly declared as described below. The one case in which an an unnamed_instance does not occur as an unnamed_instance_name is when it occurs as a package_default (i.e., as the default for a formal package_declaration). That case is described in 12.7
When an unnamed_instance is used as an unnamed_instance_name, it is a name which denotes a generic instance declared immediately before the nearest enclosing declaration of the unnamed_instance. If a given declaration is the nearest enclosing declaration for two or more such names, then the order of the corresponding implicit declarations matches that of the unnamed_instance_names.
The implicitly declared instance is an instance of the generic unit denoted by the generic_unit_name and having the generic actual parameters specified by the generic_actual_part (if any), as for an explicitly declared instance.
An implicitly declared instance associated with an unnamed_instance_name is subject to the same rules (e.g., legality rules, name resolution rules) as for a corresponding explicitly declared instance.
Legality Rules
An unnamed_instance may be used as an unnamed_instance_name only in the following contexts:
- as a prefix of the subtype_mark of an object_declaration; - as the actual parameter corresponding to a generic formal package
or a generic formal subprogram in a generic_association.
A name occuring within an unnamed_instance_name shall not denote a declaration which is a homograph of an entity declared by the nearest enclosing declaration of the unnamed_instance_name.
[AARM For example,
X : Natural := ... ;
declare generic Hi : Natural; package G1 is type T is new Integer range 0 .. Hi; end G1;
X, Y : new G1 (Y).T; -- illegal, even though the -- "equivalent" explicit instantiations would -- be legal. begin null; end;
Note that a declaration
A, B, C : new Some_Generic (Some_Formal => Some_Actual).Some_Type;
is equivalent (by section 3.3.1) to
A : new Some_Generic (Some_Formal => Some_Actual).Some_Type; B : new Some_Generic (Some_Formal => Some_Actual).Some_Type; C : new Some_Generic (Some_Formal => Some_Actual).Some_Type;
so that three instantations are implicitly declared. end AARM]
===
12.7
In 2/3 (Syntax) change
package_default ::= unnamed_instance
formal_package_declaration ::= with package defining_identifier is new generic_package_name formal_package_actual_part [aspect_specification] [:= package_default];
[TBD: The ":=" syntax proposed here is extremely tentative.
Normally we would use "is" to introduce a default, as is done with formal subprograms. However, we already have an "is" earlier in the same construct. We presumably don't want two "is" occurrences, as in
generic with package Inst is new Some_Generic (Formal1 => Actual1, Formal2 => <>) is new Some_Generic (Formal1 => Actual1, Formal2 => Actual2); package G is ... end G;
because that syntax seems very confusing.
We could use "or use" or some similar variation instead of ":=", but ":=" has a well-established association with default parameter values. On the other hand, the use of an assignment operator when we are talking about packages does seem ugly. Perhaps "or use" would be better?
end TBD]
Add after 8.1/1 (at the end of the Legality Rules section)
The package_default, if any, shall meet the requirements for an actual parameter corresponding to the given formal package parameter.
Add after 11/2 (at the end of the Static Semantics section)
If a generic unit has a package_default, and the corresponding actual parameter is omitted, then it is equivalent to an explicit actual parameter that is an unnamed_instance_name which is a copy of the package_default.
===
In 3.9(10/2), replace
The function Wide_Wide_Expanded_Name returns the full expanded name of the first subtype of the specific type identified by the tag, in upper case, starting with a root library unit. The result is implementation defined if the type is declared within an unnamed block_statement.
with
An entity is said to have an undefined fully qualified name if its occurs with an unnamed block_statement or within an implicitly declared generic instantiation.
The function Wide_Wide_Expanded_Name returns the full expanded name of the first subtype of the specific type identified by the tag, in upper case, starting with a root library unit. The result is implementation defined if the type has an undefined fully qualified name.
In 3.9(10.b/2), replace "for types declared within an unnamed block_statement" with "for types that have an undefined fully qualified name".
In 11.4.1(12/2), replace "if the exception is declared within an unnamed block_statement" with "if the exception has an undefined fully qualified name".
In 11.4.1(12.c/2), replace "for exceptions declared within an unnamed block_statement" with "for exceptions having an undefined fully qualified name".
Similar patchups for the "unnamed block statement" references in M.2, specifically M.2(20/2) and M.2(40/2).
!discussion
[Not provided by author.]
A few notes from the editor:
Containers for which cursors are needed are not appropriate uses of this syntax: it only allows the use of the name of the container type. That's OK for Vector, Map, Holder, and Queue containers, where either other indexing is provided, or no indexing is needed at all. It probably wouldn't work as well for List, Set, and Tree containers, although it could still work if the individual elements only need to be accessed via an iteration of the entire container.
We generally only allow this syntax in places where the place of the implicit instance is well-defined: directly before the explicit declaration. That allows the elaboration and freezing rules to occur in an obvious and well-defined place.
This version of the AI allows unnamed instances only where they can be used to define a type where an anonymous array type would be allowed, in a generic instance, and in generic defaults.
See AI12-0215-1, AI12-0268-1, AI12-0297-1, and AI12-0205-1 for original proposals that were used as a basis for this proposal.
!ASIS
Something is needed, TBD.
!ACATS test
ACATS B-Tests and C-Tests will be needed to check that the new capabilities are supported. (Note that all objectives for generic instances would be fair game for this construct.)
!appendix

From: Steve Baird
Sent: Monday, September 16, 2019  7:13 PM

At the Warsaw ARG meeting, I was tasked with taking the results of the 
discussions there together with the ideas discussed in AIs 268, 215, 
297, and 205 and going from there to develop a new proposal.
So that's what this is.

The general approach taken here is that in certain specified contexts where 
a name denoting an instance is currently allowed, we will also allow a 
reference to an implicitly declared anonymous instance by supplying the name 
of the generic and an accompanying generic_actual_part.

For example, this AI would allow

    X : new My_Generic (Element_Type => Float,
                        Key_Type     => Positive).Some_Type;

and define it to be equivalent to

    package Some_Unique_Identifier
      is new My_Generic (Element_Type => Float,
                         Key_Type     => Positive);

    X : Some_Unique_Identifier.Some_Type;

This is planned as the first step of a two-part change. The second step, which 
has not been designed yet, has to do with using type inference to eliminate 
the need to explicitly specify some generic actual parameters.
That is not the topic of this AI.

This isn't as polished as I would like (and Randy might notice that it is 
missing !problem, !summary, etc.), but I wanted to get something out soon 
(I'm taking most of the rest of September off) so that folks can look at this 
before the meeting in Lexington.

Thanks to Randy for reviewing an earlier version.

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

From: Raphaël Amiard
Sent: Tuesday, September 17, 2019  4:18 AM

For somebody who hasn't followed the Warsaw meeting, could you explain the 
rationale and motivation behind that feature ? There is no problem description
in the AI, so it's very hard to know what problem this is supposed to solve 
from the outside.

Thanks in advance

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

From: Jeff Cousins
Sent: Tuesday, September 17, 2019  5:50 AM

Take a look at the precursor AIs that Steve lists, particularly 268.

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

From: Jeff Cousins
Sent: Thursday, September 19, 2019  6:50 AM

Thanks Steve.  I mostly like it, though “an unnamed_instance_name is a name” 
grates as much as “named anonymous access type” did in some other proposal.  
I have some sympathy for “or else” rather than “:=” as it’s more like to the 
other proposals such as 205 and 297.

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

From: Randy Brukardt
Sent: Monday, September 23, 2019  9:04 PM

This AI was created from AIs 215 and 268 (among others), and covers the 
problem statements of both of those AIs. We were considering allowing 
anonymous instances in limited contexts where the name of the instance is 
mainly noise and where the elaboration order and freezing is well-defined.
(Allowing anonymous instances generally -- as in the middle of an expression 
-- would have additional issues of where the elaboration and freezing would 
occur -- which would get very messy, especially in existing compilers.)
 
You also can refer to the minutes of the Warsaw meeting, of course, to get 
some additional background. We do post all of that information publicly, it's
not hidden from view, and there is an AI index at the top so it isn't 
necessary to read through the entire minutes to find the discussion of a 
single item.

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

From: Randy Brukardt
Sent: Tuesday, September 24, 2019  11:42 PM

> At the Warsaw ARG meeting, I was tasked with taking the 
> results of the discussions there together with the ideas 
> discussed in AIs 268, 215, 297, and 205 and going from there 
> to develop a new proposal.
> So that's what this is.
...

Some comments on the AI contents:

>   unnamed_instance ::= new generic_unit_name [generic_actual_part]
>   unnamed_instance_name ::= unamed_instance
>   name ::= unnamed_instance_name

What is the value of both "unnamed_instance" and "unnamed_instance_name"
here? The former is only used in one place (package_default) and I don't see
any reason that these are different semantically. A package_default could
certainly be a name (since generic instances have names), so I fail to
understand why we need both. (Dropping unnamed_instance_name as a production
would also address Jeff's complaint.)

>   when it occurs as a package_default (i.e., as the default for a
>   formal package_declaration).  That case is described in 12.7

We don't allow "i.e." in AIs or the RM. Say "(that is, ". There's an extra
blank after the period in the second sentence, and no period after 12.7.

>   An implicitly declared instance associated with an unnamed_instance_name
>   is subject to the same rules (e.g., legality rules, name resolution
rules)
>   as for a corresponding explicitly declared instance.

We don't allow "e.g.", either, use "for example" here. We might have a
better wording for this somewhere in the Standard (but I couldn't find it in
a quick check). It also might be completely redundant, since it follows from
the definition of "implicitly declared" -- it's the same construct, so *of
course* it follows the same rules.

>   An unnamed_instance may be used as an unnamed_instance_name only in the
>   following contexts:
>      - as a prefix of the subtype_mark of an object_declaration; 
>      - as the actual parameter corresponding to a generic formal package
>        or a generic formal subprogram in a generic_association.

The missing discussion should note that one of the goals here is to make
using containers no harder than using arrays, so we allow
unnamed_instance_names in contexts that allow anonymous array declarations.
(If it is OK to not name an array type, it can't be any worse to not name an
instance of Vectors or Maps in that same context.)

The other case is in instances, to make using signature packages and similar
sorts of things easier.

>    package_default ::= unnamed_instance

It seems odd to ONLY allow an unnamed_instance here; shouldn't it be OK to
specify a named instance in the case where it is providing the types (as
opposed to other formal parameters)? 

For instance, imagine something like:

package Ada.Strings.Bounded80 is new
Ada.Strings.Bounded.Generic_Bounded_Length (80);

with Ada.Strings.Bounded, Ada.Strings.Bounded80;
generic
   with package Bounded is
                     new Ada.Strings.Bounded.Generic_Bounded_Length (<>)
         or use Ada.Strings.Bounded80;
package Ada.Text_IO.Bounded_IO is
 
This seems reasonable (maybe not in this particular case, but the pattern is
common).

>         X, Y : new G1 (Y).T; -- illegal, even though the
>                              -- "equivalent" explicit instantiations would
>                              -- be legal.

I suspect that (Y) here ought to be (X), since
    package Unnamed is new G1 (Y).T;
is illegal since there is no global Y defined. (But you do have a Global X
defined.)

>We could use "or use" or some similar variation instead of ":=", but
>":=" has a well-established association with default parameter values.
>On the other hand, the use of an assignment operator when we are talking
>about packages does seem ugly. Perhaps "or use" would be better?

When we discussed generic defaults, there was a lot of discomfort using ":="
for non-value defaults, even in the case of in out generic parameters (where
it is argubly meaningful). I think "or use" would be better here and in any
other generic default defined in the future.

>In 3.9(10/2), replace

This was a good catch; I'm not sure I would have thought of this problem. It
seems a bit of overkill to define a term for it, but it would make adding
other future anonymous constructs easier, so perhaps it makes sense from
that perspective.

---

You only defined a package default. When we discussed this in Warsaw, we
also touched on wanting to allow this for type defaults (which of course
implies supporting type defaults). Since there's no !discussion, I don't
know if you left that out for some semantic reason or if it was just an
oversight. I note that the interaction problems with other formal parameters
are much, much worse (and different) for formal package defaults as compared
with formal types (where the interactions already occur, for instance in
formal access and array types, and formal defaults would not add anything
particularly new).

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

From: Randy Brukardt
Sent: Wednesday, September 25, 2019  12:01 AM

I forgot to mention that there doesn't seem to be a provision to allow 
unnamed_instances as the default for a formal subprogram. That seems like 
an obvious usage (given that generics can be subprograms). That's probably 
just an oversight.

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


Questions? Ask the ACAA Technical Agent