CVS difference for ai12s/ai12-0212-1.txt
--- ai12s/ai12-0212-1.txt 2018/01/27 04:54:51 1.7
+++ ai12s/ai12-0212-1.txt 2018/02/27 23:07:58 1.8
@@ -1,4 +1,4 @@
-!standard 4.3.5(0) 18-01-24 AI12-0212-1/02
+!standard 4.3.5(0) 18-02-09 AI12-0212-1/03
!class Amendment 16-12-27
!status work item 17-06-10
!status received 16-06-12
@@ -37,468 +37,577 @@
!proposal
-Thus, we propose to add new aspect (in the spirit of Constant_Indexing,
-Default_Iterator, and Iterator_Element) along with two new aggregates to use it.
+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
-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 syntax is highly inspired by Python (please do not let that put you off), it
-just is more Ada-like than comprehension in, say, Haskell.
-
-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:
-
- 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 things you specify in the
-Aggregate aspect, the procedure "Include" is the other.
-
-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. Thy
-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.
-Two 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");
-
-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
-
-Related changes:
-
-This AI will have some interesting interplay with declare expressions and
-generators.
-
!wording
-
-4.3 Aggregates (Syntax)
-
-Change paragraph 2/5:
-
- aggregate ::= record_aggregate | extension_aggregate | array_aggregate
- | delta_aggregate
-To:
+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);
- 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 any 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 any order:
- * for a container_element_association with a key_expression_list,
- for each /key_/expression of the list in any order, the
- /key_/expression is evaluated as is the expression of the
- container_element_association (in any 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
-
-I KNOW I NEED TO REWORK THESE TO USE EXISTING THINGS IN THE RM
-
- -- Declares a container type.
- type Set_Type is private
- with Aggregate => (Empty => Empty_Set;
- Add_Positional => Merge);
- function Empty_Set return Set_Type;
-
- procedure Merge (S : in out Set_Type; N : Integer)
- with Pre => N in 0 .. 1000;
-
- private
-
- type Set_Type is array (0 .. 1000) of Boolean
-
- function Empty_Set return Set_Type is (others => False);
-
- -- A positional set aggregate
- S := (1, 2);
-
- -- is Equivalent to:
- S := Empty_Set;
- S.Include (1);
- S.Include (2);
-
- -- A named map aggregate
- M := (12 => "house", 14 => "beige");
-
- -- 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
- S.Include (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
- S.Include (Item);
- end if;
- end loop;
-
- -- A set aggregate consisting out 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
- S.Include (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 =>
- S.Include (Customer.Name);
- end if;
- end loop;
- for Manager of Managers loop
- for Staff of Manager.Minions loop
- if Staff.Performance => 3.0 then
- S.Include (Staff.First_Name & Staff.Last_Name);
- end if;
- end loop;
- end loop;
-
-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.
+
+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.
+
!ASIS
!ACATS test
@@ -1148,7 +1257,8 @@
> "evaluated to a single value", doesn't match freezing rules, and
> probably more. I suppose your intent is that this would have to be
> implemented with aspect-specific code anyway, so it isn't a hardship
-> to take an uninterpreted tree (required by aspects anyway) and apply a custom interpretation to it.
+> to take an uninterpreted tree (required by aspects anyway) and apply a
+> custom interpretation to it.
>
> However, if we're going to use a clever hack here, we have to define
> it properly (with rule changes in 13.1.1). Also, we ought to do the
@@ -1255,7 +1365,8 @@
> There aren't any examples of named aggregates, I was trying to figure
> out the usage of the key_expression in an iterator and didn't find any.
-Good point. Here is a simple one where you have a table of keys and values, and you want to create a mapping built from that table:
+Good point. Here is a simple one where you have a table of keys and values,
+and you want to create a mapping built from that table:
Map : constant Mapping := (for I in Table'Range, Table(I).Key => Table(I).Value);
@@ -1607,6 +1718,31 @@
3. Our proposal is more advanced in terms of features already.
That's it !
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, January 29, 2018 10:18 AM
+
+Here is an example missing from the AI, showing how key_expression is used for
+specifying a map, when the iterator loop parameter is *not* the key to use:
+
+ Map : constant Mapping := (for I in Table'Range, Table(I).Key => Table(I).Value);
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Saturday, February 10, 2018 12:12 PM
+
+Here is another update to the write-up of container aggregates. I
+re-organized and enhanced the examples a bit. In the !discussion section,
+I added a paragraph about why we are *not* extending the generalized
+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.]
****************************************************************
Questions? Ask the ACAA Technical Agent