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

Differences between 1.14 and version 1.15
Log of other versions for file 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