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

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

--- ai12s/ai12-0020-1.txt	2018/03/30 07:55:07	1.7
+++ ai12s/ai12-0020-1.txt	2018/06/07 00:51:47	1.8
@@ -1,4 +1,11 @@
-!standard 6.1.1(0/3)                                 18-02-28    AI12-0020-1/02
+!standard 4.10(0)                                     18-06-06    AI12-0020-1/03
+!standard 3.5(27.1/2)
+!standard 3.5(55.1/5)
+!standard 3.5(55.2/5)
+!standard 3.5(55.3/5)
+!standard 3.5(55.4/5)
+!standard 13.13.1(9)
+!standard 13.13.1(11)
 !class Amendment 12-02-14
 !status work item 12-02-14
 !status received 11-10-13
@@ -7,7 +14,9 @@
 !subject 'Image for all types
 !summary
 
-**TBD.
+Define T'Put_Image for all types, and redefine T'Image, T'Wide_Image,
+and T'Wide_Wide_Image in terms of it. (This provides a default image for
+objects of all types.)
 
 !problem
 
@@ -17,191 +26,535 @@
 !proposal
 
 T'Image is defined for all non-abstract types (including class-wide types).
-Ditto for T'Wide_Image and T'Wide_Wide_Image. T'Image and T'Wide_Image
-are defined in terms of T'Wide_Wide_Image just as they are already
-defined in the RM for scalar types. Image, Wide_Image, and Wide_Wide_Image
-attributes are defined for any object of a non-abstract type just as they
-are defined for any object of a scalar type today.
+Ditto for T'Wide_Image and T'Wide_Wide_Image.
 
+All of these are defined in terms of T'Put_Image, a stream-like attribute
+with the specification:
+
+   S'Put_Image
+       (Arg : T; Stream : access Counted_Stream'Class);
+
+Like streams, this routine can be specified for any type to give
+a user-defined image for that type. Also like streams, this routine is
+inherited by derived types (although it is always available, unlike
+stream attributes).
+
 Default implementation:
    For scalars - unchanged.
    For access types -
      Integer value displayed as a hex digits in square brackets,
-     except null displayed as "null". Number of hex digits determined
+     except null displayed as "NULL". Number of hex digits determined
      by size of access type. For example, "[FF0012AC]".
    For task types -
-      Undiscriminated: "(<task_id_image>)"
-      Discriminated: "(D1 => 123, D2 => 456, <task_id_image>)"
+      Undiscriminated: "(TASK <task_id_image>)"
+      Discriminated: "(TASK <task_id_image> with D1 => 123, D2 => 456)"
    For protected types -
       Nothing special. Same as any record type.
       Protected_Obj'Image is a protected function (this matters, for example,
       for locking).
-   For type extensions -
-      By default we treat a type extension the same as any other record type.
-      This may involve (in corner cases) having multiple components with
-      the same component name, but that's ok because the order disambiguates.
-
-      But suppose an ancestor type has a user-defined Image attribute
-      (actually a user-defined Put attribute, but we haven't gotten to
-      that detail yet; for purposes of this discussion, we will incorrectly
-      assume that Image is a user-specifiable attribute). In that case
-      we use extension aggregate syntax, as in
-         "(<parent part image> with C1 => 123, C2 => 4.5)" .
-	 
-      It might be more regular to always use extension-aggregate syntax but
-      the result would be less readable.
-
-   For other composite specific types:
-      Named aggregate syntax is used; only
-      white space is a single blank after "," and both before and after "=>".
-      This can result in double blanks in some cases, as in
+   For all other composite types:
+      Named aggregate syntax is used; only white space is a single blank 
+      after "," and both before and after "=>". This can result in double 
+      blanks in some cases, as in
          "(Field =>  123)"
       where the second blank comes from the image of the component value.
