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

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

--- ai12s/ai12-0312-1.txt	2019/04/06 05:08:50	1.7
+++ ai12s/ai12-0312-1.txt	2019/09/04 02:53:26	1.8
@@ -646,3 +646,357 @@
 [This is version /04 of the AI - Editor.]
 
 ****************************************************************
+
+From: Brad Moore
+Sent: Thursday, June 20, 2019  12:59 AM
+
+In Warsaw, for AI12-0312-1 Examples for Ada 2020,
+
+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 
+improvement.
+
+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 
+values before applying the operations.
+
+Does that sound right?
+
+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
+  - User Defined String Literals
+  - Quantified Expression
+  - Expression Functions
+  - Declare Expressions
+  - Conditional Expressions
+  - Reduction Expressions
+  - Case Expressions
+  - Array Aggregate with an iterator expression
+  - When clause on an iterator expression
+  - User defined 'Image
+  - Preconditions
+
+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 
+simple with the new features.
+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)
+
+   type Roman      is array(Positive range <>) of Roman_Digit;  -- From RM 3.6 (26)
+
+   subtype Roman_Character is Character
+     with Static_Predicate =>
+       Roman_Character in 'I' | 'V' | 'X' | 'L' | 'C' | 'D' | 'M';
+
+   subtype Roman_String is String with   -- Not really needed for this example
+     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  
+      with String_Literal => To_Roman_Number;
+   for Roman_Number'Put_Image use Image;
+
+   function To_Roman_Number (S : String) return Roman_Number
+     with Pre => (for all Char of S => Char in Roman_Character);
+
+   function To_Roman_Number (S : String) return Roman_Number is
+     (declare R : constant array (Integer range <>) of Roman_Number :=
+        (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))
+      begin
+        [for I in R'Range =>
+          (if I < R'Last and then R(I) < R(I + 1) then -1 else 1) * R(I))]
+            'Reduce("+", 0)
+     );
+
+   procedure Image
+     (Arg : Integer;
+      Stream : not null access Ada.Streams.Root_Stream_Type'Class)
+      with Pre => (Arg <= 1000);
+
+   procedure Image
+     (Arg : Integer;
+      Stream : not null access Ada.Streams.Root_Stream_Type'Class)
+   is
+      Lookup : constant array (Roman_Digit) of Roman_Number :=
+        ('I' => 1, 'V' => 5, 'X' => 10, 'L' => 50, 'C' => 100, 'D' => 500,
+         'M' => 1000);
+
+      procedure Convert (Value : Natural)
+      is
+         Above : constant Roman_Digit :=
+            [for I in Lookup'Range when Lookup (I) >= Value => I]
+             'Reduce(Roman_Digit'Min, Roman_Digit'Last);
+      begin
+         if Value = 0 then
+            return;
+         elsif Value = 1 then
+            Roman_Digit'Write (Stream, 'I');
+         elsif Value = Lookup (Above) then
+            Roman_Digit'Write (Stream, Above);
+            Convert (Value - Lookup (Above));
+         elsif Roman_Digit'Pos(Above) rem 2 = 0 and then Value >= Lookup (Above) -
+           Lookup (Roman_Digit'Pred(Roman_Digit'Pred (Above))) then
+            Roman_Digit'Write (Stream,
+                               Roman_Digit'Pred(Roman_Digit'Pred (Above)));
+            Roman_Digit'Write (Stream, Above);
+            Convert
+              (Value - (Lookup (Above) -
+                 Lookup (Roman_Digit'Pred(Roman_Digit'Pred (Above)))));
+         elsif Value /= Lookup (Above) and then
+           Roman_Digit'Pos(Above) rem 2 = 1 and then Value >= Lookup (Above) -
+           Lookup (Roman_Digit'Pred (Above))
+         then
+            Roman_Digit'Write (Stream,
+                               Roman_Digit'Pred (Above));
+            Roman_Digit'Write (Stream, Above);
+            Convert
+              (Value - (Lookup (Above) -
+                 Lookup (Roman_Digit'Pred (Above))));
+         else
+            Roman_Digit'Write (Stream, Roman_Digit'Pred(Above));
+            Convert (Value - Lookup (Roman_Digit'Pred (Above)));
+         end if;
+      end Convert;
+   begin
+      Convert (Arg);
+   end Image;
+
+  X : Roman_Integer := "III" * "IV" * "XII"; -- 144 ( i.e. CXLIV)
+
+...
+   --  Outputs  "Answer is 144 ( CXLIV )"
+   Put_Line ("Answer is" & Integer'Image(X)
+             & " ( " & Roman_Number'Image(X) & " )");
+
+
+I also have a working version of this, using Ada 2012 syntax, and one of my
+Stream Buffer class in case anyone is interested.
+
+****************************************************************
+
+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 
+"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 
+> 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 
+type of Roman_Number it is probably fine.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Thursday, June 20, 2019  10:58 AM
+
+Cute example, much better than the old one, ....
+
+****************************************************************
+
+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 
+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 
+both. [Not available here, see source below - Editor.]
+
+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 
+GNAT, such as @, and array aggregate with iterators.
+
+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 
+bits from the updated 202x version....
+
+  type Roman_Digit is ('I', 'V', 'X', 'L', 'C', 'D', 'M');
+
+   subtype Roman_Character is Character
+     with Static_Predicate =>
+       Roman_Character in 'I' | 'V' | 'X' | 'L' | 'C' | 'D' | 'M';
+
+   subtype Roman_String is String with
+     Dynamic_Predicate =>
+       (for all Char of Roman_String => Char in Roman_Character);
+
+   subtype Roman_Number is Positive range 1 .. 1_000 
+      with String_Literal => To_Roman_Number;
+   for Roman_Number'Put_Image use Image;
+
+   function To_Roman_Number (S : String) return Roman_Number
+     with Pre => (for all Char of S => Char in Roman_Character);
+
+   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))
+      begin
+        [for I in R'Range =>
+          (if I < R'Last and then R(I) < R(I + 1) then -1 else 1) * R(I))]
+            'Reduce("+", 0)
+     );
+
+   procedure Image
+     (Arg : Integer;
+      Stream : not null access Ada.Streams.Root_Stream_Type'Class)
+      with Pre => (Arg <= 1000);
+
+   procedure Image
+     (Arg : Integer;
+      Stream : not null access Ada.Streams.Root_Stream_Type'Class)
+   is
+      Lookup : constant array (Roman_Digit) of Roman_Number :=
+        ('I' => 1, 'V' => 5, 'X' => 10, 'L' => 50, 'C' => 100, 'D' => 500,
+         'M' => 1000);
+
+      procedure Convert (Value : Natural)
+      is
+         function To_Char (D : Roman_Digit) return Roman_Character is
+           (case D is
+               when 'I' => 'I',
+               when 'V' => 'V',
+               when 'X' => 'X',
+               when 'L' => 'L',
+               when 'C' => 'C',
+               when 'D' => 'D',
+               when 'M' => 'M');
+
+         Above : constant Roman_Digit :=
+            [for I in Lookup'Range when Lookup (I) >= Value => I]
+             'Reduce(Roman_Digit'Min, Roman_Digit'Last);
+      begin --  Convert
+         if Value = 0 then
+            return;
+         elsif Value = 1 then
+            Character'Write (Stream, 'I');
+         elsif Value = Lookup (Above) then
+            Character'Write (Stream, To_Char (Above));
+            Convert (Value - Lookup (Above));
+         elsif Roman_Digit'Pos (Above) rem 2 = 0
+           and then Value >= Lookup (Above) -
+           Lookup (Roman_Digit'Pred (Roman_Digit'Pred (Above)))
+         then
+            Character'Write
+              (Stream,
+               To_Char (Roman_Digit'Pred (Roman_Digit'Pred (Above))));
+            Character'Write (Stream, To_Char (Above));
+            Convert
+              (Value - (Lookup (Above) -
+                 Lookup (Roman_Digit'Pred (Roman_Digit'Pred (Above)))));
+         elsif Value /= Lookup (Above) and then
+           Roman_Digit'Pos (Above) rem 2 = 1 and then Value >= Lookup (Above) -
+           Lookup (Roman_Digit'Pred (Above))
+         then
+            Character'Write (Stream, To_Char (Roman_Digit'Pred (Above)));
+            Character'Write (Stream, To_Char (Above));
+            Convert
+              (Value - (Lookup (Above) -
+                 Lookup (Roman_Digit'Pred (Above))));
+         else
+            Character'Write (Stream, To_Char (Roman_Digit'Pred (Above)));
+            Convert (Value - Lookup (Roman_Digit'Pred (Above)));
+         end if;
+      end Convert;
+   begin --  Image
+      Convert (Arg);
+   end Image;
+
+  X : Roman_Number := "III" * "IV" * "XII"; -- 144 ( i.e. CXLIV)
+
+...
+   --  Outputs  "Answer is 144 ( CXLIV )
+   Put_Line ("Answer is" & Integer'Image(X)
+             & " ( " & Roman_Number'Image(X) & " )");
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, June 20, 2019  11:36 AM
+
+> 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 
+user-defined literal example.
+
+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".  
+
+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 
+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 
+preconditions and predicates in that case (replacing them with regular code)
+- those things aren't under test here.
+
+****************************************************************

Questions? Ask the ACAA Technical Agent