CVS difference for ai12s/ai12-0212-1.txt
--- ai12s/ai12-0212-1.txt 2018/07/15 00:25:58 1.14
+++ ai12s/ai12-0212-1.txt 2018/10/19 01:23:14 1.15
@@ -1,4 +1,4 @@
-!standard 4.3.5(0) 18-03-13 AI12-0212-1/06
+!standard 4.3.5(0) 18-10-17 AI12-0212-1/07
!class Amendment 16-12-27
!status work item 17-06-10
!status received 16-06-12
@@ -7,29 +7,32 @@
!subject Container aggregates; generalized array aggregates
!summary
-Add aggregate syntax to construct container instances. Allow
-container iterators in array aggregates.
+Add aggregate syntax to construct container instances, using a syntax
+based on array aggregates, but using square brackets ("[...]"). Allow
+container iterators in array aggregates, and permit the use of square
+brackets, which eases the specification of a null array and a
+single-element array, without resorting to somewhat awkward named notation.
!problem
Currently, there are very few constructors for containers. We have for
-example the constant Empty_Set, and To_Set to construct a set containing
-the specified element. The best way to do this now is to manually
-assemble a new container with a series of statements; but this has a
-number of issues:
+example in the Set container package, the constant Empty_Set, and To_Set
+to construct a set containing the specified element. The best way to do
+this now is to manually assemble a new container with a series of
+statements; but this has a number of issues:
- cannot be used in a subprogram contract (such as a post condition)
- can make code harder to read since construction has to be moved to a
separate function
-An obvious approach would be to add functions that initialise a
+One approach would be to add functions that initialise a
container from an aggregate of an unconstrained array, for example:
X : Example.Set := Example.From_Array ((1, 2, 3));
However there are a number of drawbacks: the syntax is ugly (double
brackets), it would not allow comprehensions (i.e. containers defined by
-a nested iterator) (only displays -- i.e. an explicit list of
+a nested iterator), only displays (i.e. an explicit list of
components), and it would only work for array-like containers and not
maps.
@@ -52,11 +55,41 @@
and set "comprehensions," but it uses, largely, Ada's array aggregate as the
basis for the syntax.
+One challenge with existing array aggregates is that an empty array
+aggregate (a "null array" in Ada parlance) requires the use of a null
+range. When the container is not indexed by contiguous discrete key values,
+this poses a bit of a problem. Single-element array aggregates are also
+awkward in Ada, in that positional notation cannot be used. Therefore,
+we propose to adopt the use of square brackets ("[...]") for container
+aggregates.
+
+We also propose (though it is not essential to the container aggregate
+proposal and could be carved out) to permit the use of square brackets
+for array aggregates, which would allow the use of "[]" as an empty
+array aggregate, with semantics like that of empty string literals. We
+do not propose to permit the use of square brackets for record or
+extension aggregates, as we believe arrays and containers are similar,
+in that they represent a data structure made of elements all of the same
+type, while record aggregates are inherently a different beast, and
+already have their own special "(null record)" syntax for the rare empty
+record aggregate. Furthermore, by disallowing record-ish aggregates from
+using square brackets, we can allow container aggregates for visible
+record or record extensions, rather than restricting them to private
+types. Finally, we already somewhat equated arrays and containers in
+the "for X of Container_Or_Array ..." iterator syntax, while there is
+(of course!) no corresponding iteration defined over a record type.
+
+For delta aggregates, square brackets would be permitted for
+array delta aggregates, but not for record delta aggregates.
+
+At some point, we could also imagine permitting the use of square brackets
+for array (and container) indexing, but we see that as a separate AI.
+
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);
+ X : My_Set := [1, 2, 3];
-- Equivalent to:
X : My_Set := Empty_Set;
@@ -78,7 +111,7 @@
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);
+ Y : My_Set := [for Item of X => Item * 2];
-- Equivalent to:
Y : My_Set := Empty_Set;
@@ -88,7 +121,7 @@
We may also wish to filter the items:
- Z : My_Set := (for Item of X when Item > 1 => Item - 1);
+ Z : My_Set := [for Item of X when Item > 1 => Item - 1];
-- Equivalent to:
Z : My_Set := Empty_Set;
@@ -102,8 +135,8 @@
one. Three approaches are considered. This is the nested (or "product") one
(note that this is not part of the current proposal):
- W : My_Set := (for A of X =>
- for B of X => A * B); -- TBD: Not currently in this AI
+ 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;
@@ -117,8 +150,8 @@
capability in the array aggregate to have multiple iterated component
associations in a single aggregate:
- V : My_Set := (for A of X => A,
- for A of X => -A);
+ V : My_Set := [for A of X => A,
+ for A of X => -A]; -- This *is* part of this AI
-- Equivalent to:
V : My_Set := Empty_Set;
@@ -135,8 +168,8 @@
in that the two iterators are advanced concurrently, stopping when
either one finishes):
- V : My_Set := (for (A of X; I in 1..Max) => (A, I));
- -- TBD: Not currently in this AI yet
+ V : My_Set := [for (A of X; I in 1..Max) => (A, I)];
+ -- TBD: *Not* currently part of this AI
-- Equivalent to:
V : My_Set := Empty_Set;
@@ -161,8 +194,8 @@
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");
+ M : My_Map := [42 => "foo",
+ 88 => "bar"];
This is equivalent to:
@@ -187,6 +220,10 @@
Add_Named procedure, or an Add_Unnamed procedure and/or an
Assign_Indexed procedure (with a New_Indexed function to go with it).
* Extend aggregate syntax to support these based on the expected type
+* Use square brackets for container aggregates (to solve the empty
+ aggregate problem and simplify the singleton aggregate); also
+ permit the square bracket syntax in array aggregates, and array delta
+ aggregates.
We also provide wording to allow container iterators within an
array aggregate.
@@ -220,11 +257,28 @@
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}.
-
----- wording for adding container iterators to array aggregates:
+ expected type for [any other aggregate] {an array aggregate, a
+ record_aggregate, or an extension_aggregate} shall be a single array
+ type, record type, or record extension. {The expected type for a container
+ aggregate shall be a single array type or a single type with
+ the Aggregate aspect specified.}
+
+---- wording for adding container iterators to array aggregates
+---- and allowing the use of "[...]"
+
+Replace 4.3.3(3/2) with:
+ positional_array_aggregate ::=
+ (expression, expression {, expression})
+ | (expression {, expression}, others => expression)
+ | (expression {, expression}, others => <>)
+ | [ expression{, expression}[, others => expression] ]
+ | [ expression{, expression}, others => <> ]
+ | [ ]
+
+Replace 4.3.3(4/5) with:
+ named_array_aggregate ::=
+ (array_component_association_list)
+ | [array_component_association_list]
Replace 4.3.3(5.1/5):
@@ -237,13 +291,18 @@
for defining_identifier in discrete_choice_list => expression
| for iterator_specification => expression
+Modify 4.3.3(9):
+
+ An array_aggregate of an n-dimensional array type shall be written as
+ an n-dimensional array_aggregate{, or as a /null aggregate/ -- [ ]}.
+
Add after 4.3.3(17/5):
Either all or none of the array_component_associations of an
array_component_association_list shall be iterated_component_associations
with an iterator_specification.
-Add 4.2.3(20) as follows:
+Add 4.3.3(20) as follows:
For an array_aggregate that contains only
array_component_associations that are iterated_component_associations
with iterator_specifications, evaluation proceeds in two steps:
@@ -261,7 +320,7 @@
value of the next component of the array starting at the low bound
and proceeding sequentially toward the high bound.
-Modify 4.2.3(21) as follows:
+Modify 4.3.3(21) as follows:
The evaluation of [an] {any other} array_aggregate of a given
array type proceeds in two steps:
@@ -283,11 +342,24 @@
an OTHERS choice, and the upper bound is determined from the lower
bound and the total number of values produced by the iteration(s);
----- end of wording for array aggregate enhancement ----
+Modify 4.3.3(30):
+ For a multidimensional array_aggregate, a check is made that all
+ subaggregates that correspond to the same index have the same bounds.
+ {For a null aggregate used to define the value of a multidimensional
+ array type, bounds for each dimension are determined as for a
+ positional_array_aggregate with zero expressions.}
-Add new section:
+Replace 4.3.4(4/5) with:
+ array_delta_aggregate ::=
+ (base_expression with delta array_component_association_list)
+ | [base_expression with delta array_component_association_list]
+
+---- end of wording for array [delta] aggregate enhancement ----
+
+---- Add new section, 4.3.5, for container aggregates:
+
4.3.5 Container Aggregates
In a container_aggregate, values are specified for elements of a
@@ -297,11 +369,8 @@
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
+Given a type T other than an array type, 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 an aggregate of the form:
@@ -315,7 +384,10 @@
A /procedure_/name shall be specified for at least one of Add_Named,
Add_Unnamed, or Assign_Indexed. If Add_Named is specified, neither
Add_Unnamed nor Assign_Indexed shall be specified. Either both or
- neither of New_Indexed and Assign_Indexed shall be specified.
+ neither of New_Indexed and Assign_Indexed shall be specified. If the
+ associated type T is a private type, the full type shall not be an
+ array type. If type T is limited, the name specified for Empty
+ shall denote a function rather than a constant object.
Name Resolution Rules
@@ -354,16 +426,20 @@
If both Add_Unnamed and Assign_Indexed are specified, the final
parameters shall be of the same type -- the element type of T.
+Static Semantics
+
+ The Aggregate aspect is nonoverridable.
+
Syntax
- container_aggregate ::= empty_container_aggregate
+ container_aggregate ::= null_container_aggregate
| positional_container_aggregate | named_container_aggregate
- empty_container_aggregate ::= (<>)
+ null_container_aggregate ::= [ ]
- positional_container_aggregate ::= (expression, expression {, expression})
+ positional_container_aggregate ::= [ expression{, expression} ]
- named_container_aggregate ::= (container_element_association_list)
+ named_container_aggregate ::= [ container_element_association_list ]
container_element_association_list ::=
container_element_association {, container_element_association}
@@ -378,8 +454,8 @@
key_choice ::= /key_/expression | discrete_range
iterated_element_association ::=
- for loop_parameter_specification[, /key_/expression] => expression
- | for iterator_specification[, /key_/expression] => expression
+ for loop_parameter_specification[ use /key_/expression] => expression
+ | for iterator_specification[ use /key_/expression] => expression
Name Resolution Rules
@@ -402,10 +478,10 @@
procedure. The expected type for a named_container_aggregate that
contains one or more key_choice_lists shall have an Aggregate aspect
that includes a specification for the Add_Named or Assign_Indexed
-procedure. [Redundant: (An empty_container_aggregate can be of any type
+procedure. [Redundant: (A null_container_aggregate can be of any type
with an Aggregate aspect.)]
-A non-empty container aggregate is called an /indexed aggregate/ if the
+A non-null container aggregate is called an /indexed aggregate/ if the
expected type T of the aggregate specifies an Assign_Indexed procedure
in its Aggregate aspect, and either there is no Add_Unnamed procedure
specified for the type, or the aggregate is a named_container_aggregate
@@ -473,7 +549,7 @@
Empty constant, or from a call on the Empty function specified in
the Aggregate aspect. In the case of an Empty function with a formal
parameter, the actual parameter has the following value:
- * for an empty_container_aggregate, the value zero;
+ * for a null_container_aggregate, the value zero;
* for a positional_container_aggregate, the number of expressions;
* for a named_container_aggregate without an iterated_element_association,
the number of /key_/expressions;
@@ -484,7 +560,7 @@
* otherwise, to an implementation-defined value.
The evaluation then proceeds as follows:
- * for an empty_container_aggregate, the anonymous object A is the result;
+ * for a null_container_aggregate, the anonymous object A is the result;
* for a positional_container_aggregate of a type with a specified
Add_Unnamed procedure, each expression is evaluated in an arbitrary
order, and the Add_Unnamed procedure is invoked in sequence with the
@@ -605,15 +681,18 @@
type Vector_Type is new String_Vectors.Vector;
Examples of container aggregates for Set_Type, Map_Type, and Vector_Type
+
+ -- Example aggregates using Set_Type
+ S : Set_Type;
- -- Assign S to an empty set
- S := (<>);
+ -- Assign S to be the empty set
+ S := [];
-- Is Equivalent to:
S := Empty_Set;
-- A positional set aggregate
- S := (1, 2);
+ S := [1, 2];
-- is Equivalent to:
S := Empty_Set;
@@ -621,7 +700,7 @@
Include (S, 2);
-- A set aggregate with an iterated_element_association
- S := (for Item in 1 .. 5 => Item * 2)
+ S := [for Item in 1 .. 5 => Item * 2]
-- is equivalent to
S := Empty_Set;
@@ -630,7 +709,7 @@
end loop;
-- A set aggregate with a filter (separate AI)
- S := (for Item in 1 .. 100 when Is_Prime (Item) => Item);
+ S := [for Item in 1 .. 100 when Is_Prime (Item) => Item];
-- is equivalent to
S := Empty_Set;
@@ -641,23 +720,23 @@
end loop;
-- A set aggregate consisting of two iterated_element_associations
- S := (for Item in 1 .. 5 => Item,
- for Item in 1 .. 5 => -Item);
+ S := [for Item in 1 .. 5 => Item,
+ for Item in 1 .. 5 => -Item];
-- Is equivalent (assuming set semantics) to
- S := (for Item in -5 .. 5 when Item /= 0 => Item);
+ S := [for Item in -5 .. 5 when Item /= 0 => Item];
-- Example aggregates using Map_Type
M : Map_Type;
-- Create an empty map
- M := (<>);
+ M := [];
-- is equivalent to:
M := Empty_Map;
-- A simple named map aggregate
- M := (12 => "house", 14 => "beige");
+ M := [12 => "house", 14 => "beige"];
-- is equivalent to:
M := Empty_Map;
@@ -671,12 +750,12 @@
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")));
+ [(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);
+ M := [for P of Table use P.Key => P.Value];
-- is equivalent to:
M := Empty_Map;
@@ -685,12 +764,12 @@
end loop;
-- Create an image table for an array of integers
- Keys : constant array (Positive range <>) of Integer := (2, 3, 5, 7, 11);
+ 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));
+ M := [for Key of Keys => Integer'Image (Key)];
-- is equivalent to:
M := Empty_Map;
@@ -699,19 +778,19 @@
end loop;
-- The above could have been written using an explicit key_expression:
- M := (for Key of Keys, Key => Integer'Image (Key));
+ M := [for Key of Keys, Key => Integer'Image (Key)];
-- Example aggregates using Vector_Type
V : Vector_Type;
-- Create an empty vector aggregate
- V := (<>);
+ V := [];
-- Is equivalent to:
V := Empty_Vector (0);
-- A positional vector aggregate
- V := ("abc", "def");
+ V := ["abc", "def"];
-- Is equivalent to:
V := Empty_Vector (2);
@@ -719,7 +798,7 @@
Append_One (V, "def");
-- An indexed vector aggregate
- V := (1 => "this", 2 => "is", 3 => "a", 4 => "test");
+ V := [1 => "this", 2 => "is", 3 => "a", 4 => "test"];
-- Is equivalent to:
V := New_Vector (1, 4);
@@ -729,7 +808,7 @@
Assign_Element (V, 4, "test");
-- A vector of images of dynamic length
- V := (for I in 1 .. N => Integer'Image (I));
+ V := [for I in 1 .. N => Integer'Image (I)];
-- is equivalent to:
V := New_Vector (1, N);
@@ -738,7 +817,7 @@
end loop;
-- A vector made from the elements of a map
- V := (for Elem of M => Elem);
+ V := [for Elem of M => Elem];
-- is equivalent to:
V := Empty_Vector (<estimate of size of M>);
@@ -856,19 +935,30 @@
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
+We chose "use" 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
+ M := [for P of Table use 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
+ 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 also considered a comma, a vertical bar, one or two colons, "do,"
+"with," etc. None of the choices were ideal, but we note that when it is
+combined with a filtered iterator (AI12-0250-1), "use" works pretty well
+after the "when" clause because it is a verb:
+
+ M := [for P of Table when Is_Good(P) use P.Key => P.Value];
+
+Also, "for ... use" is a familiar pairing of reserved words in Ada for
+specifying attributes, so it is not an unprecedented combination.
+Our second choice is probably comma, because it is quite light, and
+works adequately with or without a "when" clause, but it was pointed out
+that we allow multiple iterated_element_association's, which are
+themselves separated by commas.
!ASIS
@@ -3295,7 +3385,7 @@
From: Randy Brukardt
Sent: Wednesday, March 28, 2018 8:27 PM
-> OK, here is another shot at container aggregates, including a section
+> OK, here is another shot at container aggregates, including a section
> on generalizing array aggregates.
Thanks. A few thoughts.
@@ -3306,13 +3396,13 @@
something else. I won't belabor this, I've covered it before. [(7) covers one
possible way to eliminate this objection.]
-(3) <> in array and record aggregates means a default-initialized component.
+(3) <> in array and record aggregates means a default-initialized component.
Here, you have defined it to mean an empty (uninitialized) slot instead. These
aren't the same thing! (It's a Bounded Error to read an uninitialized slot; a
default-initialized element is usable in the normal way.) I use
default-initialized aggregate items all the time with the explicit intent of
getting default initialization (typically, so counters/lengths and the like
-are initialized to empty).
+are initialized to empty).
Note that most of the (definite) containers have Insert operations that don't
take an element and insert a default initialized object. (See, for instance,
@@ -3348,8 +3438,8 @@
follows:" should really be "Add after 4.3.3(20):" since I presume you are not
suggesting to replace 4.3.3(20) [and there is no 4.2.3 anyway].
-(5) The wording change (presumably) added after 4.3.3(20) seems a bit more
-explicit than necessary. Do we have to *require* that the iteration is
+(5) The wording change (presumably) added after 4.3.3(20) seems a bit more
+explicit than necessary. Do we have to *require* that the iteration is
performed twice? We surely should allow it, but if the compiler can figure
the length some other way (or is willing/able to use an expandable temporary
space), shouldn't we allow only a single execution of the iterator? (An as-if
@@ -3400,12 +3490,12 @@
likely empty lists. (That is, there isn't much point in plugging one hole if
we leave a worse one.)
-I would personally prefer to add the missing functions to List and Set to
+I would personally prefer to add the missing functions to List and Set to
create one-element lists and forget anything about empty aggregates (here and
for null arrays), but I'd be happy to figure better solutions.
(7) One wild thought I just had was that we don't really need an Empty
-parameter to the Aggregate aspect -- all of the language-defined containers
+parameter to the Aggregate aspect -- all of the language-defined containers
require the default-initialized container to be "empty". If we simply said
that the container object is default-initialized, this would mean "empty" for
the language-defined containers, then (<>) would actually mean a default
@@ -3428,9 +3518,9 @@
From: Tucker Taft
Sent: Wednesday, March 28, 2018 8:57 PM
->> OK, here is another shot at container aggregates, including a section
+>> OK, here is another shot at container aggregates, including a section
>> on generalizing array aggregates.
->
+>
> Thanks. A few thoughts. ...
Thanks, all good comments, and no particular responses at this point. It
@@ -3442,7 +3532,7 @@
From: Randy Brukardt
Sent: Wednesday, March 28, 2018 9:14 PM
-Comments are welcome; I can justify debating this proposal's details much
+Comments are welcome; I can justify debating this proposal's details much
more easily than anything involving rarely-used contracts. ;-)
****************************************************************
@@ -3450,7 +3540,7 @@
From: Jeff Cousins
Sent: Saturday, July 7, 2018 3:52 PM
-a few minor comments that I didn’t raise at the meeting as the AI was going
+a few minor comments that I didn’t raise at the meeting as the AI was going
back for a re-write anyway...
4.3.5
@@ -3460,12 +3550,12 @@
3rd bullet – “as the low bound of a range” -> “is the low bound of a range”?
8th bullet (for a named_container_aggregate) – “is of the form with” – I don’t
-find this terribly clear, though maybe just changing “with” to “containing”
+find this terribly clear, though maybe just changing “with” to “containing”
would suffice.
-15th (for a container_element_association) and final (the
-iterated_element_association) bullets – both of these have two “and”s – maybe
-the first “and” should go, and/or possibly the second “and” should be a
+15th (for a container_element_association) and final (the
+iterated_element_association) bullets – both of these have two “and”s – maybe
+the first “and” should go, and/or possibly the second “and” should be a
“then”??
Examples
@@ -3474,3 +3564,47 @@
is private”, the various “S := ...”s.
****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, October 17, 2018 8:32 PM
+
+Here is an update to the container aggregate AI, switching over to using square
+brackets "[...]" for such aggregates. [This is version /07 of the AI - Editor.]
+This AI also permits the use of "[...]" for array aggregates and array delta
+aggregates. It also permits the use of container iterators within array
+aggregates. Finally, we switch from using "," to separate off an explicitly
+specified key to using the reserved word "use" (after much internal debate).
+The "for ... use ..." combination appears elsewhere jn the language, so it
+seemed like a reasonable choice here. It also seemed to work in the presence of
+iterator filters, if we ever incorporate them. E.g.:
+
+ [for P of C when Is_Good(P) use P.Key => P.Value]
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, October 17, 2018 8:32 PM
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, October 18, 2018 8:09 PM
+
+One thing I immediately noticed is missing here is an update to 2.2 to add
+square brackets as an acceptable delimiter. That is, we need to add square
+brackets to the lists in 2.2(9/5) and 2.1(15/5). Else they're not acceptable
+syntax.
+
+There's a second problem, and that is that our syntax form uses brackets to
+denote optional items. We need to think of some way to differentiate literal
+brackets from the use as a syntax form. (As it stands, your syntax changes make
+aggregates optional. :-)
+
+1.1.4 has a hack for the vertical bar, that it stands for itself when it appears
+immediately after a curly bracket. That sort of hack won't work here, but we
+need *something*.
+
+Didn't notice anything else.
+
+****************************************************************
+
Questions? Ask the ACAA Technical Agent