CVS difference for 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