CVS difference for ai12s/ai12-0212-1.txt

Differences between 1.8 and version 1.9
Log of other versions for file ai12s/ai12-0212-1.txt

--- ai12s/ai12-0212-1.txt	2018/02/27 23:07:58	1.8
+++ ai12s/ai12-0212-1.txt	2018/02/27 23:59:17	1.9
@@ -1,4 +1,4 @@
-!standard 4.3.5(0)                                  18-02-09  AI12-0212-1/03
+!standard 4.3.5(0)                                  18-02-14  AI12-0212-1/04
 !class Amendment 16-12-27
 !status work item 17-06-10
 !status received 16-06-12
@@ -37,577 +37,573 @@
 
 !proposal
 
-Thus, we propose to add a new aspect (in the spirit of Constant_Indexing,
-Default_Iterator, and Iterator_Element) along with two new aggregates to
-use it, based on the array aggregate syntax.
-
-This proposal works for most of the standard containers (Vectors,
-Doubly_Linked_Lists, Hashed_Sets, Ordered_Sets, Hashed_Maps and
-Ordered_Maps including their bounded and indefinite versions).
-Multiway_Trees are not supported by this proposal.
-
-The concept is inspired by Python and other languages that have list and
-set "comprehensions," but it uses, largely, Ada's array aggregate as the
-basis for the syntax.
-
-In the most simple form (called a positional container aggregate) we
-just give the elements to add in a form very similar to a simple array
-aggregate, but with no "others" permitted:
-
-   X : My_Set := (1, 2, 3);
-
-   --  Equivalent to:
-   X : My_Set := Empty_Set;
-   Include (X, 1);
-   Include (X, 2);
-   Include (X, 3);
-
-The function or constant "Empty_Set" is one of the two (or three) things
-you specify in the Aggregate aspect (the "Empty" component of the
-Aggregate aspect), the procedure "Include" is the other (the
-"Add_Positional" component of the Aggregate aspect).
-
-Positional container aggregates are good for defining simple container
-instances, but often, you might want to derive one container from
-another (a concept that is called comprehension). This is vaguely
-related to a delta aggregate, but neither construct can easily emulate
-the other.
-
-Here we loop over one container and apply some function to each item.
-The proposed syntax steals from existing loop and quantifier syntax:
-
-   Y : My_Set := (for Item of X => Item * 2);
-
-   --  Equivalent to:
-   Y : My_Set := Empty_Set;
-   for Item of X loop
-      Include (Y, Item * 2);
-   end loop;
-
-We may also wish to filter the items:
-
-   Z : My_Set := (for Item of X when Item > 1 => Item - 1);
-
-   --  Equivalent to:
-   Z : My_Set := Empty_Set;
-   for Item of X loop
-      if Item > 1 then
-         Include (Z, Item - 1);
-      end if;
-   end loop;
-
-Finally, it is also a common pattern to combine multiple containers into
-one. Three approaches are supported. This is the nested (or "product") one:
-
-   W : My_Set := (for A of X =>
-                    for B of X => A * B);  --  TBD: Not currently in this AI
-
-   --  Equivalent to:
-   W : My_Set := Empty_Set;
-   for A of X loop
-      for B of X loop
-         Include (W, A * B);
-      end loop;
-   end loop;
-
-This is the sequential (or "list") one:
-
-   V : My_Set := (for A of X => A,
-                  for A of X => -A);
-
-   --  Equivalent to:
-   V : My_Set := Empty_Set;
-   for A of X loop
-      Include (V, A);
-   end loop;
-   for A of X loop
-      Include (V, -A);
-   end loop;
-
-This is the concurrent one (TBD --  not in this AI yet):
-
-   V : My_Set := (for (A of X; I in 1..Max) => (A, I));
-   -- TBD: Not currently in this AI yet
-
-   --  Equivalent to:
-   V : My_Set := Empty_Set;
-   for (A of X; I in 1..Max) loop
-      Include (V, (A, I));
-   end loop;
-
-   --  where the parenthesized iterators run concurrently, with the iteration
-   --  stopping when either runs out of elements.
-
-The new contract on the set container would be:
-
-   type Set is tagged private
-      with --  currently we have this:
-           Constant_Indexing => Constant_Reference,
-           Default_Iterator  => Iterate,
-           Iterator_Element  => Element_Type,
-           --  this is new
-           Aggregate         => (Empty => Empty_Set,
-                                 Add_Positional => Include);
-
-For containers such as maps, an Add_Named component of the Aggregate
-aspect would be specified, to enable a usage such as:
-
-   M : My_Map := (42 => "foo",
-                  88 => "bar");
-                  
-This is equivalent to:
-
-   M := Empty_Map;
-   Insert (M, 42, "foo");
-   Insert (M, 88, "bar");
-   
-where "Insert" is specified as the "Add_Named" component of the
-Aggregate aspect.
-
-So, to summarise:
-* New aspect on types specifying an empty default, plus either an
-  Add_Positional or an Add_Named procedure (or both).
-* Extend aggregate syntax to trigger these
+Thus, we propose to add a new aspect (in the spirit of Constant_Indexing,
+Default_Iterator, and Iterator_Element) along with two new aggregates to
+use it, based on the array aggregate syntax.
+
+This proposal works for most of the standard containers (Vectors,
+Doubly_Linked_Lists, Hashed_Sets, Ordered_Sets, Hashed_Maps and
+Ordered_Maps including their bounded and indefinite versions).
+Multiway_Trees are not supported by this proposal.
+
+The concept is inspired by Python and other languages that have list and
+set "comprehensions," but it uses, largely, Ada's array aggregate as the
+basis for the syntax.
+
+In the most simple form (called a positional container aggregate) we
+just give the elements to add in a form very similar to a simple array
+aggregate, but with no "others" permitted:
+
+   X : My_Set := (1, 2, 3);
+
+   --  Equivalent to:
+   X : My_Set := Empty_Set;
+   Include (X, 1);
+   Include (X, 2);
+   Include (X, 3);
+
+The function or constant "Empty_Set" is one of the two (or three) things
+you specify in the Aggregate aspect (the "Empty" component of the
+Aggregate aspect), the procedure "Include" is the other (the
+"Add_Positional" component of the Aggregate aspect).
+
+Positional container aggregates are good for defining simple container
+instances, but often, you might want to derive one container from
+another (a concept that is called comprehension). This is vaguely
+related to a delta aggregate, but neither construct can easily emulate
+the other.
+
+Here we loop over one container and apply some function to each item.
+The proposed syntax steals from existing loop and quantifier syntax:
+
+   Y : My_Set := (for Item of X => Item * 2);
+
+   --  Equivalent to:
+   Y : My_Set := Empty_Set;
+   for Item of X loop
+      Include (Y, Item * 2);
+   end loop;
+
+We may also wish to filter the items:
+
+   Z : My_Set := (for Item of X when Item > 1 => Item - 1);
+
+   --  Equivalent to:
+   Z : My_Set := Empty_Set;
+   for Item of X loop
+      if Item > 1 then
+         Include (Z, Item - 1);
+      end if;
+   end loop;
+
+Finally, it is also a common pattern to combine multiple containers into
+one. Three approaches are supported. This is the nested (or "product") one:
+
+   W : My_Set := (for A of X =>
+                    for B of X => A * B);  --  TBD: Not currently in this AI
+
+   --  Equivalent to:
+   W : My_Set := Empty_Set;
+   for A of X loop
+      for B of X loop
+         Include (W, A * B);
+      end loop;
+   end loop;
+
+This is the sequential (or "list") one:
+
+   V : My_Set := (for A of X => A,
+                  for A of X => -A);
+
+   --  Equivalent to:
+   V : My_Set := Empty_Set;
+   for A of X loop
+      Include (V, A);
+   end loop;
+   for A of X loop
+      Include (V, -A);
+   end loop;
+
+This is the concurrent one (TBD --  not in this AI yet):
+
+   V : My_Set := (for (A of X; I in 1..Max) => (A, I));
+   -- TBD: Not currently in this AI yet
+
+   --  Equivalent to:
+   V : My_Set := Empty_Set;
+   for (A of X; I in 1..Max) loop
+      Include (V, (A, I));
+   end loop;
+
+   --  where the parenthesized iterators run concurrently, with the iteration
+   --  stopping when either runs out of elements.
+
+The new contract on the set container would be:
+
+   type Set is tagged private
+      with --  currently we have this:
+           Constant_Indexing => Constant_Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           --  this is new
+           Aggregate         => (Empty => Empty_Set,
+                                 Add_Positional => Include);
+
+For containers such as maps, an Add_Named component of the Aggregate
+aspect would be specified, to enable a usage such as:
+
+   M : My_Map := (42 => "foo",
+                  88 => "bar");
+
+This is equivalent to:
+
+   M := Empty_Map;
+   Insert (M, 42, "foo");
+   Insert (M, 88, "bar");
+
+where "Insert" is specified as the "Add_Named" component of the
+Aggregate aspect.
+
+So, to summarise:
+* New aspect on types specifying an empty default, plus either an
+  Add_Positional or an Add_Named procedure (or both).
+* Extend aggregate syntax to trigger these
 
 !wording
 
