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

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

--- ai12s/ai12-0312-1.txt	2019/09/05 04:14:06	1.9
+++ ai12s/ai12-0312-1.txt	2019/10/01 02:03:04	1.10
@@ -1,4 +1,4 @@
-!standard 5.5.2(2/3)                                  19-03-24  AI12-0312-1/04
+!standard 5.5.2(2/3)                                  19-09-27  AI12-0312-1/05
 !class presentation 19-02-07
 !status work item 19-02-07
 !status received 19-02-07
@@ -21,42 +21,59 @@
 
 !wording
 
+Modify 3.10.1(23)
+
+My_Car, Your_Car, Next_Car : Car_Name := new Car;  -- see 4.8
+[George]{Casey} : Person_Name := new Person(M);
+   ...
+[George]{Casey}.Vehicle := Your_Car;
+
+[Author's note: George was changed to Casey, because a more unisex name
+was asked for in the comments against the example for 4.5.7(21/3),
+and googling famous people named Casey produces about an even mix of the sexes.
+Chris produced mostly male for example, and Pat was also heavily male oriented]
+
 Append after 4.2.1(10/5):
 
 Examples
 
-   -- The Date Example in 3.8 could be augmented to support integer literal representation
+   subtype Roman_Character is Character
+     with Static_Predicate =>
+       Roman_Character in 'I' | 'V' | 'X' | 'L' | 'C' | 'D' | 'M';
 
-   type Month_Name is (Jan, Feb, Mar, Apr, May, Jun,
-                       Jul, Aug, Sep, Oct, Nov, Dec);
+   Max_Roman_Number : constant := 3_999;  -- MMMCMXCIX
 
-   type Date is
-      record
-         Day   : Integer range 1 .. 31;
-         Month : Month_Name;
-         Year  : Integer range 0 .. 4000;
-      end record with Integer_Literal => To_Date;
+   subtype Roman_Number is Positive range 1 .. Max_Roman_Number
+      with String_Literal => To_Roman_Number;
 
-   function To_Date (Value : String) return Date;
+   function To_Roman_Number (S : String) return Roman_Number
+     with Pre => S'Length > 0 and then
+        (for all Char of S => Char in Roman_Character);
 