-      Record component names in upper case (same as existing rule for
-        'Image of enumeration values). TBD: Do we want to allow
-	Discard_Names to be specified for a record type, meaning that
-        implementation component names would be used in image functions?
-      Record component ordering follows positional aggregate rules.
-      Array index names generated via image.
-      Null arrays displayed as
-         "(1 .. 0 => <>)" or "(1 .. 0 => (1 .. 10 => <>))" 
-      Null records displayed as "(null record)".
-      [For an array with contiguous elements with the same image,
-      there is no collapsing down to a range. We get
-        "( 1 => False,  2 => False,  3 => True)"
-      instead of something like "( 1 ..  2 => False,  3 => True)]
-      [No special treatment for string types.]
-   For class-wide, the image obtained from the specific
-      type is prefixed with the Wide_Wide_Expanded_Name of the tag
-      and a "'", yielding qualified expression syntax, as in
-         "My_Pkg.My_Tagged_Type'(ABC => True, DEF => 123.45)"
-   Inherited by untagged derived types like streaming operators (although
-   no "availability" rules are needed - Image is always available).
-
-   TBD: Do we want to do anything special for predefined String types
-   so that, for example, String'Image ("cat") returns something other than
-   "( 1 => 'c',  2 => 'a',  3 => 't')"? Note that bounds information
-   would be missing if it returns "cat"; is that acceptable? Perhaps it
-   should return something like "1 .. 3 => ""cat""" (using usual Ada
-   double-quoting here for quotes-in-quotes). We could punt and make Put
-   implementation dependent for these types, but that seems like
-   sacrificing portability for no good reason.
-
-   TBD: Do we want to require anything about the images of predefined types
-   which are private (e.g., the variable length string types)? Portability
-   seems like less of an issue for these guys, but it seems worth mentioning.
+      For all record types:
+         Record component names in upper case (same as existing rule for
+           'Image of enumeration values).
+         Record component ordering follows positional aggregate rules.
+      For type extensions:
+         By default we treat a type extension the same as any other record type.
+         This may involve (in corner cases) having multiple components with
+         the same component name, but that's ok because the order disambiguates.
+         However, if an ancestor type has a user-defined Put_Image attribute,
+         we use extension aggregate syntax, as in
+             "(<parent part image> with C1 => 123, C2 => 4.5)" .
+  
+         It would have been more regular to always use extension-aggregate 
+         syntax but the result would be less readable, especially for deep 
+         hierarchies.
+      For class-wide types, the image obtained from the specific
+         type is prefixed with the Wide_Wide_Expanded_Name of the tag
+         and a "'", yielding qualified expression syntax, as in
+            "My_Pkg.My_Tagged_Type'(ABC => True, DEF => 123.45)"
+      For array types:
+         Array index names generated via image.
+         Null arrays displayed as
+            "(1 .. 0 => <>)" or "(1 .. 0 => (1 .. 10 => <>))" 
+         Null records displayed as "(NULL RECORD)".
+         There is no special treatment for string types.
+
+!wording
 
+
+We are going to define Image and related attributes for (almost) all types
+and objects, so we begin by deleting the existing definitions which are
+specific to scalars.
+
+Delete 3.5(27.1/2 - 37.a/2, 55.1/5-55.4/4)
+
+In 3.5(37.12, 38, and 39), replace the three occurrences of
+  "over all values of the subtype S"
+with
+  "over all values of the subtype S, assuming a default
+  implementation of S'Put_Image".
+
+In 3.5(43/3 and 55/3), replace the two occurrences of
+  "(or corresponds to the result of S'Image for a value of the type)"
+with
+  "(or corresponds to the result of S'Image for a value of the type,
+   assuming a default implementation of S'Put_Image)".
+
 ====
 
-Default implementation of T'Image for a type T is defined in terms of another
-subprogram-valued attribute, T'Put. T'Image cannot be overridden with a
-user-defined subprogram but T'Put can (which is how one gets the effect of
-a user-defined Image function). In other words, Put is a specifiable
-attribute and Image is not. [Attribute name "Put" is, of course, TBD.
-Perhaps "Put_Image"?]
-
-The idea here is that we want to avoid excessive copying as we build
-up the image value of a composite type. Instead, we do all the "real" work
-in "Put" procedures which pass around a stream parameter which is used
-as a buffer. A typical Put procedure contains calls to Wide_Wide_String'Write
-and, in the case of a composite type, a call to each component's Put procedure.
+Add a new subclause
 
-Before going into further detail about Image and Put attributes, we first
-introduce some new predefined child units (TBD: names are tentative).
+   4.10  Images
 
-    package Ada.Streams.Counted_Streams is
-       type Counted_Stream is abstract new Root_Stream_Type with private;
+   For every subtype S of a non-universal type T, the following
+   type-related operational attributes are defined:
 
-       function Element_Count (Stream : Buffered_Stream)
-         return Stream_Element_Count is abstract;
-    end;
+      S'Put_Image
+         S'Put_Image denotes a procedure with the following specification:
+            S'Put_Image
+               (Arg : T; Stream : access Counted_Stream'Class);
+ 	    
+      The default implementation of S'Put_Image writes out
+      (using Wide_Wide_String'Write and or Wide_Wide_String'Output)
+      an image of the value of Arg; that is, a Wide_Wide_String
+      representing the value in display form.
+      This is described in more detail later in this section.
+
+      The Put_Image attribute may be specified for any specific
+      type T either via an attribute_definition_clause or via an
+      aspect_specification specifying the Put_Image aspect of the type.
+
+      AARM Note: In contrast, the Image, Wide_Image, and Wide_Wide_Image
+      attributes and their associated aspects may not be specified.
+      The behavior of any of these attributes is defined in
+      terms of calls to the corresponding Put_Image procedure, so changes
+      in their behavior may be accomplished via a Put_Image specification.
+
+      S'Wide_Wide_Image
+
+         S'Wide_Wide_Image denotes a function with the following specification:
+            function S'Wide_Wide_Image (Arg : S'Base)
+              return Wide_Wide_String
+
+        The implementation of S'Wide_Wide_Image calls S'Put_Image
+        (which will typically write a sequence of Wide_Wide_Character values
+	out to a stream) and then returns the result of reading the contents
+        of that stream; the lower bound of that result is 1.
+        More specifically, it is equivalent to
+	
+           function T'Wide_Wide_Image (Arg : T) return Wide_Wide_String is
+              Local_Stream : aliased
+                Ada.Streams.Counted_Streams.Unbounded.Unbounded_Stream;
+                -- see 13.13.1
+
+              Elements_Per_Char : constant :=
+                Wide_Wide_Character'Stream_Size / Stream_Element'Size;
+                -- typically 4
+           begin
+              T'Put_Image (Arg, Local_Stream'Access);
+              return Result :
+                Wide_Wide_String (1 ..
+                 (Element_Count (Local_Stream) + (Elements_Per_Char - 1))
+                 / Elements_Per_Char)
+              do
+                 Wide_Wide_String'Read (Result, Local_Stream'Access);
+              end return;
+           end;
+
+         except that if the value of T'Max_Image_Elements (see below)
+         is not -1 then the variable Local_Stream is instead declared as
+              Local_Stream : aliased
+                Ada.Streams.Counted_Streams.Unbounded.Unbounded_Stream
+                  (Max_Elements => T'Max_Image_Elements);
+                -- see 13.13.1
+         .
+
+      S'Wide_Image
+         S'Wide_Image denotes a function with the following specification: 
+         function S'Wide_Image (Arg : T) return Wide_String
+
+         The function returns an image of the value of Arg as a Wide_String.
+         The lower bound of the result is one. The image has the same sequence
+	 of graphic characters as defined for S'Wide_Wide_Image if all the
+	 graphic characters are defined in Wide_Character; otherwise, the
+	 sequence of characters is implementation defined (but no shorter
+	 than that of S'Wide_Wide_Image for the same value of Arg). 
+
+     S'Image
+        S'Image denotes a function with the following specification: 
+           function S'Image(Arg : S'Base) return String
+
+        The function returns an image of the value of Arg as a String.
+        The lower bound of the result is one. The image has the same
+	sequence of graphic characters as that defined for S'Wide_Wide_Image
+	if all the graphic characters are defined in Character; otherwise,
+	the sequence of characters is implementation defined (but no shorter
+	than that of S'Wide_Wide_Image for the same value of Arg). 
+
+     S'Max_Image_Elements
+        S'Max_Image_Elements yields the value of T's Max_Image_Elements
+        aspect. The type of both the aspect and the attribute is
+        Ada.Streams.Stream_Offset.
+        The Max_Image_Elements attribute may be specified for any type
+        type T either via an attribute_definition_clause, via an
+        an aspect_specification specifying the Put_Image aspect of the type,
+	or (in the case of a derived type) via inheritance.
+        If specified, the aspect_definition shall be a static expression in
+	the range -1 .. Ada.Streams.Stream_Element_Offset'Last.
+	If no value for the aspect is specified, then value of the aspect
+        is determined by any Default_Max_Image_Elements
+        pragmas (described below) which are applicable to the compilation unit
+	in which T's full declaration occurs, if any such pragmas exist.
+	If no value for the aspect is specified and no such pragma exists,
+	then the value of the aspect is -1.
+
+    Pragma Default_Max_Image_Elements is a configuration pragma which
+    takes a single argument, a static expression of type
+    Ada.Streams.Stream_Offset in the range
+    -1 .. Ada.Streams.Stream_Element_Offset'Last.
+    Pragma Default_Max_Image_Elements shall not be used other than
+    as a configuration pragma. If more than one Default_Max_Image_Elements
+    pragma applies to a given compilation unit, then they shall all
+    specify equal (static) Stream_Element_Offset values.
+
+    The behavior of the default implementation of S'Put_Image depends
+    on the class of T. For an elementary type, the implementation is
+    equivalent to
+       procedure Put_Image
+         (Arg : Scalar_Type; Stream : access Counted_Stream'Class)
+       is
+       begin
+          Wide_Wide_String'Write (<described below>, Stream)
+       end;
+    where the Wide_Wide_String value written out to the stream is
+    defined as follows:
+
+       AARM Discussion: In earlier versions of Ada, Image and related 
+       attributes were defined only for scalar types. The definition of these
+       attributes is now textually very different, but it is intended
+       that there should be no change in the behavior of existing
+       programs as a result of these changes. End AARM Discussion.
+
+       For an integer type, the image written out is the corresponding
+       decimal literal, without underlines, leading zeros, exponent, or
+       trailing spaces, but with a single leading character that is either
+       a minus sign or a space.
+
+       For an enumeration type, the image written out is either the
+       corresponding identifier in upper case or the corresponding character
+       literal (including the two apostrophes); neither leading nor trailing
+       spaces are included. For a nongraphic character (a value of a character
+       type that has no enumeration literal associated with it), the value is
+       a corresponding language-defined name in upper case (for example,
+       the image of the nongraphic character identified as nul is “NUL” —
+       the quotes are not part of the image).
+
+       For a floating point type, the image written out is a decimal real
+       literal best approximating the value (rounded away from zero if
+       halfway between) with a single leading character that is either a minus
+       sign or a space, a single digit (that is nonzero unless the value is
+       zero), a decimal point, S'Digits–1 (see 3.5.8) digits after the
+       decimal point (but one if S'Digits is one), an upper case E, the sign
+       of the exponent (either + or –), and two or more digits (with leading
+       zeros if necessary) representing the exponent. If S'Signed_Zeros is
+       True, then the leading character is a minus sign for a negatively
+       signed zero.
+
+       For a fixed point type, the image written out is a decimal real literal
+       best approximating the value (rounded away from zero if halfway between)
+       with a single leading character that is either a minus sign or a space,
+       one or more digits before the decimal point (with no redundant leading
+       zeros), a decimal point, and S'Aft (see 3.5.10) digits after the
+       decimal point.
+
+       For an access type (named or anonymous), the image written out depends
+       on whether the value is null. If it is null, then the image is "NULL".
+       Otherwise the image is a sequence of uppercase hexadecimal digits
+       representing the value enclosed in square brackets, as in "[FF0012AC]".
+       The number of hexadecimal digits will be the same for all non-null
+       values of any one access type.
+
+   [In general, the default implementation of T'Put_Image for a composite
+   type will involve some sequence of calls to Wide_Wide_String'Write
+   and calls to the Put_Image procedures of component types and, in the
+   case of an array type, index types. The Wide_Wide_String'Write calls
+   may pass in either literal values (e.g., "(", ")", "'(", " => ", or ", "),
+   or other things (such as component names for record values, task_id
+   images for tasks, or the Wide_Wide_Expanded_Name of the tag in the
+   class-wide case).]
+
+   For an array type T, the default implementation of
+   T'Put_Image generates an image based on (named, not positional)
+   array aggregate syntax using calls to the Put_Image procedures of
+   the index type(s) and the element type to generate images for values
+   of those type.
+   This might generate an image such as
+       "( 1 => ( 1 => ( 123 => True,  124 => False),  2 => ( 123 => False,  124 => False)),  2 => ( 1 => ( 123 => True,  124 => True),  2 => ( 123 => True,  124 => False)))"
+   .
+   The case of a null array is handled specially, using ranges for
+   index bounds and "<>" as a syntactic component-value placeholder.
+   This might generate an image such as
+   "( 1 ..  3 => ( 1 ..  0 => ( 1 .. 5 => <>))), where the use of "<>"
+   (among other things) indicates that the array argument is a null array.
+
+   The the order in which components are written for
+   a composite type is the same canonical order in
+   which, for example, components of a composite type T are written out
+   by the default implementation of T'Write. [This is also the
+   order that is used in determining the meaning of a positional aggregate
+   of type T.]
+
+   For a class-wide type, the default implementation of T'Put_Image
+   generates an image based on qualified expression syntax.
+   Wide_Wide_String'Write is called with Wide_Wide_Expanded_Name of Arg'Tag.
+   Next the literal "'(" is written out.
+   Then Corresponding_Specific_Type'Put_Image is called. [At the
+   implementation level this will typically require a dispatching call.]
+   Finally a right parenthesis is written. This might generate an image
+   such as
+      "SOME_PACKAGE.SOME_TAGGED_TYPE'(COMPONENT_1 =>  123, COMPONENT_2 =>  456)"
+   .
+
+   For a (specific) type extension, the default implementation of T'Put_Image
+   depends  on whether there exists a non-interface ancestor of T (other than
+   T itself) for which the Put_Image aspect has been [explicitly] specified.
+   If so, then T'Put image will generate an image based on extension aggregate
+   syntax where the ancestor type of the extension aggregate is the
+   nearest ancestor type whose Put_Aspect has been specified.
+   [This might generate an image such as
+   "(This Text Was User-Generated with C1 =>  123, C2 =>  456)"
+   where the "This Text was User-Generated" portion of the text was
+   generated by the call to the user-specified Put_Image routine.]
+   If no such ancestor exists, then the default implementation of T'Put_Image
+   is the same as described below for an untagged record type.
+
+   For an untagged record type, a specific tagged record type other than
+   a type extension which meets the criteria described in the previous
+   paragraph, or a protected type, the default implementation of
+   T'Put_Image generates an image based on (named, not positional) record
+   aggregate syntax. Component names are displayed in upper case,
+   following the rules for the image of an enumeration value. Component
+   values are displayed via calls to the component type's Put_Image
+   procedure. This might generate an image such as
+   "(FOO => ( 1 => 'c',  2 => 'a',  3 => 't'), BAR => TRUE)".
+   The image written out for a record having no components (including
+   any interface type) is "(NULL RECORD)".
+   In the case of a protected type T, a call to the default implementation
+   of T'Put_Image begins only one protected (readonly) action.
+
+   [AARM Implementation Note: The expected, but
+   not required, implementation model for generating the image of a
+   protected record involves the compiler producing a
+   "helper" protected function which T'Put_Image would call. The result
+   type of this function might be a null record; it is only a function
+   because it does not need a write-lock, not because it returns a
+   meaningful result.]
+
+   [TBH - Note that the assertion in the following example should succeed:
+      type T1 (D1, D2 : Positive) is record ... end record; -- untagged
+      type T2 (D : Positive) is new T1 (D1 => D, D2 => D);
+      X : T2 (D => 123) := ... ;
+      pragma Assert (X'Image /= T1(X)'Image);]
+
+   For an undiscriminated task type, the default implementation of T'Put_Image
+   generates an image of the form "(TASK <task_id_image>)"
+   where <task_id_image> is the result obtained by calling
+   Ada.Task_Identification.Image with the id of the given task.
+   For a discriminated task type, the default implementation of T'Put_Image
+   also includes discriminant values, as in
+   "(TASK <task_id_image> with D1 =>  123, D2 =>  456)".
+
+For a prefix X that denotes an object of a non-universal type T, the following
+attributes are defined:
+   X'Wide_Wide_Image
+      X'Wide_Wide_Image denotes the result of calling function
+      S'Wide_Wide_Image with Arg being X, where S is the nominal subtype of X.
+   X'Wide_Image
+      X'Wide_Image denotes the result of calling function S'Wide_Image with
+      Arg being X, where S is the nominal subtype of X.
+   X'Image
+      X'Image denotes the result of calling function S'Image with Arg being X,
+      where S is the nominal subtype of X.
 
-    package Ada.Streams.Counted_Streams.Unbounded is
-       -- intended implementation uses allocators, controlled types, etc.
+====
 
-       type Unbounded_Stream is new Counted_Stream with private;
-       overriding procedure Read (...);
-       overriding procedure Write (...);
-       overriding function Element_Count ...;
-    end;
+Add after 13.13.1(9) (the end of the static semantics section):
 
-    package Ada.Streams.Counted_Streams.Bounded is
-       -- same as unbounded except for the discriminant
+   The following related units are also declared.
 
-       type Bounded_Stream (Max_Elements : Stream_Element_Count)
-         is new Counted_Stream with private;
-       overriding procedure Read (...);
-       overriding procedure Write (...);
-       overriding function Element_Count ...;
-    end;
-       
-The Bounded variant isn't strictly needed for this AI, but it is provided
-for use in calls to T'Put when compilation restrictions would
-preclude use of the Unbounded package (and therefore uses of 'Image
-for non-scalar types).
-
-For each non-abstract type T, T'Put is a procedure with the profile
-  (<arg> : T; Stream : access Counted_Stream'Class);
-
-For every type T such that T'Wide_Wide_Image is defined, that function
-is defined to be equivalent to the following implementation:
-
-    function T'Wide_Wide_Image (<arg> : T) return Wide_Wide_String is
-       Local_Stream : aliased
-         Ada.Streams.Counted_Streams.Unbounded.Unbounded_Stream;
-       Elems_Per_Char : constant :=
-         Wide_Wide_Character'Stream_Size / Stream_Element'Size;
-	 -- typically 4
-    begin
-       T'Put (<arg>, Local_Stream'Access);
-       return Result :
-         Wide_Wide_String (1 ..
-           (Element_Count (Local_Stream) + Elems_Per_Char - 1)
-           / Elems_Per_Char) do
-           Wide_Wide_String'Read (Result, Local_Stream'Access);
-       end return;
-    end;
+      package Ada.Streams.Counted_Streams is
+         type Counted_Stream is abstract new Root_Stream_Type with private;
+
+         function Element_Count (Stream : Counted_Stream)
+           return Stream_Element_Count is abstract;
+      end Ada.Streams.Counted_Streams;
+
+       package Ada.Streams.Counted_Streams.Unbounded is
+          type Unbounded_Stream is new Counted_Stream with private
+          with Default_Initial_Condition =>
+            Element_Count (Unbounded_Stream) = 0;
+
+          overriding
+          procedure Read (
+	     Stream : in out Unbounded_Stream;
+             Item   : out Stream_Element_Array;
+             Last   : out Stream_Element_Offset)
+             with Post =>
+               Element_Count (Stream) =
+               Element_Count (Stream)'Old - Item (Item'First .. Last)'Length;
+          overriding
+          procedure Write (
+             Stream : in out Unbounded_Stream;
+             Item   : in Stream_Element_Array)
+             with Post =>
+               Element_Count (Stream) =
+               Element_Count (Stream)'Old + Item'Length;
+          overriding
+          function Element_Count (Stream : Unbounded_Stream)
+             return Stream_Element_Count;
+       end Ada.Streams.Counted_Streams.Unbounded;
+
+       package Ada.Streams.Counted_Streams.Bounded is
+         -- same as Unbounded except for the discriminant
+
+         type Bounded_Stream (Max_Elements : Stream_Element_Count)
+           is new Counted_Stream with private
+           with Default_Initial_Condition =>
+             Element_Count (Unbounded_Stream) = 0;
+
+          overriding
+          procedure Read (
+	     Stream : in out Bounded_Stream;
+             Item   : out Stream_Element_Array;
+             Last   : out Stream_Element_Offset)
+             with Post =>
+               Element_Count (Stream) =
+               Element_Count (Stream)'Old - Item (Item'First .. Last)'Length;
+          overriding
+          procedure Write (
+             Stream : in out Bounded_Stream;
+             Item   : in Stream_Element_Array)
+             with Pre =>
+               Element_Count (Stream) + Item'Length <= Stream.Max_Elements
+               or else (raise Constraint_Error)
+             with Post =>
+               Element_Count (Stream) =
+               Element_Count (Stream)'Old + Item'Length;
+          overriding
+          function Element_Count (Stream : Bounded_Stream)
+             return Stream_Element_Count
+             with Post => Element_Count'Result <= Stream.Max_Elements;
+       end Ada.Streams.Counted_Streams.Bounded;
+
+The Element_Count functions return the number of stream elements
+that are available for reading in the given stream.
+
+====
+
+Add after 13.13.1(9.1/1):
+
+Implementation Advice
 