-4.3 Aggregates
-
-Change paragraph 2/5:
-
-   aggregate ::= record_aggregate | extension_aggregate | array_aggregate
-               | delta_aggregate
-
-To:
-
-   aggregate ::= record_aggregate | extension_aggregate | array_aggregate
-               | delta_aggregate | container_aggregate
-
-Modify paragraph 3/5:
-
-  The expected type for a delta_aggregate shall be a single array type,
-  or a single descendant of a record type or of a record extension. The
-  expected type for any other aggregate shall be a single array type,
-  record type, [or ]record extension{, or other composite type with the
-  Aggregate aspect specified}.
-
-Add new section: 4.3.5 Container Aggregates
-
-In a container_aggregate, values are specified for elements of a
-container; for a positional_container_aggregate, the elements are given
-sequentially; for a named_container_aggregate, the elements are
-specified by a sequence of key/value pairs, or using an iterator.
-The Aggregate aspect of the type of the aggregate determines how the
-elements are combined to form the container.
-
-Given a private type or private extension T, the following type-related
-operational aspect may be specified:
-  AARM Reason: We require the type to be a partial view so it is
-  clear that the aggregate should not be interpreted as some other
-  kind of aggregate, since syntactically it is indistinguishable.
-
-  Aggregate
-    This aspect is of the form:
-
-      (Empty => name[,
-       Add_Positional => /procedure_/name][,
-       Add_Named => /procedure_/name])
-
-    Either Add_Positional, Add_Named, or both shall be specified.
-
-Name Resolution Rules
-
-    The name specified for Empty shall denote a constant of type T,
-    or denote a function with a result type of T that has no parameters,
-    or that has one IN parameter of type Integer with a default expression.
-      AARM Reason: In the function case, the parameter, if present,
-      may be used to specify an initial size for the container, in
-      anticipation of adding elements to it.  For a positional
-      aggregate, or a named aggregate that doesn't use an iterator, it
-      will be initialized with the number of elements.  For a named
-      aggregate that uses an iterator, the implementation is permitted
-      to estimate the number of elements that the iterator will produce,
-      but it is not required to do so.
-
-    The /procedure_/name specified for Add_Positional, if any, shall
-    have two parameters, the first an IN OUT parameter of type T,
-    and the second an IN parameter of some nonlimited type, called
-    the /element type/ of T.
-
-    The /procedure_/name specified for Add_Named, if any, shall have
-    three parameters, the first an IN OUT parameter of type T,
-    the second an IN parameter of a nonlimited type, that is called the
-    /key type/ of the container, and the third, an IN parameter of a
-    nonlimited type that is called the /element type/ of T.
-
-    If both Add_Positional and Add_Named are specified, the final
-    parameters shall be of the same type -- the element type of T.
-
-
-Syntax
-
-   container_aggregate ::=
-     positional_container_aggregate | named_container_aggregate
-
-   positional_container_aggregate ::= (expression, expression {, expression)
-
-   named_container_aggregate ::= (container_element_association_list)
-
-   container_element_association_list ::=
-     container_element_association {, container_element_association}
-
-   container_element_association ::=
-     key_expression_list => expression
-   | iterated_element_association
-
-   key_expression_list ::= /key_/expression {| /key_/expression}
-
-   iterated_element_association ::=
-      for loop_parameter_specification[, /key_/expression] => expression
-    | for iterator_specification[, /key_/expression] => expression
-
-Name Resolution Rules
-
-The expected type for a container_aggregate shall be a type for which
-the Aggregate aspect has been specified.  The expected type for each
-expression of a container_aggregate is the element type of the expected
-type.
-
-The expected type for a positional_container_aggregate shall have an
-Aggregate aspect that includes a specification for an Add_Positional
-procedure.  The expected type for a named_container_aggregate that has
-one or more /key_/expressions shall have an Aggregate aspect that
-includes a specification for the Add_Named procedure.  The expected type
-for each such /key_/expression is the key type of the expected type.
-
-Legality Rules
-
-For an iterated_element_association without a /key_/expression, if the
-expected type T of the aggregate does not specify an Add_Positional
-procedure in its Aggregate aspect, then the type of the loop parameter
-of the iterated_element_association shall be the same as the key type of T.
-  AARM Ramification: If there is a /key_/expression in an
-  iterated_element_association, it determines the key of each added
-  key/value pair, rather than the loop parameter.  If there is no
-  /key_/expression, the loop parameter itself is used as the key.
-
-Dynamic Semantics
-
-The evaluation of a container_aggregate starts by creating an anonymous
-object A of the expected type T initialized by assignment from the Empty
-constant, or from a call on the Empty function specified in the Aggregate
-aspect.  In the case of an Empty function, the parameter, if any, is
-initialized as follows:
-   * for a positional_container_aggregate, the number of expressions;
-   * for a named_container_aggregate without an iterated_element_association,
-     the number of container_element_associations;
-   * otherwise, to an implementation-defined value.
-
-The evaluation then proceeds as follows:
-  * for a positional_container_aggregate, each expression is evaluated
-    in an arbitrary order, and the Add_Positional procedure is invoked in
-    sequence with the anonymous object A as the first parameter and the
-    result of evaluating each expression in the order of the expressions;
-  * for a named_container_aggregate for a type with an Add_Named procedure
-    in its Aggregate aspect, the container_element_associations are evaluated
-    in an arbitrary order:
-     * for a container_element_association with a key_expression_list,
-       for each /key_/expression of the list in an arbitrary order, the
-       /key_/expression is evaluated as is the expression of the
-       container_element_association (in an arbitrary order), and the Add_Named
-       procedure is invoked with the anonymous object A as the first
-       parameter, the result of evaluating the /key_/expression as the
-       second parameter, and the result of evaluating the expression as
-       the third parameter;
-     * for a container_element_association with an iterated_element_association,
-       the iterated_element_association is elaborated, and an iteration
-       is performed, and for each value of the loop parameter of the
-       iteration the Add_Named procedure is invoked with the anonymous
-       object A as the first parameter, the result of evaluating the
-       expression as the third parameter, and:
-          * if there is a /key_/expression, the result of evaluating
-            the /key_/expression as the second parameter;
-          * otherwise, with the loop parameter as the second parameter;
-   * for a named_container_aggregate for a type without an Add_Named
-     procedure in its Aggregate aspect, the container_element_associations
-     (which are necessarily iterated_element_associations)
-     are evaluated in the order given:
-       * the iterated_element_association is elaborated, and an iteration
-         is performed, and for each value of the loop parameter of the
-         iteration, the Add_Positional procedure is invoked with the
-         anonymous object A as the first parameter, and the result of
-         evaluating the expression as the second parameter.
-           AARM Ramification: In this case, the value of the loop parameter
-           is not directly relevant, though presumably it appears within
-           the expression of the iterated_element_association.
-
-
-Examples
-
-Declarations of Set_Type and Map_Type:
-
-   --  Set_Type is a set-like container type.
-   type Set_Type is private
-     with Aggregate => (Empty          => Empty_Set;
-                        Add_Positional => Include);
-   function Empty_Set return Set_Type;
-   
-   subtype Small_Natural is Natural range 0..1000;
-
-   procedure Include (S : in out Set_Type; N : Small_Natural);
-
-   --  Map_Type is a map-like container type.
-   type Map_Type is private
-     with Aggregate =>  (Empty      => Empty_Map;
-                         Add_Named  => Add_To_Map);
-                         
-   procedure Add_To_Map (M : in out Map_Type; Key : Integer; Value : String);
-   
-   Empty_Map : constant Map_Type;
-   
- private
-
-   type Set_Type is new Bit_Vector (Small_Natural); -- see 3.6
-
-   function Empty_Set return Set_Type is (others => False);
-   
-   package Int_String_Maps is
-     new Ada.Containers.Ordered_Maps  -- see A.18.14
-       (Key_Type => Integer; Element_Type => String);
-       
-   type Map_Type is new Int_String_Maps.Map;
-   
-   procedure Add_To_Map (M : in out Map_Type; Key : Integer; Value : String)
-     renames Insert;
-     
-   Empty_Map : constant Map_Type := Map_Type (Int_String_Maps.Empty_Map);
-   
-Examples of container aggregates for Set_Type and Map_Type
-
-   --  A positional set aggregate
-   S := (1, 2);
-
-   --  is Equivalent to:
-   S := Empty_Set;
-   Include (S, 1);
-   Include (S, 2);
-
-   --  A set aggregate with an iterated_element_association
-   S := (for Item in 1 .. 5 => Item * 2)
-
-   --  is equivalent to
-   S := Empty_Set;
-   for Item in 1 .. 5 loop
-      Include (S, Item * 2);
-   end loop;
-
-   --  A set aggregate with a filter (separate AI)
-   S := (for Item in 1 .. 100 when Is_Prime (Item) => Item);
-
-   --  is equivalent to
-   S := Empty_Set;
-   for Item in 1 .. 5 loop
-      if Is_Prime then
-         Include (S, Item);
-      end if;
-   end loop;
-
-   --  A set aggregate consisting of two iterated_element_associations
-   S := (for Item in 1 .. 5 => Item,
-         for Item in 1 .. 5 => -Item);
-
-   --  Is (mostly, assuming set semantics) equivalent to
-   S := (for Item in -5 .. 5 when Item /= 0 => Item);
-
-   --  A set aggregate with more than one item_selector (a TBD AI)
-   S := (for X in 1 .. 10 => for Y in -1 .. 1 when Y /= 0 => X * Y);
-
-   --  is equivalent to
-   S := Empty_Set;
-   for X in 1 .. 10 loop
-      for Y in -1 .. 1 loop
-         if Y /= 0 then
-            Include (S, X * Y);
-         end if;
-      end if;
-   end if;
-
-   --  An example that combines all aspects of the grammar
-   S := (for Customer of Customer_Database when not Customer.Poor =>
-           Customer.Name,
-         for Manager of Managers =>
-            for Staff of Manager.Minions when Staff.Performance >= 3.0 =>
-              Staff.First_Name & Staff.Last_Name);
-
-   --  Is equivalent to
-   S := Empty_Set;
-   for Customer of Customer_Database loop
-      if not Customer.Poor =>
-         Include (S, Customer.Name);
-      end if;
-   end loop;
-   for Manager of Managers loop
-      for Staff of Manager.Minions loop
-         if Staff.Performance => 3.0 then
-            Include (S, Staff.First_Name & Staff.Last_Name);
-         end if;
-      end loop;
-   end loop;
-   
-      
-   M : Map_Type;
-
-   --  A simple named map aggregate
-   M := (12 => "house", 14 => "beige");
-   
-   --  is equivalent to:
-   M := Empty_Map;  
-   Add_To_Map (M, 12, "house");
-   Add_To_Map (M, 14, "beige");
-   
-   --  Define a table of pairs
-   type Pair is record
-      Key : Integer;
-      Value : access constant String;
-   end record;
-   
-   Table : constant array(Positive range <>) of Pair :=
-      ((Key => 33, Value => new String'("a nice string")),
-       (Key => 44, Value => new String'("an even better string")));
-
-   --  A map aggregate using an iterated_element_association
-   --  and a key expression, built from from a table of key/value pairs:
-   M := (for P of Table, P.Key => P.Value);
-   
-   --  is equivalent to:   
-   M := Empty_Map;
-   for P of Table loop
-      Add_To_Map (M, P.Key, P.Value);
-   end loop;
-
-   --  Create an image table for an array of integers
-   Keys : constant array (Positive range <>) of Integer := (2, 3, 5, 7, 11);
-   
-   --  A map aggregate where the values produced by the
-   --  iterated_element_association are of the same type as the key
-   --  (eliminating the need for a separate key_expression):
-   M := (for Key of Keys => Integer'Image (Key));
-   
-   --  is equivalent to:
-   M := Empty_Map;
-   for Key of Keys loop
-      Add_To_Map (M, Key, Integer'Image (Key));
-   end loop;
-   
-   --  The above could have been written using an explicit key_expression:
-   M := (for Key of Keys, Key => Integer'Image (Key));
-
-A.18.2 The Generic Package Containers.Vectors
-
-Add the Aggregate aspect to the existing ones on type Vector:
-
-   type Vector is tagged private
-      with Constant_Indexing => Constant_Reference,
-           Variable_Indexing => Reference,
-           Default_Iterator  => Iterate,
-           Iterator_Element  => Element_Type,
-           Aggregate         => (Empty          => Empty_Vector,
-                                 Add_Positional => Append);
-
-A.18.3 The Generic Package Containers.Doubly_Linked_Lists
-
-Add the Aggregate aspect to the existing ones on type List:
-
-   type List is tagged private
-      with Constant_Indexing => Constant_Reference,
-           Variable_Indexing => Reference,
-           Default_Iterator  => Iterate,
-           Iterator_Element  => Element_Type,
-           Aggregate         => (Empty          => Empty_List,
-                                 Add_Positional => Append);
-
-A.18.5 The Generic Package Containers.Hashed_Maps
-
-Add the Aggregate aspect to the existing ones on type Map:
-
-   type Map is tagged private
-      with Constant_Indexing => Constant_Reference,
-           Variable_Indexing => Reference,
-           Default_Iterator  => Iterate,
-           Iterator_Element  => Element_Type,
-           Aggregate         => (Empty     => Empty_Map,
-                                 Add_Named => Insert);
-
-A.18.6 The Generic Package Containers.Ordered_Maps
-
-Add the Aggregate aspect to the existing ones on type Map:
-
-   type Map is tagged private
-      with Constant_Indexing => Constant_Reference,
-           Variable_Indexing => Reference,
-           Default_Iterator  => Iterate,
-           Iterator_Element  => Element_Type,
-           Aggregate         => (Empty     => Empty_Map,
-                                 Add_Named => Insert);
-
-A.18.8 The Generic Package Containers.Hashed_Sets
-
-Add the Aggregate aspect to the existing ones on type Set:
-
-   type Set is tagged private
-      with Constant_Indexing => Constant_Reference,
-           Default_Iterator  => Iterate,
-           Iterator_Element  => Element_Type,
-           Aggregate         => (Empty          => Empty_Set,
-                                 Add_Positional => Include);
-
-A.18.9 The Generic Package Containers.Ordered_Sets
-
-Add the Aggregate aspect to the existing ones on type Set:
-
-   type Set is tagged private
-      with Constant_Indexing => Constant_Reference,
-           Default_Iterator  => Iterate,
-           Iterator_Element  => Element_Type,
-           Aggregate         => (Empty          => Empty_Set,
-                                 Add_Positional => Include);
+4.3 Aggregates
 
+Change paragraph 2/5:
+
+   aggregate ::= record_aggregate | extension_aggregate | array_aggregate
+               | delta_aggregate
+
+To:
+
+   aggregate ::= record_aggregate | extension_aggregate | array_aggregate
+               | delta_aggregate | container_aggregate
+
+Modify paragraph 3/5:
+
+  The expected type for a delta_aggregate shall be a single array type,
+  or a single descendant of a record type or of a record extension. The
+  expected type for any other aggregate shall be a single array type,
+  record type, [or ]record extension{, or other composite type with the
+  Aggregate aspect specified}.
+
+Add new section: 4.3.5 Container Aggregates
+
+In a container_aggregate, values are specified for elements of a
+container; for a positional_container_aggregate, the elements are given
+sequentially; for a named_container_aggregate, the elements are
+specified by a sequence of key/value pairs, or using an iterator.
+The Aggregate aspect of the type of the aggregate determines how the
+elements are combined to form the container.
+
+Given a private type or private extension T, the following type-related
+operational aspect may be specified:
+  AARM Reason: We require the type to be a partial view so it is
+  clear that the aggregate should not be interpreted as some other
+  kind of aggregate, since syntactically it is indistinguishable.
+
+  Aggregate
+    This aspect is of the form:
+
+      (Empty => name[,
+       Add_Positional => /procedure_/name][,
+       Add_Named => /procedure_/name])
+
+    Either Add_Positional, Add_Named, or both shall be specified.
+
+Name Resolution Rules
+
+    The name specified for Empty shall denote a constant of type T,
+    or denote a function with a result type of T that has no parameters,
+    or that has one IN parameter of type Integer with a default expression.
+      AARM Reason: In the function case, the parameter, if present,
+      may be used to specify an initial size for the container, in
+      anticipation of adding elements to it.  For a positional
+      aggregate, or a named aggregate that doesn't use an iterator, it
+      will be initialized with the number of elements.  For a named
+      aggregate that uses an iterator, the implementation is permitted
+      to estimate the number of elements that the iterator will produce,
+      but it is not required to do so.
+
+    The /procedure_/name specified for Add_Positional, if any, shall
+    have two parameters, the first an IN OUT parameter of type T,
+    and the second an IN parameter of some nonlimited type, called
+    the /element type/ of T.
+
+    The /procedure_/name specified for Add_Named, if any, shall have
+    three parameters, the first an IN OUT parameter of type T,
+    the second an IN parameter of a nonlimited type, that is called the
+    /key type/ of the container, and the third, an IN parameter of a
+    nonlimited type that is called the /element type/ of T.
+
+    If both Add_Positional and Add_Named are specified, the final
+    parameters shall be of the same type -- the element type of T.
+
+
+Syntax
+
+   container_aggregate ::=
+     positional_container_aggregate | named_container_aggregate
+
+   positional_container_aggregate ::= (expression, expression {, expression})
+
+   named_container_aggregate ::= (container_element_association_list)
+
+   container_element_association_list ::=
+     container_element_association {, container_element_association}
+
+   container_element_association ::=
+     key_expression_list => expression
+   | iterated_element_association
+
+   key_expression_list ::= /key_/expression {| /key_/expression}
+
+   iterated_element_association ::=
+      for loop_parameter_specification[, /key_/expression] => expression
+    | for iterator_specification[, /key_/expression] => expression
+
+Name Resolution Rules
+
+The expected type for a container_aggregate shall be a type for which
+the Aggregate aspect has been specified.  The expected type for each
+expression of a container_aggregate is the element type of the expected
+type.
+
+The expected type for a positional_container_aggregate shall have an
+Aggregate aspect that includes a specification for an Add_Positional
+procedure.  The expected type for a named_container_aggregate that has
+one or more /key_/expressions shall have an Aggregate aspect that
+includes a specification for the Add_Named procedure.  The expected type
+for each such /key_/expression is the key type of the expected type.
+
+Legality Rules
+
+For an iterated_element_association without a /key_/expression, if the
+expected type T of the aggregate does not specify an Add_Positional
+procedure in its Aggregate aspect, then the type of the loop parameter
+of the iterated_element_association shall be the same as the key type of T.
+  AARM Ramification: If there is a /key_/expression in an
+  iterated_element_association, it determines the key of each added
+  key/value pair, rather than the loop parameter.  If there is no
+  /key_/expression, the loop parameter itself is used as the key.
+
+Dynamic Semantics
+
+The evaluation of a container_aggregate starts by creating an anonymous
+object A of the expected type T initialized by assignment from the Empty
+constant, or from a call on the Empty function specified in the Aggregate
+aspect.  In the case of an Empty function, the parameter, if any, is
+initialized as follows:
+   * for a positional_container_aggregate, the number of expressions;
+   * for a named_container_aggregate without an iterated_element_association,
+     the number of container_element_associations;
+   * otherwise, to an implementation-defined value.
+
+The evaluation then proceeds as follows:
+  * for a positional_container_aggregate, each expression is evaluated
+    in an arbitrary order, and the Add_Positional procedure is invoked in
+    sequence with the anonymous object A as the first parameter and the
+    result of evaluating each expression in the order of the expressions;
+  * for a named_container_aggregate for a type with an Add_Named procedure
+    in its Aggregate aspect, the container_element_associations are evaluated
+    in an arbitrary order:
+     * for a container_element_association with a key_expression_list,
+       for each /key_/expression of the list in an arbitrary order, the
+       /key_/expression is evaluated as is the expression of the
+       container_element_association (in an arbitrary order), and the Add_Named
+       procedure is invoked with the anonymous object A as the first
+       parameter, the result of evaluating the /key_/expression as the
+       second parameter, and the result of evaluating the expression as
+       the third parameter;
+     * for a container_element_association with an iterated_element_association,
+       the iterated_element_association is elaborated, and an iteration
+       is performed, and for each value of the loop parameter of the
+       iteration the Add_Named procedure is invoked with the anonymous
+       object A as the first parameter, the result of evaluating the
+       expression as the third parameter, and:
+          * if there is a /key_/expression, the result of evaluating
+            the /key_/expression as the second parameter;
+          * otherwise, with the loop parameter as the second parameter;
+   * for a named_container_aggregate for a type without an Add_Named
+     procedure in its Aggregate aspect, the container_element_associations
+     (which are necessarily iterated_element_associations)
+     are evaluated in the order given:
+       * the iterated_element_association is elaborated, and an iteration
+         is performed, and for each value of the loop parameter of the
+         iteration, the Add_Positional procedure is invoked with the
+         anonymous object A as the first parameter, and the result of
+         evaluating the expression as the second parameter.
+           AARM Ramification: In this case, the value of the loop parameter
+           is not directly relevant, though presumably it appears within
+           the expression of the iterated_element_association.
+
+
+Examples
+
+Declarations of Set_Type and Map_Type:
+
+   --  Set_Type is a set-like container type.
+   type Set_Type is private
+     with Aggregate => (Empty          => Empty_Set;
+                        Add_Positional => Include);
+   function Empty_Set return Set_Type;
+
+   subtype Small_Natural is Natural range 0..1000;
+
+   procedure Include (S : in out Set_Type; N : Small_Natural);
+
+   --  Map_Type is a map-like container type.
+   type Map_Type is private
+     with Aggregate =>  (Empty      => Empty_Map;
+                         Add_Named  => Add_To_Map);
+
+   procedure Add_To_Map (M : in out Map_Type; Key : Integer; Value : String);
+
+   Empty_Map : constant Map_Type;
+
+ private
+
+   type Set_Type is new Bit_Vector (Small_Natural); -- see 3.6
+
+   function Empty_Set return Set_Type is (others => False);
+
+   package Int_String_Maps is
+     new Ada.Containers.Indefinite_Ordered_Maps  -- see A.18.14
+       (Key_Type => Integer, Element_Type => String);
+
+   type Map_Type is new Int_String_Maps.Map with null record;
+
+   procedure Add_To_Map (M : in out Map_Type; Key : Integer; Value : String)
+     renames Insert;
+
+   Empty_Map : constant Map_Type :=
+     (Int_String_Maps.Empty_Map with null record);
+
+Examples of container aggregates for Set_Type and Map_Type
+
+   --  A positional set aggregate
+   S := (1, 2);
+
+   --  is Equivalent to:
+   S := Empty_Set;
+   Include (S, 1);
+   Include (S, 2);
+
+   --  A set aggregate with an iterated_element_association
+   S := (for Item in 1 .. 5 => Item * 2)
+
+   --  is equivalent to
+   S := Empty_Set;
+   for Item in 1 .. 5 loop
+      Include (S, Item * 2);
+   end loop;
+
+   --  A set aggregate with a filter (separate AI)
+   S := (for Item in 1 .. 100 when Is_Prime (Item) => Item);
+
+   --  is equivalent to
+   S := Empty_Set;
+   for Item in 1 .. 5 loop
+      if Is_Prime then
+         Include (S, Item);
+      end if;
+   end loop;
+
+   --  A set aggregate consisting of two iterated_element_associations
+   S := (for Item in 1 .. 5 => Item,
+         for Item in 1 .. 5 => -Item);
+
+   --  Is (mostly, assuming set semantics) equivalent to
+   S := (for Item in -5 .. 5 when Item /= 0 => Item);
+
+   --  A set aggregate with more than one item_selector (a TBD AI)
+   S := (for X in 1 .. 10 => for Y in -1 .. 1 when Y /= 0 => X * Y);
+
+   --  is equivalent to
+   S := Empty_Set;
+   for X in 1 .. 10 loop
+      for Y in -1 .. 1 loop
+         if Y /= 0 then
+            Include (S, X * Y);
+         end if;
+      end if;
+   end if;
+
+   --  An example that combines all aspects of the grammar
+   S := (for Customer of Customer_Database when not Customer.Poor =>
+           Customer.Name,
+         for Manager of Managers =>
+            for Staff of Manager.Minions when Staff.Performance >= 3.0 =>
+              Staff.First_Name & Staff.Last_Name);
+
+   --  Is equivalent to
+   S := Empty_Set;
+   for Customer of Customer_Database loop
+      if not Customer.Poor =>
+         Include (S, Customer.Name);
+      end if;
+   end loop;
+   for Manager of Managers loop
+      for Staff of Manager.Minions loop
+         if Staff.Performance => 3.0 then
+            Include (S, Staff.First_Name & Staff.Last_Name);
+         end if;
+      end loop;
+   end loop;
+
+
+   M : Map_Type;
+
+   --  A simple named map aggregate
+   M := (12 => "house", 14 => "beige");
+
+   --  is equivalent to:
+   M := Empty_Map;
+   Add_To_Map (M, 12, "house");
+   Add_To_Map (M, 14, "beige");
+
+   --  Define a table of pairs
+   type Pair is record
+      Key : Integer;
+      Value : access constant String;
+   end record;
+
+   Table : constant array(Positive range <>) of Pair :=
+      ((Key => 33, Value => new String'("a nice string")),
+       (Key => 44, Value => new String'("an even better string")));
+
+   --  A map aggregate using an iterated_element_association
+   --  and a key expression, built from from a table of key/value pairs:
+   M := (for P of Table, P.Key => P.Value);
+
+   --  is equivalent to:
+   M := Empty_Map;
+   for P of Table loop
+      Add_To_Map (M, P.Key, P.Value);
+   end loop;
+
+   --  Create an image table for an array of integers
+   Keys : constant array (Positive range <>) of Integer := (2, 3, 5, 7, 11);
+
+   --  A map aggregate where the values produced by the
+   --  iterated_element_association are of the same type as the key
+   --  (eliminating the need for a separate key_expression):
+   M := (for Key of Keys => Integer'Image (Key));
+
+   --  is equivalent to:
+   M := Empty_Map;
+   for Key of Keys loop
+      Add_To_Map (M, Key, Integer'Image (Key));
+   end loop;
+
+   --  The above could have been written using an explicit key_expression:
+   M := (for Key of Keys, Key => Integer'Image (Key));
+
+A.18.2 The Generic Package Containers.Vectors
+
+Add the Aggregate aspect to the existing ones on type Vector:
+
+   type Vector is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Variable_Indexing => Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Aggregate         => (Empty          => Empty_Vector,
+                                 Add_Positional => Append);
+
+A.18.3 The Generic Package Containers.Doubly_Linked_Lists
+
+Add the Aggregate aspect to the existing ones on type List:
+
+   type List is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Variable_Indexing => Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Aggregate         => (Empty          => Empty_List,
+                                 Add_Positional => Append);
+
+A.18.5 The Generic Package Containers.Hashed_Maps
+
+Add the Aggregate aspect to the existing ones on type Map:
+
+   type Map is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Variable_Indexing => Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Aggregate         => (Empty     => Empty_Map,
+                                 Add_Named => Insert);
+
+A.18.6 The Generic Package Containers.Ordered_Maps
+
+Add the Aggregate aspect to the existing ones on type Map:
+
+   type Map is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Variable_Indexing => Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Aggregate         => (Empty     => Empty_Map,
+                                 Add_Named => Insert);
+
+A.18.8 The Generic Package Containers.Hashed_Sets
+
+Add the Aggregate aspect to the existing ones on type Set:
+
+   type Set is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Aggregate         => (Empty          => Empty_Set,
+                                 Add_Positional => Include);
+
+A.18.9 The Generic Package Containers.Ordered_Sets
+
+Add the Aggregate aspect to the existing ones on type Set:
+
+   type Set is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Aggregate         => (Empty          => Empty_Set,
+                                 Add_Positional => Include);
+
 !discussion
+
+See !proposal for most of the discussion.  Here we discuss some rejected
+alternatives or additions.
+
+We plan to generalize array aggregates as well to allow arbitrary
+iterators, probably in a separate AI, or perhaps a subsequent revision
+of this one.  Originally we were concerned about making this
+generalization, because to determine the size of the array to create,
+you will need to execute the iterator until it ends. We initially
+presumed you would have to save all of the values somewhere, create the
+array, and finally initialize the array components. However, by just
+getting cursors but not the actual iterator elements, you can do the
+iteration efficiently and determine an upper bound for the size of the
+array.
+
+
+We use a simple "," to separate the iterator from the key => value
+when there is an explicit key_expression:
+
+As illustrated in an example above, we write:
+
+   M := (for P of Table, P.Key => P.Value);  --  yes
 
-See !proposal for most of the discussion.  Here we discuss some rejected
-alternatives or additions.
-
-Array aggregates have *not* been generalized:
-
-We considered extending the use of generalized iterators to allow them
-in array aggregates, but that becomes quite awkward because to determine
-the size of the array to create, you need to execute the iterator until
-it ends, save all of the values somewhere, create the array, and finally
-initialize the array components. This is something that would
-effectively require a temporary Vector, and that seems like something we
-don't want to bury inside the array aggregate syntax.  So if someone
-wants to create such an array, they should create a temporary Vector
-using a container aggregate, and then write an array aggregate using an
-iterated_component_association such as:
-
-  Temp_Vec : My_Vec := (for E of Container when Blah(E) => F(E));
-
-  Arr : My_Arr := (for I in 1..Length(Temp_Vec) => Temp_Vec(I));
-
-We use a simple "," to separate the iterator from the key => value
-when there is an explicit key_expression:
-
-As illustrated in an example above, we write:
-
-   M := (for P of Table, P.Key => P.Value);  --  yes
-   
-We considered using two "=>" but we believe it made it harder to read:
-
-   M := (for P of Table => P.Key => P.Value);  --  no, harder to read
-   
-The comma seems to read quite nicely, without any need for extra parentheses,
-or multiple "=>"s.
+We considered using two "=>" but we believe it made it harder to read:
 
+   M := (for P of Table => P.Key => P.Value);  --  no, harder to read
+
+The comma seems to read quite nicely, without any need for extra parentheses,
+or multiple "=>"s.
+
 !ASIS
 
 !ACATS test
@@ -1740,9 +1736,196 @@
 iterators to array aggregates, and also discussed the syntax of "map"
 container aggregates when the key is specified explicitly in the presence
 of an iterator.
- 
+
 Here is a cut-and-paste, followed by an attachment.  Hopefully one of them
 comes through legibly. [This is version /03 of the AI - Editor.]
 
 ****************************************************************
 
+From: John Barnes
+Sent: Sunday, February 11, 2018  8:57 AM
+
+This looks pretty good to me. No sign of excessive function expressions. Or if
+there is, it has been adequately filtered by a bottle of decent claret.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Sunday, February 11, 2018  10:52 AM
+
+Thanks, John.  Sounds like you should share some of that claret with the rest
+of the ARG... ;-)
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Sunday, February 11, 2018  10:30 AM
+
+Randy pointed out that for an array aggregate, we could avoid actually getting
+the values of a generalized iterator, but instead just get cursors, and count
+the number of values to be produced that way.  An applicable index constraint
+could also provide the bounds.  Even if there were a filter, you could ignore
+the filter for the purposes of creating a temporary to hold the values, and
+determine the final bounds after you fill in the potentially overly large
+temp.  So perhaps the advantage of treating things like arrays and vectors
+symmetrically argues for allowing array aggregates to use generalized
+iterators.  I will write that up as a separate AI.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Monday, February 12, 2018  4:18 PM
+
+> Finally, it is also a common pattern to combine multiple containers
+> into one. Three approaches are supported. .....
+>
+> This is the sequential (or "list") one:
+>
+>    V : My_Set := (for A of X => A,
+>                   for A of X => -A);
+
+I would feel happier if sequentiality were expressed with ";" or "&" not ",".
+
+Without explanation, I would have guessed that the construct above yields a
+list of tuples (A, -A).
+
+So, for the sequential case, my suggestion is
+    V : My_Set := (for A of X => A;
+                   for A of X => -A);
+or even preferred:
+    V : My_Set := (for A of X => A) & (for A of X => -A);
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, February 12, 2018  4:32 PM
+
+I believe "," is already allowed in array aggregates with two
+iterated_component_associations, so it would be a bit odd to switch to ";"
+here for container aggregates.
+
+Of course "&" is allowed, presuming "&" is defined for the container type,
+though you might end up requiring a type qualifier to resolve it, if you
+provide the usual four definitions for "&" (i.e. C & C, C & E, E & C, E & E)
+and the element type is composite.
+
+****************************************************************
+
+From: Jeff Cousins
+Sent: Wednesday, February 14, 2018  1:41 PM
+
+Thanks Tuck, that’s more comprehensible than some of the reduce stuff.
+
+A few comments.
+
+In the syntax,
+
+positional_container_aggregate ::= (expression, expression {, expression)
+
+is missing the closing }
+
+In the examples, as String is indefinite it needs to be an
+Indefinite_Ordered_Map (the reference is actually correct), and the separator
+should be , not ; in the parameter list.
+
+   package Int_String_Maps is
+     new Ada.Containers.Indefinite_Ordered_Maps  -- see A.18.14
+       (Key_Type => Integer, Element_Type => String);
+
+Extending a tagged type requires an extension
+
+   type Map_Type is new Int_String_Maps.Map with null record;
+
+The following is a “downward conversion”:
+
+   Empty_Map : constant Map_Type := Map_Type (Int_String_Maps.Empty_Map);
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, February 14, 2018  2:39 PM
+
+Thanks for the corrections.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, February 14, 2018  2:50 PM
+
+Here is an update, with Jeff's corrections. [This is version /04 of the AI
+- Editor.]
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, February 27, 2018  5:56 PM
+
+> Here is an update, with Jeff's corrections. 
+
+I'm just getting around to reading this. Comments:
+
+For some reason, you numbered this "version 5" (and the previous one "version
+4"), but there never was a version 3. So you are off by one for the version
+numbers. (This one was posted as version /04.)
+
+---
+
+The syntax for aspect Aggregate separates the parts with commas, but the
+examples use semicolons. (I'd expect commas to be consistent with similar
+syntax elsewhere in Ada, but whatever it is should be consistent.)
+
+---
+
+13.1.1 gives a list of things that can be an aspect. This new syntax for
+aspect Aggregate is not one of those things. Note that when I was faced with
+a similar issue for aspect Stable_Properties, I extended the syntax in 13.1.1.
+We do have a blanket "alternative rules may apply" statement, but it would be
+best if we made all of the language-defined aspects as consistent as possible.
+One possibility would be to make "aggregate" a syntactic choice here, and then
+redo Stable_Properties in terms of that (stable properties needing a list, for
+which positional aggregate syntax would be fine).
+
+Maybe we should do that here, maybe in another AI.
+
+---
+
+You and I have swapped positions on the iterated choices. :-) I now think that
+they ought to be treated like others (which isn't allowed here) -- that is,
+they can appear in positional aggregates, but only if they appear last. That's
+the only way to make vector and array aggregates near identical, because the
+iterated choice (except for the "traditional" discrete range one) doesn't
+provide the indexes needed for a named array aggregate. And all of them (again
+except for the "traditional" discrete range one) can't appear in a named array
+aggregate without a key expression (which is really the index expression for
+an array aggregate).
+
+We probably need to figure out the array aggregate rules for this, because it
+doesn't do for container aggregates and array aggregates to work very
+differently in this case (or any case, when it comes to vector aggregates).
+
+---
+
+Erhard complained about using "," to represent sequentiality -- but this is an
+aggregate, and the choices can be evaluated in an arbitrary order. Ergo, it
+ISN'T representing sequentiality, just proximity. ";" (which does represent
+sequentiality) would be wrong.
+
+---
+
+If we want array and vector aggregates to really be similar, then we need a
+named vector aggregate option. This would best be somewhat separate from the
+map aggregate, so that the requirements on named array and vector aggregates
+are identical.
+
+Ergo, I'd suggest a third choice (maybe "Add_Indexed") which requires that the
+key type is discrete; then choices that are ranges would be allowed, and
+non-overlap checking (with the only one dynamic choice rule) could be
+enforced. Essentially, the legality rules would match an array aggregate sans
+"others" (no others as there is no sane way to get an applicable index
+constraint). (The dynamic rules would be essentially the same as Add_Named).
+
+---
+
+That's all I have at this point.
+  
+****************************************************************

Questions? Ask the ACAA Technical Agent