-   function To_Date (Value : String) return Date is
-     (declare
-        S : constant String := Integer'Image (Integer'Value (Value));
+   function To_Roman_Number (S : String) return Roman_Number is
+     (declare R : constant array (Integer range <>) of Integer :=
+        (for D of S =>
+             (case D is
+                 when 'I' => 1,
+                 when 'V' => 5,
+                 when 'X' => 10,
+                 when 'L' => 50,
+                 when 'C' => 100,
+                 when 'D' => 500,
+                 when 'M' => 1000,
+                 when others => 0)) [<= Author's note: This is needed because S is of type String, even though precondition makes this impossible?]
       begin
-        (Day   => Integer'Value (S (S'Last-5 .. S'Last-4)),
-         Year  => Integer'Value (S (S'Last-3 .. S'Last)),
-         Month => Month_Name'Val (Integer'Value (S (S'First .. S'Last-6))-1)));
-
-   ...
+        [for I in R'Range =>
+          (if I < R'Last and then R(I) < R(I + 1) then -1 else 1) * R(I))]
+            'Reduce("+", 0)
+     );
 
-    Today : Date := 2_22_2019;  -- Integer representation of date (MMDDYYYY format)
+  X : Roman_Number := "III" * "IV" * "XII"; -- 144 ( i.e. CXLIV)
 
 Append after 4.3.3(47/5):
 
 Empty_Matrix : constant Matrix := []; -- A matrix without elements
 
-Delete paragraphs 4.3.5(86/5 - 86/5).    [Already show example of empty container aggregate]
-
 Delete paragraph 4.3.5(97/5). [Alternate form example shown above]
 
 Delete paragraphs 4.3.5(99/5 - 100/5).  [Already show example of empty container aggregate]
@@ -66,10 +83,11 @@
 Append after 4.5.7(21/3):
 
 Examples
-   Put_Line ("George is " & (if George.Sex = M then "Male" else "Female")); -- See 3.10.1
+   Put_Line ("Casey is " & (if Casey.Sex = M then "Male" else "Female")); -- See 3.10.1
 
    function Value (Digit : Roman_Digit) return Natural is --  See 3.5.2
-     (case Digit is when 'I' => 1,
+     (case Digit is
+         when 'I' => 1,
          when 'V' => 5,
          when 'X' => 10,
          when 'L' => 50,
@@ -84,25 +102,21 @@
      are greater than 100.0:
 
    type Accumulator is record
-      Sum          : Real; -- See 3.5.7
-      Addend_Count : Integer;
+      Sum   : Real; -- See 3.5.7
+      Count : Integer;
    end record;
 
-   function Combine (L, R : Accumulator) return Accumulator is
-     (Sum => L.Sum + R.Sum,
-      Addend_Count => L.Addend_Count + R.Addend_Count);
+   function Accumulate (L, R : Accumulator) return Accumulator is
+     (Sum   => L.Sum   + R.Sum,
+      Count => L.Count + R.Count);
 
-   function Reduce (A : Accumulator; Addend : Real) return Accumulator is
-     (Sum => A.Sum + Addend, Addend_Count => A.Addend_Count + 1);
-
    function Average_of_Values_Greater_Than_100 (M : Matrix) return Real is
      (declare Acc : constant Accumulator :=
-        [for Val of M when Val > 100.0 => Val]
-          'Parallel_Reduce(Reduce, (Sum => 0, Addend_Count => 0), Combine);
+        [parallel for Val of M when Val > 100.0 => (Val, 1)]
+          'Reduce(Accumulate, (Sum => 0, Count => 0));
       begin
-        Acc.Sum / Real(Acc.Addend_Count));
+        Acc.Sum / Real(Acc.Count));
 
-
 Modify 5.5(22/5):
 "Example{s} of [a] parallel loop{s}: "
 
@@ -121,7 +135,7 @@
    for I in Grid'Range(1) loop
       declare
          True_Count : constant Natural :=
-           (for J in Grid'Range(2) => (if Grid (I, J) then 1 else 0))'Reduce("+",0);
+           [for J in Grid'Range(2) => (if Grid (I, J) then 1 else 0)]'Reduce("+",0);
       begin
          Partial_Sum (Chunk) := @ + True_Count;
          Partial_Min (Chunk) := Natural'Min(@, True_Count);
@@ -150,31 +164,55 @@
 
 Examples
 
+   --  A work scheduler where only urgent work can be scheduled for weekends
+
    package Work_Orders is
 
       type Work_Order is private with
         Type_Invariant => Day_Scheduled (Work_Order) in Weekday or else Priority (Work_Order) = Urgent; -- See 3.5.1
 
+      function Schedule_Work (Urgency : in Level;
+                              When    : in Day) return Work_Order
+         with Pre => Urgency = Urgent or else When in Weekday;
+
       function Day_Scheduled (Order : in Work_Order) return Day; -- See 3.5.1
       function Priority (Order : in Work_Order) return Level;    -- See 3.5.1
+      procedure Change_Priority (Order        : in out Work_Order;
+                                 New_Priority : in     Level;
+                                 Changed      : out    Boolean);
 
-      ...
-
    private
 
       type Work_Order is record
          Scheduled : Day;
          Urgency   : Level;
-         ...
       end record;
 
+      function Schedule_Work (Urgency : in Level;
+                              When    : in Day) return Work_Order is
+         (Scheduled => When, Urgency => Urgency);
+
       function Day_Scheduled (Order : in Work_Order) return Day is (Order.Scheduled);
       function Priority (Order : in Work_Order) return Level is (Order.Urgency);
-
-      ...
+      procedure Change_Priority (Order    : in out Work_Order;
+                                 Priority : in     Level;
+                                 Changed  : out    Boolean) is
+      begin
+         --  Ensure type invariant is not violated
+         if Priority = Urgent or else Order.Scheduled in Weekday then
+            Changed := True;
+            Order.Urgency := Priority;
+         else
+            Changed := False;
+         end if;
+      end Change_Priority;
 
    end Work_Orders;
 
+For another example of the use of the Type_Invariant aspect, see the Vector container definition
+in A.18.2.
+
+
 Append after 7.3.3(9/5):
 
 NOTES
@@ -184,11 +222,133 @@
 
 Append after 11.3(7):
 
-For examples of raise expressions, see the Streams Subsytem definitions in
+For an example of a raise expression, see the Streams Subsytem definitions in
 13.13.1.
 
+Modify A.18.2(8/5):
+
+type Vector is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Variable_Indexing => Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Iterator_View     => Stable.Vector,
+           Aggregate         => (Empty          => Empty,
+                                 Add_Unnamed    => Append_One,
+                                 New_Indexed    => New_Vector,
+                                 Assign_Indexed => Replace_Element),
+           Stable_Properties => (Length, Capacity,
+                                 Tampering_With_Cursors_Prohibited,
+                                 Tampering_With_Elements_Prohibited),
+           Default_Initial_Condition =>
+              Length (Vector) = 0 and then
+              (not Tampering_With_Cursors_Prohibited (Vector)) and then
+              (not Tampering_With_Elements_Prohibited (Vector)){,
+           Type_Invariant => Length (Vector) <= Capacity (Vector)};
+
+Modify A.18.5(3/5):
+
+type Map is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Variable_Indexing => Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Iterator_View     => Stable.Map,
+           Aggregate         => (Empty     => Empty,
+                                 Add_Named => Insert),
+           Stable_Properties => (Length,
+                                 Tampering_With_Cursors_Prohibited,
+                                 Tampering_With_Elements_Prohibited),
+           Default_Initial_Condition =>
+              Length (Map) = 0 and then
+              (not Tampering_With_Cursors_Prohibited (Map)) and then
+              (not Tampering_With_Elements_Prohibited (Map)){,
+           Length (Map) <= Capacity (Map)};
+   pragma Preelaborable_Initialization(Map);
+
+Modify A.18.6(16.7/5):
+ procedure Assign (Target : in out Map; Source : in Map)
+      with Pre  => (if Tampering_With_Cursors_Prohibited (Target)
+                    then raise Program_Error),
+           Post => Length (Source) = Length (Target) [and then
+                   Capacity (Target) >= Length (Source)];
+
+[Author's note: This is a bug in the RM. Ordered maps do not have a Capacity function!]
+
+Modify A.18.8(3/5):
+type Set is tagged private
+      with Constant_Indexing => Constant_Reference,
+           Default_Iterator  => Iterate,
+           Iterator_Element  => Element_Type,
+           Iterator_View     => Stable.Set,
+           Aggregate         => (Empty       => Empty,
+                                 Add_Unnamed => Include),
+           Stable_Properties => (Length,
+                                 Tampering_With_Cursors_Prohibited),
+           Default_Initial_Condition =>
+              Length (Set) = 0 and then
+              (not Tampering_With_Cursors_Prohibited (Set)){,
+           Length (Set) <= Capacity (Set)};
+   pragma Preelaborable_Initialization(Set);
+
+Modify A.18.20(5/3):
+  type List (Capacity : Count_Type) is tagged private{,
+     with Type_Invariant => Length (List) <= List.Capacity};
+
+[Author's question: I presume that we only need to describe type invariants
+for bounded containers where the unbounded forms do not already have such a
+type invariant? Also, presuming that in unbounded forms it's OK to use
+non- object prefix form (for consistency, and not need to redefine to
+use prefix form for bounded containers even though that is required
+because Capacity is a discriminant, not a primitive operation?
+Otherwise, we'd need to explicitly show the type invariant for all
+bounded containers, and describe that the non-prefix notation form
+doesn't exist, which seems like unnecessary detail.]
+
+Modify A.18.22(5/3):
+
+   type Map (Capacity : Count_Type) is tagged private{,
+     with Type_Invariant => Length (Map) <= Map.Capacity};
+
+Modify A.18.24(5/3):
+
+type Set (Capacity : Count_Type) is tagged private{,
+     with Type_Invariant => Length (Set) <= Set.Capacity};
+
+Modify A.18.25(5/3):
+
+type Tree (Capacity : Count_Type) is tagged private{,
+     with Type_Invariant => Length (Tree) <= Tree.Capacity};
+
+Modify B.3(78/3):
+--Calling the C Library Function{s} strcpy{, and printf}
+with Interfaces.C;
+procedure Test is
+   package C renames Interfaces.C;
+   use type C.char_array;
+   -- Call <string.h>strcpy:
+   -- C definition of strcpy:  char *strcpy(char *s1, const char *s2);
+   --    This function copies the string pointed to by s2 (including the terminating null character)
+   --     into the array pointed to by s1. If copying takes place between objects that overlap,
+   --     the behavior is undefined. The strcpy function returns the value of s1.
+
 Append after B.3(78/3):
 
+   -- Call <sdtio.h>printf:
+   -- C definition of printf:  int printf ( const char * format, ... );
+   --    This function writes the C string pointed by format to the standard
+   --    output (stdout). If format includes format specifiers (subsequences
+   --    beginning with %), the additional arguments following format are
+   --    formatted and inserted in the resulting string replacing their
+   --    respective specifiers. If the number of arguments does not match
+   --    the number of format specifiers, or if the types of the arguments
+   --    do not match the corresponding format specifier, the behaviour is
+   --    undefined. On success, the printf function returns the total
+   --    number of characters written to the standard output. If a writing
+   --    error occurs, a negative number is returned.
+
+   -- Note: since the C function's return value is of no interest, the Ada interface is a procedure
+
    procedure Printf (Format : in C.char_array)
       with Import => True, Convention => C_Variadic_1, External_Name => "printf";
 
@@ -652,28 +812,28 @@
 
 In Warsaw, for AI12-0312-1 Examples for Ada 2020,
 
-I had an example for user defined literals involving specifying dates as 
+I had an example for user defined literals involving specifying dates as
 integers using underscores to separate the fields.
 
-This generally was not liked, (for example Erhard commented that one could 
-create an aggregate assignment for this, which is safer, which is a good point). 
-So since then I have conjured up another example, that I think is an 
+This generally was not liked, (for example Erhard commented that one could
+create an aggregate assignment for this, which is safer, which is a good point).
+So since then I have conjured up another example, that I think is an
 improvement.
 
-This example uses the Roman numeral types in the RM to allow one to express 
+This example uses the Roman numeral types in the RM to allow one to express
 values for an integer type, using roman numeral strings.
 
 I think this means, one would be able to write expressions such as;
 
   X : Roman_Number := "III" * "IV" * "XII";   --  = 144 or "CXLIV", when 'Image is applied
 
-As I am thinking the compiler will deduce from the context that all values 
-are of the same type, and thus should be converted to integer Roman_Number 
+As I am thinking the compiler will deduce from the context that all values
+are of the same type, and thus should be converted to integer Roman_Number
 values before applying the operations.
 
 Does that sound right?
 
-In any case, the example code I have is an interesting example in that it 
+In any case, the example code I have is an interesting example in that it
 uses a lot of newer features.
   - Static Subtype Predicates
   - Dynamic Subtype Predicate
@@ -689,12 +849,12 @@
   - User defined 'Image
   - Preconditions
 
-So I am curious to see if others think this is an appropriate example, or if 
+So I am curious to see if others think this is an appropriate example, or if
 someone might suggest a better idea.
 
-The user defined literal going from Roman Numerals to Integer was surprisingly 
+The user defined literal going from Roman Numerals to Integer was surprisingly
 simple with the new features.
-Going the other way round, with 'Image was surprisingly more difficult than 
+Going the other way round, with 'Image was surprisingly more difficult than
 expected, but we could drop off the 'Image easily enough from the example.
 
    type Roman_Digit is ('I', 'V', 'X', 'L', 'C', 'D', 'M');    -- From RM 3.5.2 (11)
@@ -709,7 +869,7 @@
      Dynamic_Predicate =>
        (for all Char of Roman_String => Char in Roman_Character);
 
-   subtype Roman_Number is Positive range 1 .. 1_000   -- Subtype with user-defined string literal  
+   subtype Roman_Number is Positive range 1 .. 1_000   -- Subtype with user-defined string literal
       with String_Literal => To_Roman_Number;
    for Roman_Number'Put_Image use Image;
 
@@ -802,25 +962,25 @@
 From: Tucker Taft
 Sent: Thursday, June 20, 2019  7:36 AM
 
-Interesting.  Implementation is too long for the manual, but we could put 
-just the specs in the manual.  Might be clearer if you called the routine 
+Interesting.  Implementation is too long for the manual, but we could put
+just the specs in the manual.  Might be clearer if you called the routine
 "Put_Image" rather than "Image".  Might make a good ACATS test.
 
 > I think this means, one would be able to write expressions such as;
-> 
+>
 >  X : Roman_Number := "III" * "IV" * "XII";   --  = 144 or "CXLIV", when 'Image is applied
-> 
-> As I am thinking the compiler will deduce from the context that all 
-> values are of the same type, and thus should be converted to integer 
+>
+> As I am thinking the compiler will deduce from the context that all
+> values are of the same type, and thus should be converted to integer
 > Roman_Number values before applying the operations.
-> 
+>
 > Does that sound right?
 > ...
 
-I have to think a bit about the overload resolution here.  I am unsure whether 
-the multiplication will work as you wrote it.  Normally we require exactly one 
-expected type for string literals, unlike for numeric literals.  There is no 
-"universal" type for string literals.  But since you provided an expected 
+I have to think a bit about the overload resolution here.  I am unsure whether
+the multiplication will work as you wrote it.  Normally we require exactly one
+expected type for string literals, unlike for numeric literals.  There is no
+"universal" type for string literals.  But since you provided an expected
 type of Roman_Number it is probably fine.
 
 ****************************************************************
@@ -835,25 +995,25 @@
 From: Brad Moore
 Sent: Thursday, June 20, 2019  7:58 AM
 
-I've made a few minor fixes to this. In particular, the user-defined Image 
+I've made a few minor fixes to this. In particular, the user-defined Image
 function needed to write to the stream as characters, not Roman Digits.
 
-Since Tullio privately mentioned an interest in seeing the Ada 2012 version, 
-I might as well send out the update with the fix as well as the working Ada 
-2012 version to the group. Please see the attached tar file which contains 
+Since Tullio privately mentioned an interest in seeing the Ada 2012 version,
+I might as well send out the update with the fix as well as the working Ada
+2012 version to the group. Please see the attached tar file which contains
 both. [Not available here, see source below - Editor.]
 
-The Ada 202x version is in main_202x.adb, and the Ada 2012 version is in 
+The Ada 202x version is in main_202x.adb, and the Ada 2012 version is in
 main.adb.
 
-The Ada 2012 version is actually a hybrid between Ada 2012 and Ada 202x, as 
-it incorporates some 202x features that have already been implemented in 
+The Ada 2012 version is actually a hybrid between Ada 2012 and Ada 202x, as
+it incorporates some 202x features that have already been implemented in
 GNAT, such as @, and array aggregate with iterators.
 
-The project file should compile with the latest GNAT community edition, 
+The project file should compile with the latest GNAT community edition,
 released this month (or in May)
 
-For those not wanting to fiddle with untarring files, here are the relevant 
+For those not wanting to fiddle with untarring files, here are the relevant
 bits from the updated 202x version....
 
   type Roman_Digit is ('I', 'V', 'X', 'L', 'C', 'D', 'M');
@@ -866,7 +1026,7 @@
      Dynamic_Predicate =>
        (for all Char of Roman_String => Char in Roman_Character);
 
-   subtype Roman_Number is Positive range 1 .. 1_000 
+   subtype Roman_Number is Positive range 1 .. 1_000
       with String_Literal => To_Roman_Number;
    for Roman_Number'Put_Image use Image;
 
@@ -967,35 +1127,35 @@
 From: Randy Brukardt
 Sent: Thursday, June 20, 2019  11:36 AM
 
-> Interesting.  Implementation is too long for the manual, but we could 
+> Interesting.  Implementation is too long for the manual, but we could
 > put just the specs in the manual.
 
-I think it is OK if all of the stuff unrelated to user-defined literals is 
-left out (that is, all of the Image stuff). Perhaps that fits in the Image 
-section to show a redefinition, but it definitely doesn't belong in a 
+I think it is OK if all of the stuff unrelated to user-defined literals is
+left out (that is, all of the Image stuff). Perhaps that fits in the Image
+section to show a redefinition, but it definitely doesn't belong in a
 user-defined literal example.
 
-I'd also leave out the unused Roman_String, especially as one could also 
+I'd also leave out the unused Roman_String, especially as one could also
 declare a string type thusly:
     type Other_Roman_String is array (Positive range <>) of Roman_Character;
 
 Do you use Roman_Character for anything in this example?
 
 > Might be clearer
-> if you called the routine "Put_Image" rather than "Image".  
+> if you called the routine "Put_Image" rather than "Image".
 
 Agreed. Why confuse the usage (usually a routine "Image" returns a String).
 
 > Might make a good ACATS test.
 
-Well, no, because it uses a kitchen sink of features and would cover 
-objectives from multiple sections. We try to make ACATS tests that 
-mostly use basic stuff outside of the tested feature so that the tests 
-are useable for staged implementations (no one can implement everything at 
+Well, no, because it uses a kitchen sink of features and would cover
+objectives from multiple sections. We try to make ACATS tests that
+mostly use basic stuff outside of the tested feature so that the tests
+are useable for staged implementations (no one can implement everything at
 once).
 
-I suppose it could make *two* ACATS tests (one for user-defined literals, and 
-one for user-defined image), but I'd probably suggest getting rid of the 
+I suppose it could make *two* ACATS tests (one for user-defined literals, and
+one for user-defined image), but I'd probably suggest getting rid of the
 preconditions and predicates in that case (replacing them with regular code)
 - those things aren't under test here.
 
@@ -1005,16 +1165,359 @@
 Sent: Wednesday, July 24, 2019  8:44 PM
 
 Jeff had the following comments on your AI that didn't get discussed in Warsaw
-as Jeff misplaced his notes. These ought to be addressed in the next draft 
+as Jeff misplaced his notes. These ought to be addressed in the next draft
 along with the things noted in the minutes:
 
 	4.3.5(86/5 - 86/5) should be 4.3.5(86/5 - 87/5)
 
-	11.3 (7) There is only one raise expression in 13.13.1 so this should say 
+	11.3 (7) There is only one raise expression in 13.13.1 so this should say
         "for an example of a raise expression..."
 
 	B.3(78/3) needs a comment saying what it is about:
 
 	-- Example of a variadic C function
+
+****************************************************************
+
+From: Brad Moore
+Sent: Saturday, September 28, 2019  6:20 PM
+
+In the minutes from last meeting, I was asked to see if I could simplify 
+the Reduction Expression example for 4.5.10 (53/5), possibly by using a set 
+container.
+
+The example currently in the AI is;
+
+   type Accumulator is record
+      Sum          : Real; -- See 3.5.7
+      Addend_Count : Integer;
+   end record;
+
+   function Combine (L, R : Accumulator) return Accumulator is
+     (Sum => L.Sum + R.Sum,
+      Addend_Count => L.Addend_Count + R.Addend_Count);
+
+   function Reduce (A : Accumulator; Addend : Real) return Accumulator is
+     (Sum => A.Sum + Addend, Addend_Count => A.Addend_Count + 1);
+
+   function Average_of_Values_Greater_Than_100 (M : Matrix) return Real is
+     (declare Acc : constant Accumulator :=
+        [parallel for Val of M when Val > 100.0 => Val]
+          'Reduce(Reduce, (Sum => 0, Addend_Count => 0), Combine);
+      begin
+        Acc.Sum / Real(Acc.Addend_Count));
+
+
+I have given thought to using a container such as a set, but so far, have not
+arrived at anything sensible.
+
+However, I do think the example can be simplified, without using containers.
+
+We can eliminate the need for a separate combiner function by having the 
+map/reduce part of the value_sequence produce an Accumulator object rather
+than a real value as an input to the reduction. The count part of the 
+accumulator is 1, which gets tallied up by the reducer.
+
+If we do that, then the example becomes;
+
+  type Accumulator is record
+      Sum   : Real; -- See 3.5.7
+      Count : Integer;
+   end record;
+
+   function Reduce (L, R : Accumulator) return Accumulator is
+     (Sum   => L.Sum   + R.Sum,
+      Count => L.Count + R.Count);
+
+   function Average_of_Values_Greater_Than_100 (M : Matrix) return Real is
+     (declare Acc : constant Accumulator :=
+        [parallel for Val of M when Val > 100.0 => (Val, 1)]
+          'Reduce(Reduce, (Sum => 0, Count => 0));
+      begin
+        Acc.Sum / Real(Acc.Count));
+
+It this enough of a simplification for this example? I looks pretty simple to 
+me.
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Sent: Sunday, September 29, 2019  12:15 AM
+
+> It this enough of a simplification for this example? I looks pretty simple to me.
+
+Much better; I'd rather call the function Reducer (or something else) to avoid the 
+"'Reduce(Reduce"
+
+****************************************************************
+
+From: Edmond Schonberg
+Sent: Sunday, September 29, 2019  8:17 AM
+
+Second. For greater clarity I would suggest the name “Accumulate” for that function.
+
+****************************************************************
+
+From: Brad Moore
+Sent: Sunday, September 29, 2019  11:33 AM
+
+I agree with both comments, and ultimately went with Eds suggestion.
+
+I am now wondering though, whether we need the combiner field for parallel 
+reduction at all?
+
+The combiner field (the third parameter to a reduction attribute is only 
+needed for parallel reductions, when the types of the parameters to the 
+reducer function are different types. For non-parallel reduction, there is no 
+need to combine results from different threads of execution.
+
+This example shows that it can be possible to simplify the expression to a 
+form that doesn't need the combiner, by using the map/reduce part of the value 
+sequence to make both parameters of the reduction the same type.
+
+Another motivating example that was used for justifying the combiner is a 
+concatenation example.
+
+Consider:
+
+function Accumulate(Result : in String; Letter : in Character) return String is
+   (Result & Letter);
+
+Alphabet : constant String :=
+   [parallel for Letter in 'A' .. 'Z' => Letter]'Reduce(Accumulate, "", "&");
+
+Admittedly, this is not a practical parallelism example, but it does illustrate my point.
+
+Again, the combiner can be eliminated here, and this can all be replaced with;
+
+Alphabet : constant String :=
+   [parallel for Letter in 'A' .. 'Z' => String'(1 => Letter)]'Reduce("&", "");
+
+
+It is at least worthwhile to consider if eliminating the combiner from the syntax would 
+"guide" programmers to  write simpler, more readable code, which is one of the features 
+I generally like about Ada.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, September 30, 2019  8:24 PM
+
+...
+> I am now wondering though, whether we need the combiner field for 
+> parallel reduction at all?
+...
+> This example shows that it can be possible to simplify the expression 
+> to a form that doesn't need the combiner, by using the map/reduce part 
+> of the value sequence to make both parameters of the reduction the 
+> same type.
+
+Didn't we consider that when we designed this feature? Didn't we decide that 
+the performance impact of eliminating the combiner would be unacceptable? 
+After all, the only reason for parallelizing something is to improve the 
+performance, and if doing that requires making a lot of expensive copies 
+then that doesn't make much sense. I'm certain that we discussed this at 
+least once and probably more than once. I'd suggest going back through 
+the mail/minutes on this topic (AI12-0242-1 & AI12-0262-1) to see what we 
+discussed about it in the past (rather than reopening a discussion that we've 
+had in the past).
+
+IMHO, this feature is complex enough without forcing people to jump through 
+hoops to figure out how to encode the parameters as both the same type. Just
+because something is *possible* doesn't mean that we ought to make the *only*
+way. And I'm pretty sure we had examples that didn't work well without 
+allowing the parameters to be of different types (which then requires a 
+combiner).
+
+>It is at least worthwhile to consider if eliminating the combiner from 
+>the syntax would "guide" programmers to write simpler, more readable 
+>code, which is one of the features I generally like about Ada.
+
+There's no reduction code that will ever qualify as "simpler" or "readable". 
+The idea itself is a brain-bender for most - I'd guess that most of us will 
+have to write out the expansion of any such expression to figure out what's 
+going on. (There are some of course who find such things "natural", but 
+they're weird. ;-)
+
+****************************************************************
+
+From: Brad Moore
+Sent: Sunday, September 29, 2019  7:58 PM
+
+Here is my homework for the upcoming ARG meeting, which addresses all 
+comments captured in the Warsaw meeting. [This is version /05 of the AI - 
+Editor.]
+
+Also, I do have recollection of having addressed Jeff's comments a long time 
+ago, so I was curious to find out why his early comments were not incorporated
+into the version we were looking at in Warsaw.
+
+It turns out that on March 7th, 2019, I sent out an update which addressed 
+Jeff's comments. However, that version of the AI did not seem to properly 
+make it into the system. 
+
+There is a version 1.4 of the AI, which corresponds to Mar 8th, which seems 
+like it should be the version that corresponds to my sent email, but it 
+doesn't have the changes that I sent out.
+
+Anyway, I hope I now have addressed Jeff's comments in this new version of 
+the AI.
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Sent: Monday, September 30, 2019  12:04 AM
+
+Suggestion:
+
+             (case D is
+                 when 'I' => 1,
+                 when 'V' => 5,
+                 when 'X' => 10,
+                 when 'L' => 50,
+                 when 'C' => 100,
+                 when 'D' => 500,
+                 when 'M' => 1000,
+                 when others => raise Program_Error with "Impossible"))
+
+****************************************************************
+
+From: Jeff Cousins
+Sent: Monday, September 30, 2019  2:41 PM
+
+Thanks Brad.
+
+Some of the paragraph numbers seem odd places to give the examples:
+
+6.1.1(41/3) (actually now up to 41/5) is in Implementation Permissions, 
+6.1.2(42/5) is in the middle of Legality Rules.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, September 30, 2019  4:27 PM
+
+The paragraph numbers in "new" clauses, like 6.1.2, change every time there is
+a change to those clauses, so they have to be rechecked with every version. 
+Also, we have a meta-rule allowing paragraph numbers of non-normative material 
+to change, so if there are additions near the end of a clause, the paragraph 
+numbers of examples may change.
+ 
+Which is a long-winded way of saying that Brad probably had the right paragraph 
+numbers when he wrote the AI, but they've probably changed since. It would be 
+hard to keep up.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, September 30, 2019  9:01 PM
+
+>Here is my homework for the upcoming ARG meeting...
+
+I fixed up some of the "Modify" and "Append" headers to have the correct form.
+
+You have:
+
+>Modify A.18.2(8/5):
+>
+>type Vector is tagged private
+>      with Constant_Indexing => Constant_Reference,
+>           Variable_Indexing => Reference,
+>           Default_Iterator  => Iterate,
+>           Iterator_Element  => Element_Type,
+>           Iterator_View     => Stable.Vector,
+>           Aggregate         => (Empty          => Empty,
+>                                 Add_Unnamed    => Append_One,
+>                                 New_Indexed    => New_Vector,
+>                                 Assign_Indexed => Replace_Element),
+>           Stable_Properties => (Length, Capacity,
+>                                 Tampering_With_Cursors_Prohibited,
+>                                 Tampering_With_Elements_Prohibited),
+>           Default_Initial_Condition =>
+>              Length (Vector) = 0 and then
+>              (not Tampering_With_Cursors_Prohibited (Vector)) and then
+>              (not Tampering_With_Elements_Prohibited (Vector)){,
+>           Type_Invariant => Length (Vector) <= Capacity (Vector)};
+
+That is, adding a Type_Invariant to the containers.
+
+This would be a normative change, so it doesn't belong in an AI about examples.
+If we're going to do this, it will have to be in some other AI.
+
+I presume that you added this change based on Tucker's comment from the 
+meeting:
+
+   Tucker suggests that we could imagine a type invariant on the containers 
+   that Length(V) <= Capacity(V).
+
+This followed some discussion about shortcomings in the example you had. I 
+believe he was suggesting a different example that you could use, not a change 
+to the container's contracts. "we could imagine" doesn't sound to me to be a 
+directive to change the actual container's definition.
+
+Note that there's nothing really wrong with adding this to the containers 
+other than the work required (both for me and for implementers). But it is
+already reflected in various postconditions where it could be relevant, so
+it seems like it would primarily be redundant (you only found a single 
+postcondition that it would make redundant).
+
+>Modify A.18.6(16.7/5):
+> procedure Assign (Target : in out Map; Source : in Map)
+>      with Pre  => (if Tampering_With_Cursors_Prohibited (Target)
+>                    then raise Program_Error),
+>           Post => Length (Source) = Length (Target) [and then
+>                   Capacity (Target) >= Length (Source)];
+>
+>[Author's note: This is a bug in the RM. Ordered maps do not have a Capacity 
+>function!]
+
+I've fixed this, an obvious cut-and-paste error. No need to mention it 
+anywhere (few of the container contract things are written out anywhere other 
+than the RM and we can fix mistakes accordingly, at least until we publish a 
+new Standard).
+
+I note that I concluded when contracting containers that it would have been a 
+lot easier had all of the containers had a Capacity of some sort. (I also 
+concluded that we needed a different cross-cut than the way the Sets/Maps are 
+organized -- probably, there should have been a set of operations that exist 
+in all six of the "normal" containers defined separately [there are about 
+30 or so], and then all of the other operations defined individually. That 
+would save a lot of text. Too late to do any of that, of course, it would 
+mainly be churn now and it would change all of the clause numbers.)
+
+>Modify A.18.20(5/3):
+>  type List (Capacity : Count_Type) is tagged private{,
+>     with Type_Invariant => Length (List) <= List.Capacity};
+
+This doesn't work as you wrote it, as the lead-in text says that this is only 
+describing the discriminant. Moreover, all of these are wrong anyway as they 
+seem to imply that this is the complete declaration, when this is only the 
+first line. That is, the existing example text (for all of the bounded forms) 
+should end with "..." and not ";", thus:
+
+  type List (Capacity : Count_Type) is tagged private...
+
+as they already have 6 or more aspects specified after them. There's no intent 
+that this declaration change any of those aspects unless there is text 
+elsewhere to do that. (Note that the Bounded_Vectors have text to omit the 
+capacity from the stable properties.)
+
+>[Author's question: I presume that we only need to describe type invariants
+>for bounded containers where the unbounded forms do not already have such a
+>type invariant? 
+
+Surely (if we do this at all).
+
+>Also, presuming that in unbounded forms it's OK to use
+>non- object prefix form (for consistency, and not need to redefine to
+>use prefix form for bounded containers even though that is required
+>because Capacity is a discriminant, not a primitive operation? ...
+
+??? Bounded_Vectors, Bounded_Hashed_Maps, and Bounded_Hashed_Sets all still 
+have a function Capacity. So it's certainly OK to call it! Map.Capacity is 
+the discriminant, Capacity (Map) is the function. (There's a preference for 
+components, else there would have been a nasty incompatibility and the 
+possibility of "losing" access to components because of an inherited 
+primitive.)
 
 ****************************************************************

Questions? Ask the ACAA Technical Agent