-Wide_Wide_Image is not a specifiable attribute (nor are Wide_Image or
-Image). However, Put is a specifiable attribute. Given X of type T,
-X'Put (<stream arg>) is equivalent to T'Put (X, <stream arg>).
-
-Note that the usual "as if" optimization rules apply, so that this
-definition does not require any change in the existing default implementation
-of a scalar type's image function. It probably needs to be stated explicitly
-that a use of T'Image for a scalar type T doesn't violate any restrictions
-pertaining to dynamic storage allocation, controlled types, dispatching, unless
-the default implementation of T'Put has been overridden ... details TBD.
-
-In situations where dynamic storage allocation and/or controlled types are
-disallowed, one could imagine a compiler option which causes the local variable
-declared by the compiler inside each Wide_Wide_Image function to be of
-type Bounded_Stream instead of Unbounded_Stream, with the discriminant
-value determined via a (user-specified?) aspect associated with the type.
+Bounded_Stream objects should be implemented without implicit pointers or
+dynamic allocation.
 
-The default implementation of Put for a Scalar type is equivalent to
+!discussion
+
+This change does introduce an obscure incompatibility having to do with
+implicit dereferencing when the prefix of an Image (or Wide_Image, or
+Wide_Wide_Image) attribute is an object of an access-to-scalar type.
+Consider the following example:
+
+    type Int_Ref is access Integer;
+    Ptr : Int_Ref := new Integer'(123);
+    Ptr_Image : String := Ptr'Image;
+    pragma Assert (Ptr_Image = Ptr.all'Image);
+
+With the current language definition, the assertion should succeed.
+See the words "(after any implicit dereference)" in
+3.5(55.1/5); this wording was added as part of AI12-0124.
+
+With the proposed changes, the program remains legal but the assertion
+will now fail because Ptr_Image will be initialized with the image of
+an access value, as opposed to the image of an integer value.
+Clients of the GNAT and Janus Ada compilers will be unaffected by this
+incompatibility because these compilers do not currently accept the
+above (legal) example; it seems likely that this is true of other
+Ada implementations, but this has not been confirmed.
+
+---
+
+In some obscure cases, the image of a record value may include
+multiple components with the same name. For example
+   package Pkg is
+     type T1 is tagged private;
+   private
+     type T1 is tagged record Foo : Integer := 123; end record;
+   end;
+
+   type T2 is new T1 with record Foo : Integer := 456; end record;
+
+   X2 : T2;
+   pragma Assert (X2'Image = "(FOO =>  123, FOO =>  456)");
+
+In cases like this, the ordering of the component values prevents
+ambiguity.
+
+---
+
+A derived type which defines new discriminants behaves as one
+would expect (i.e., consistently with the rules for record
+aggregates and for streaming). For example, the assertion in the
+following example will succeed:
+
+   type T1 (D1, D2 : Integer) is record F : Integer := 123; end record;
+   type T2 (D3 : Integer) is new T1 (D1 => D3, D2 => D3);
+   X : T2 (456);
+   pragma Assert (X'Image = "(D3 =>  456, F =>   123)");
+
+----
+
+If a protected type T has protected subcomponents, then the default
+implementation of T'Put_Image will probably violate the
+no-potentially-blocking-ops-during-a-protected-action rule.
+Do we want any sort of legality rules relating to this?
+In evaluating any possible rules relating to this scenario, keep in mind
+the case of a protected type declared in the body of a generic unit with a
+subcomponent of a formal limited private type whose corresponding actual
+type, for some particular instance of the generic, is a protected type.
+
+----
+
+The default implementation of Put_Image for a Scalar type is equivalent to
 
-    procedure Put
+    procedure Put_Image
       (<arg> : Scalar_Type; Stream : access Counted_Stream'Class) is
        Wide_Wide_Image : constant Wide_String := <as described in RM>;
     begin
        Wide_Wide_String'Write (Wide_Wide_Image, Stream)
-    end;
+    end Put_Image;
 
 For a record type having components C1, C2, and C3 (in that order, as
 given by the component ordering rules for a positional record aggregate),
 the default implementation of Put is equivalent to
-   procedure Put (<arg> : Record_Type; Stream : access Counted_Stream'Class) is
+
+   procedure Put_Image
+     (<arg> : Record_Type; Stream : access Counted_Stream'Class) is
    begin
       Wide_Wide_String'Write ("(", Stream);
       Wide_Wide_String'Write ("C1 => ", Stream);
       <arg>.C1'Put (Stream)
       Wide_Wide_String'Write (", C2 => ", Stream);
-      <arg>.C1'Put (Stream)
+      <arg>.C2'Put (Stream)
       Wide_Wide_String'Write (", C3 => ", Stream);
-      <arg>.C1'Put (Stream)
+      <arg>.C3'Put (Stream)
       Wide_Wide_String'Write (")", Stream);
-   end;      
+   end Put_Image;      
 
 A variant part introduces a corresponding case statement.
 
@@ -229,21 +582,11 @@
    end;      
 
 Other types are handled similarly; just calls to Wide_Wide_String'Write mixed
-with Put calls for components. Note that the implementation of T'Class'Put
-will involve a dispatching call to the Put of the corresponding specific type
-(after writing out the Wide_Wide_Expanded_Name of the tag and a "'"), so
-that requires a new entry in the dispatch table for each tagged type.
-
-!wording
-
-** TBD.
-
-!discussion
-
-Ada has a way to automatically create stream attributes and equality, so there
-is some sense to supporting a way to do that for 'Image as well. But care would
-be needed: some representation would be needed for access types, and do we want
-to support 'Value for complex records?
+with Put_Image calls for components. Note that the implementation of
+T'Class'Put_Image will involve a dispatching call to the Put_Image of the 
+corresponding specific type (after writing out the Wide_Wide_Expanded_Name of 
+the tag and a "'"), so that requires a new entry in the dispatch table for each
+tagged type.
 
 !ACATS test
 
@@ -1396,5 +1739,212 @@
     type T2 (D : Positive) is new T1 (D1 => D, D2 => D);
     X : T2 (D => 123) := ... ;
     pragma Assert (X'Image /= T1(X)'Image);
+
+***************************************************************
+
+From: Steve Baird
+Sent: Monday, May 28, 2018  5:04 PM
+
+Here is a first attempt at !wording for this AI. [This is version /03 of the
+AI - Editor.]
+
+There is also a small !discussion section, but it discusses only a few corner
+cases; it is by no means complete. For example, the !discussion section lacks
+a rationale for why the Put_Image attribute/aspect was introduced and why 
+Put_Image is user-specifiable but [Wide_[Wide_]]Image is not.
+
+Undoubtedly several rough spots remain (although Randy already caught several 
+for me in his preliminary review), but hopefully this can at least give us a 
+preliminary version to work with.
+
+One question I have is whether the level of precision of the description of 
+the default implementations of the T'Put_Image for a composite type T is 
+acceptable.
+
+For example, for a record type we pretty much just say that we display 
+components in the canonical order using positional aggregate syntax, 
+displaying component names in upper case and calling each component type's
+Put_Image procedure to display component values. Then we give an example and
+that's about it.
+
+Given this approach, it is not clear whether these examples belong in normal
+RM text (which is how I have presented them) or as examples presented 
+separately in an "Examples" section.
+
+Take a look at the proposed presentation and see what you think.
+
+As always, feedback is appreciated.
+
+***************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, June 6, 2018  7:35 PM
+
+> Here is a first attempt at !wording for this AI.
+
+For the record, here's a few editorial-ish things that I did when posting
+this:
+
+(1) You didn't give a !summary or a !proposal. It seemed useful to have the 
+short overview of the default images for each kind of type, so I left that 
+(hopefully I found all of the changes), following a couple introductory 
+paragraphs. The rest was dropped.
+
+(2) I moved the example "Put_Image" implementations into the !discussion; 
+they seemed valuable and shouldn't get lost. (Fixing the names, of course,
+and also fixing the component names in the record case (they were all
+"C1").)
+
+(3) I changed the wording instructions to start with a capital letter. That 
+is "Delete 3.5(...", not "delete 3.5(...". Added a few missing commas into 
+those, too. The paragraph references should mention AARM paragraphs 
+separately, but I didn't fix that yet.
+
+(4) "new section 4.10 named "Images":" should say "Add a new subclause
+                                                   4.10 Images"
+"Section" is ISO-speak for an entire printed document; 4 is a "clause" and
+4.10 (and smaller subdivisions) are "subclauses".
+
+(5) "append to the end of the static semantics section of 13.13.1:"
+
+We need to give the paragraph number where this happens here. So I replaced
+this with:
+
+"Add after 13.13.1(9) (the end of the static semantics section):"
+
+Similarly for the next reference (should be to 13.13.1(9.1/1)).
+
+(6)
+   For a discriminated task type, the default implementation of T'Put_Image
+   also includes discriminant values, as in
+      "(TASK <task_id_image> with D1 =>  123, D2 =>  456)"
+   .
+
+We aren't even allowed to use a hanging period like this in AI text, much less
+in the RM. But we don't need the extra indentation anyway, as the example 
+should be in the example font. So this would read better as
+
+   For a discriminated task type, the default implementation of T'Put_Image
+   also includes discriminant values, as in
+   "(TASK <task_id_image> with D1 =>  123, D2 =>  456)".
+
+We're hoping that the editor remembers to mark these examples in the example 
+font, but that's pretty likely (I know him well :-).
+
+I reformatted the other examples to match, similar reasoning applies.
+
+(7)
+          overriding procedure Read (
+	     Stream : in out Unbounded_Stream;
+             Item   : out Stream_Element_Array;
+             Last   : out Stream_Element_Offset)
+
+The recommended formatting of overriding indicators has them on a separate 
+line from the rest of the subprogram declaration, much like "generic". The RM
+is supposed to follow this recommended formatting, regardless of what you 
+normally do in your own code. I fixed all of these declarations.
+
+===================================
+
+And here are a few minor comments:
+
+(C1)
+         except that if the value of T'Max_Image_Elements (see below)
+         is not -1 then the variable Local_Stream is instead declared as
+              Local_Stream : aliased
+                Ada.Streams.Counted_Streams.Unbounded.Unbounded_Stream
+                  (Max_Elements => T'Max_Image_Elements);
+
+Isn't this case supposed to use the Bounded form of the stream? The Unbounded 
+form doesn't even have a discriminant. I'd guess that "Un" should be deleted 
+from the above text (twice).
+
+(C2)
+    Pragma Default_Max_Image_Elements is a configuration pragma which
+    takes a single argument, a static expression of type
+    Ada.Streams.Stream_Offset in the range
+    -1 .. Ada.Streams.Stream_Element_Offset'Last.
+    Pragma Default_Max_Image_Elements shall not be used other than
+    as a configuration pragma. If more than one Default_Max_Image_Elements
+    pragma applies to a given compilation unit, then they shall all
+    specify equal (static) Stream_Element_Offset values.
+
+I'm not sure that we can use such a short definition of a pragma. All pragmas 
+that I can think of give a syntax definition; even List and Page do that. So I
+think we need to define the "form" of this pragma, with a Syntax portion.
+(Ugh, I know.)
+
+(C3) You probably ought to add a paragraph to the discussion describing the 
+model and use of Bounded_Stream. I know why it's there ('cause you told me),
+but it doesn't seem to be mentioned anywhere in the AI.
+
+(C4) You deleted all of the AARM notes along with the original definition of 
+Wide_Wide_Image, but you didn't put them back into the discussion of the 
+default images of the various types. That seems like (relatively) important
+information about topics like Negative Zeros and rounding is getting lost.
+The Impldef information for Wide_Image and Image definitely has to move (so 
+the annex M.1 listing doesn't lose them). A similar thought applies to 55.b/5.
+
+(C5) Under the image of arrays, you have:
+
+   This might generate an image such as
+       "( 1 => ( 1 => ( 123 => True,  124 => False),  2 => ( 123 => False,
+124 => False)),  2 => ( 1 => ( 123 => True,  124 => True),  2 => ( 123 => True,  124 => False)))"
+
+This is too long for a line in the RM. It will get folded somehow, and that 
+would probably give an incorrect interpretation of the actual result. (I see
+this e-mail editor folded it!) I don't know what the appropriate answer is 
+here, but this can't be in the RM as written; we need an alternative that fits
+in one line or additional wording to explain the extra line breaks.
+
+(C6)
+
+For a prefix X that denotes an object of a non-universal type T, the following
+attributes are defined:
+
+This is wrong, unless you mean to disallow using 'Image on a universal integer
+object. And if you meant to do that, you need to explain why and explain the
+(significant) incompatibility in the !discussion section.
+Moreover, you've reintroduced the object bug fixed in AI12-0225-1. We don't 
+want X to have to denote an object!
+
+Otherwise, this should read:
+
+For a prefix X of a type other than universal_real or universal_fixed, the 
+following attributes are defined:
+
+Perhaps you need to make a similar change to Put_Image; there's no problem 
+defining it for the (dynamic) universal_integer type (that is the largest 
+signed integer type). You can't *redefine* that attribute, but that shouldn't
+matter.
+
+(C7) We've previously discussed in passing the need for Ada to have 
+"marshalling" streams. (Claw has had those since 1999 - we needed them to
+pack/unpack binary clipboard and registry contents - items that have to be
+read/written in a single operation.) You're actually adding them sort of by
+the back door. I have to wonder if they ought to have a bit more visibility
+and if the names are right -- these packages fulfill an important need 
+having nothing to do with Image.
+
+We have a "Clear" operation to discard the contents - that seems useful in 
+more general usage, even if Put_Image will never need it.
+
+We also had an initial size discriminant for the unbounded form. Not as sure
+if that's useful, or if there should be some Reserve_Capacity operation for 
+the unbounded form. (We did it that way for the containers.)
+
+(C99) "If a protected type T has protected subcomponents, then the default
+implementation of T'Put_Image will probably violate the 
+no-potentially-blocking-ops-during-a-protected-action rule.
+Do we want any sort of legality rules relating to this?
+In evaluating any possible rules relating to this scenario, keep in mind the
+case of a protected type declared in the body of a generic unit with a 
+subcomponent of a formal limited private type whose corresponding actual type,
+for some particular instance of the generic, is a protected type."
+
+I guess it couldn't be a Steve Baird AI without at least one such case.
+*Everyone* is worried about taking the image of a protected object declared in
+a generic body with a component of a formal limited private type. Happens 
+every other day! ;-)
 
 ***************************************************************

Questions? Ask the ACAA Technical Agent