Version 1.23 of ai12s/ai12-0020-1.txt

Unformatted version of ai12s/ai12-0020-1.txt version 1.23
Other versions for file ai12s/ai12-0020-1.txt

!standard 4.10(0)          20-01-06 AI12-0020-1/11
!standard 3.5(27.1/2)
!standard 3.5(27.2/2)
!standard 3.5(27.3/2)
!standard 3.5(27.4/2)
!standard 3.5(27.5/2)
!standard 3.5(27.6/2)
!standard 3.5(27.7/2)
!standard 3.5(28)
!standard 3.5(29)
!standard 3.5(30/3)
!standard 3.5(31)
!standard 3.5(32)
!standard 3.5(33/3)
!standard 3.5(37.1/2)
!standard 3.5(38)
!standard 3.5(39)
!standard 3.5(43/3)
!standard 3.5(55/3)
!standard 3.5(55.1/5)
!standard 3.5(55.2/4)
!standard 3.5(55.3/4)
!standard 3.5(55.4/4)
!standard 3.5(59)
!standard H.4(23)
!standard H.4(23.8/2)
!class Amendment 12-02-14
!status Amendment 1-2012 18-11-27
!status WG9 Approved 22-06-22
!status ARG Approved 8-0-0 18-10-22
!status work item 12-02-14
!status received 11-10-13
!priority Medium
!difficulty Medium
!subject 'Image for all types
!summary
Define T'Put_Image for all types, and define (or redefine, for scalars) T'Image, T'Wide_Image, and T'Wide_Wide_Image in terms of it. This provides a default Image attribute for all types as well as the allowing (in effect) user-specified Image attributes for types.
!problem
Ada only provides 'Image for scalar types. However, for debugging in particular, an easy way to view an object of any type is useful.
!proposal
T'Image is defined for (almost) all types (including class-wide types). Ditto for T'Wide_Image and T'Wide_Wide_Image.
All of these are defined in terms of a procedure T'Put_Image, an attribute with the specification:
procedure T'Put_Image
(Arg : T; Stream : not null access Ada.Streams.Root_Stream_Type'Class);
Like stream attributes, this attribute 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). So to get the effect of a user-specified Image attribute, one specifies a user-defined Put_Image procedure.
The default implementation of S'Put_Image writes out to the stream (using Wide_Wide_String'Write) an image of the value of Arg; that is, a Wide_Wide_String representing the value in display form.
That Wide_Wide_String value is determined (approximately) as follows:
For scalars - the same image that Wide_Wide_Image already generated before
this AI.
For access types -
An implementation-defined string preceded by "(ACCCES", except null displayed as "NULL". The intent is that these would normally be a hex representation of the access value. For example, "(ACCESS FF0012AC)".
For task types -
Undiscriminated: "(TASK <task_id_image>)" Discriminated: "(TASK <task_id_image> with D1 => 123, D2 => 456)"
For protected types -
Same as for a record type except that the opening left parenthesis is followed by "PROTECTED with", as in "(PROTECTED with F1 => 123, F2 => 456)". Protected_Obj'Image is a protected function (this matters, for example, for locking).
For all other composite types:
Named aggregate syntax is used, as in
"(F1 => 123, F2 => 456)".
Null records displayed as "(NULL RECORD)". For type extensions:
By default we treat a type extension the same as any other record type. 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)" .
For class-wide types, the image obtained from the specific
type is prefixed with the 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 => <>]]" 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.1/2, 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)".
Modify 3.5(59):
For any value V (including any nongraphic character) of an enumeration subtype S {without a specified Put_Image (see 4.10)}, S'Value(S'Image(V)) equals V, as do S'Wide_Value(S'Wide_Image(V)) and S'Wide_Wide_Value(S'Wide_Wide_Image(V)). None of these expressions ever raise Constraint_Error.
====
Add a new subclause
4.10 Image Attributes
Static Semantics
For every subtype S of a non-universal type T, the following type-related operational attribute is defined:
S'Put_Image
S'Put_Image denotes a procedure with the following specification: procedure S'Put_Image (Arg : T;
Stream : not null access Ada.Streams.Root_Stream_Type'Class);
The default implementation of S'Put_Image writes (using Wide_Wide_String'Write) 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 cannot 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.
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 Ada.Streams.Root_Stream_Type'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 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.
[Editor's note: The rules and AARM notes for scalar types come
from the original definition of Image; they're unchanged here.]
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.
AARM Implementation Note: If the machine supports negative zeros for signed integer types, it is not specified whether " 0" or "-0" should be returned for negative zero. We don't have enough experience with such machines to know what is appropriate, and what other languages do. In any case, the implementation should be consistent.
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).
AARM Implementation Note: For an enumeration type T that has "holes" (caused by an enumeration_representation_clause), T'Put_Image should raise Program_Error if the value is one of the holes (which is a bounded error anyway, since holes can be generated only via uninitialized variables and similar things).
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.
AARM To be honest: Leading zeros are present in the exponent only if necessary to make the exponent at least two digits.
AARM Reason: This image is intended to conform to that produced by Text_IO.Float_IO.Put in its default format.
AARM Implementation Note: The rounding direction is specified here to ensure portability of output results.
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.
AARM Reason: This image is intended to conform to that produced by Text_IO.Fixed_IO.Put.
AARM Implementation Note: The rounding direction is specified here to ensure portability of output results.
AARM Implementation Note: For a machine that supports negative zeros, it is not specified whether " 0.000" or "–0.000" is returned. See corresponding comment above about integer types with signed zeros.
[Editor's note: End of pre-existing rules for scalar types.]
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 left parenthesis followed by "ACCESS", a space, and a sequence of graphic characters, other than space or right parenthesis, representing the location of the designated object, followed by a right parenthesis, as in "(ACCESS FF0012AC)".
AARM note: 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 (with '[' and ']' as the delimiters) using calls to the Put_Image procedures of the index type(s) and the element type to generate images for values of those types.
AARM note: 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]]] although perhaps with different white space and/or line breaking.
The case of a null array is handled specially, using ranges for index bounds and "<>" as a syntactic component-value placeholder.
AARM Note: This might generate an image such as "[ 1 .. 3 => [ 1 .. 0 => [ 1 .. 5 => <>]]]", where the use of "<>" (among other things) indicates that the overall array is a null array and has no actual elements.
The order in which components are written for a composite type is the same canonical order in which components of a composite type T are written out by the default implementation of T'Write. Redundant[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. Then S'Put_Image is called, where S is the specific type identified by Arg'Tag.
AARM Implementation Note: This will typically require a dispatching call.
AARM Note: This might generate an image such as:
SOME_PACKAGE.SOME_TAGGED_TYPE' (COMPONENT_1 => 123, COMPONENT_2 => 456)
The parentheses in this case are generated by the call to Some_Tagged_Type'Put_Image.
For a type extension, the default implementation of T'Put_Image depends on whether there exists a noninterface ancestor of T (other than T itself) for which the Put_Image aspect has been Redundant[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_Image aspect has been specified.
AARM note: 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 (except that for a protected type, the initial left parenthesis is followed by "PROTECTED with "). 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.
AARM note: 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)". The image written out for a componentless protected type is "(PROTECTED NULL RECORD)". In the case of a protected type T, a call to the default implementation of T'Put_Image begins only one protected (read-only) 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 - 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 and then passing that String to Characters.Conversions.To_Wide_Wide_String.
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)".
AARM note: If T is an unchecked union type, then the default implementation of T'Put_Image will raise Program_Error.
For every subtype S of a type T, the following attributes are defined:
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
S'Wide_Wide_Image calls S'Put_Image passing Arg (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 via Wide_Wide_String'Read; the lower bound of that result is 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 a Wide_String corresponding to the result of a call on S'Wide_Wide_Image with a parameter of Arg. The lower bound of the result is one. The result has the same sequence of graphic characters as that returned by 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 a Wide_String corresponding to the result of a call on S'Wide_Wide_Image with a parameter of Arg. The lower bound of the result is one. The result has the same sequence of graphic characters as that returned by 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).
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.
Implementation Permissions
An implementation may transform the image generated by the default implementation of S'Put_Image for a composite subtype S in the following ways:
- If S is a composite subtype, the leading character of the image of
a component value or index value is a space, and the immediately preceding character is an open parenthesis, then the space may be omitted. The same transformation is also permitted if the leading character of the component image is a space (in which case one of the two spaces may be omitted). [AARM note: This means that it is permitted to generate "(1 => 123, 2 => 456)" instead of "( 1 => 123, 2 => 456)".]
- If S is an array subtype, the low bound of the array in each dimension
equals the low bound of the corresponding index subtype, and the array value is not a null array value, then positional array aggregate syntax may be used. [AARM note: This means that it is permitted to generate "(TRUE, TRUE, FALSE)" instead of "( 1 => TRUE, 2 => TRUE, 3 => FALSE)" if the low bound of the index subtype is one.]
- If S is an array subtype and the given value can be displayed using
named array aggregate syntax where some discrete_choice_list identifies more than one index value by identifying a sequence of one or more ranges and values separated by vertical bars, then this image may be generated instead; this may involve the reordering of component values. [AARM note: This means that it is permitted to generate "( 1 .. 2 | 5 => TRUE, 3 .. 4 => FALSE)" instead of "( 1 => TRUE, 2 => TRUE, 3 => FALSE, 4 => FALSE, 5 => TRUE)".]
- Similarly, if S is a record subtype (or a discriminated type) and the
given value can be displayed using named component association syntax where the length of some component_choice_list is greater than one, then this image may be generated instead; this may involve the reordering of component values. [AARM note: This means that it is permitted to generate "(F1 | F2 => TRUE)" instead of "(F1 => TRUE, F2 => TRUE)".]
- Additional spaces, carriage returns, and line feeds (Wide_Wide_Characters
with positions 32, 10, and 13), may be inserted to improve readability of the generated image.
Add after H.4(23):
Dynamic Semantics
The following restriction_parameter_identifier is language defined:
Max_Image_Length
Specifies the maximum length for a Wide_Wide_Image attribute result. AARM note: Image and Wide_Image are defined in terms of Wide_Wide_Image, so this restriction also applies to evaluations of those attributes. Violation of this restriction results in the raising of Program_Error at the point of the invocation of an image attribute.
Add after H.4(23.8/2):
If a Max_Image_Length restriction applies to any compilation unit in the partition, then for any subtype S, S'Wide_Wide_Image shall be implemented within that partition without any dynamic allocation.
!discussion
The expected (although not required) implementation of the package Ada.Streams.Counted_Streams.Unbounded involves dynamic storage allocation of some kind, perhaps accompanied with uses of controlled types.
For some applications with high integrity/reliability requirements, those requirements (more specifically, requirements about predictable memory utilization) might preclude use of this package.
Nonetheless, we would like such applications to be able to use T'Image for a non-scalar type T without having to override the default implementation of T'Put_Image.
That is the motivation for introducing the Max_Image_Length restriction. The desired goal can be achieved by specifying a Max_Image_Length restriction.
The cost is that the burden is on the user to choose a "good" value for the restriction. If the value is too small, then a call to T'Put_Image may violate the restriction (at runtime); if the value is too big, then the storage requirements of a call to T'Put_Image may be unnecessarily large.
----
Put_Image is user-specifiable; Wide_Wide_Image is not.
One could imagine instead allowing user-specified Wide_Wide_Image attributes and not bothering to define User_Put_Image at all.
The drawback of this approach is that it would could introduce, at least for some compilers, lots of copying.
Given
type T is record F1, F2, F3 : Integer; end record;
the default implementation of T'Wide_Wide_Image could have been defined to be something like
return "(F1 => " &
Arg.F1'Wide_Wide_Image & ", F2 => " & Arg.F2'Wide_Wide_Image & ", F3 => & Arg.F3'Wide_Wide_Image & ")";
but that's a lot of concatenation; the situation for arrays would be even worse.
Furthermore, the two Ada.Streams.FIFO_Streams packages (Bounded and Unbounded) seem like they will be useful in their own right (now defined in AI12-0293-1).
----
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-1.
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_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 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_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>.C2'Put (Stream) Wide_Wide_String'Write (", C3 => ", Stream); <arg>.C3'Put (Stream) Wide_Wide_String'Write (")", Stream); end Put_Image;
A variant part introduces a corresponding case statement.
The default implementation of Put for a one-dimensional array type is equivalent to
procedure Put (<arg> : Array_Type; Stream : access Counted_Stream'Class) is begin Wide_Wide_String'Write ("(", Stream); if <arg>'Length = 0 then <arg>'First'Put (Stream); Wide_Wide_String'Write (" .. ", Stream); <arg>'Last'Put (Stream); Wide_Wide_String'Write (" => <>", Stream); else for Idx in <arg>'range loop Idx'Put (Stream); Wide_Wide_String'Write (" => ", Stream); <arg>(Idx)'Put (Stream); if Idx /= <arg>'Last then Wide_Wide_String'Write (", ", Stream); end if; end if; end loop; Wide_Wide_String'Write (")", Stream); end;
Other types are handled similarly; just calls to Wide_Wide_String'Write mixed 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.
=====
The following is intended as a reference implementation of S'Wide_Wide_Image, assuming the definition of Ada.Streams.FIFO_Streams and related units as described in AI12-0293-1.
function T'Wide_Wide_Image (Arg : T) return Wide_Wide_String is
Local_Stream : aliased Ada.Streams.FIFO_Streams.Unbounded.Stream_Type; -- 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 one or more Max_Image_Length restrictions applies to any compilation unit included in the partition, then the variable Local_Stream is instead declared as
Local_Stream : aliased Ada.Streams.FIFO_Streams.Bounded.Stream_Type (Max_Elements => <the smallest specified Max_Image_Length restriction value>
* Elements_Per_Char); -- see 13.13.1
In this case, exceeding the Max_Elements buffer capacity is a bounded error. Constraint_Error or Program_Error may be propagated, or an implementation defined result may be returned.
!corrigendum 3.5(27.1/2)
Delete the paragraph:
S'Wide_Wide_Image
S'Wide_Wide_Image denotes a function with the following specification:
!corrigendum 3.5(27.2/2)
Delete the paragraph:
function S'Wide_Wide_Image(Arg : S'Base) return Wide_Wide_String
!corrigendum 3.5(27.3/2)
Delete the paragraph:
The function returns an image of the value of Arg, that is, a sequence of characters representing the value in display form. The lower bound of the result is one.
!corrigendum 3.5(27.4/2)
Delete the paragraph:
The image of an integer value 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.
!corrigendum 3.5(27.5/2)
Delete the paragraph:
The image of an enumeration value 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 result 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).
!corrigendum 3.5(27.6/2)
Delete the paragraph:
The image of a floating point value 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.
!corrigendum 3.5(27.7/2)
Delete the paragraph:
The image of a fixed point value 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.
!corrigendum 3.5(28)
Delete the paragraph:
S'Wide_Image
S'Wide_Image denotes a function with the following specification:
!corrigendum 3.5(29)
Delete the paragraph:
function S'Wide_Image(Arg : S'Base) return Wide_String
!corrigendum 3.5(30/3)
Delete the paragraph:
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).
!corrigendum 3.5(35)
Delete the paragraph:
S'Image
S'Image denotes a function with the following specification:
!corrigendum 3.5(36)
Delete the paragraph:
function S'Image(Arg : S'Base) return String
!corrigendum 3.5(37/3)
Delete the paragraph:
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).
!corrigendum 3.5(37.1/2)
Replace the paragraph:
S'Wide_Wide_Width
S'Wide_Wide_Width denotes the maximum length of a Wide_Wide_String returned by S'Wide_Wide_Image over all values of the subtype S. It denotes zero for a subtype that has a null range. Its type is universal_integer.
by:
S'Wide_Wide_Width
S'Wide_Wide_Width denotes the maximum length of a Wide_Wide_String returned by S'Wide_Wide_Image over all values of the subtype S, assuming a default implementation of S'Put_Image. It denotes zero for a subtype that has a null range. Its type is universal_integer.
!corrigendum 3.5(38)
Replace the paragraph:
S'Wide_Width
S'Wide_Width denotes the maximum length of a Wide_String returned by S'Wide_Image over all values of the subtype S. It denotes zero for a subtype that has a null range. Its type is universal_integer.
by:
S'Wide_Width
S'Wide_Width denotes the maximum length of a Wide_String returned by S'Wide_Image over all values of the subtype S, assuming a default implementation of S'Put_Image. It denotes zero for a subtype that has a null range. Its type is universal_integer.
!corrigendum 3.5(39)
Replace the paragraph:
S'Width
S'Width denotes the maximum length of a String returned by S'Image over all values of the subtype S. It denotes zero for a subtype that has a null range. Its type is universal_integer.
by:
S'Width
S'Width denotes the maximum length of a String returned by S'Image over all values of the subtype S, assuming a default implementation of S'Put_Image. It denotes zero for a subtype that has a null range. Its type is universal_integer.
!corrigendum 3.5(43/3)
Replace the paragraph:
For the evaluation of a call on S'Wide_Value for an enumeration subtype S, if the sequence of characters of the parameter (ignoring leading and trailing spaces) has the syntax of an enumeration literal and if it corresponds to a literal of the type of S (or corresponds to the result of S'Wide_Image for a value of the type), the result is the corresponding enumeration value; otherwise, Constraint_Error is raised. For a numeric subtype S, the evaluation of a call on S'Wide_Value with Arg of type Wide_String is equivalent to a call on S'Wide_Wide_Value for a corresponding Arg of type Wide_Wide_String.
by:
For the evaluation of a call on S'Wide_Value for an enumeration subtype S, if the sequence of characters of the parameter (ignoring leading and trailing spaces) has the syntax of an enumeration literal and if it corresponds to a literal of the type of S (or corresponds to the result of S'Wide_Image for a value of the type, assuming a default implementation of S'Put_Image), the result is the corresponding enumeration value; otherwise, Constraint_Error is raised. For a numeric subtype S, the evaluation of a call on S'Wide_Value with Arg of type Wide_String is equivalent to a call on S'Wide_Wide_Value for a corresponding Arg of type Wide_Wide_String.
!corrigendum 3.5(55/3)
Replace the paragraph:
For the evaluation of a call on S'Value for an enumeration subtype S, if the sequence of characters of the parameter (ignoring leading and trailing spaces) has the syntax of an enumeration literal and if it corresponds to a literal of the type of S (or corresponds to the result of S'Image for a value of the type), the result is the corresponding enumeration value; otherwise, Constraint_Error is raised. For a numeric subtype S, the evaluation of a call on S'Value with Arg of type String is equivalent to a call on S'Wide_Wide_Value for a corresponding Arg of type Wide_Wide_String.
by:
For the evaluation of a call on S'Value for an enumeration subtype S, if the sequence of characters of the parameter (ignoring leading and trailing spaces) has the syntax of an enumeration literal and if it corresponds to a literal of the type of S (or corresponds to the result of S'Image for a value of the type, assuming a default implementation of S'Put_Image), the result is the corresponding enumeration value; otherwise, Constraint_Error is raised. For a numeric subtype S, the evaluation of a call on S'Value with Arg of type String is equivalent to a call on S'Wide_Wide_Value for a corresponding Arg of type Wide_Wide_String.
!corrigendum 3.5(55.1/4)
Delete the paragraph:
For a prefix X that denotes an object of a scalar type (after any implicit dereference), the following attributes are defined:
!corrigendum 3.5(55.2/4)
Delete the paragraph:
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.
!corrigendum 3.5(55.3/4)
Delete the paragraph:
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.
!corrigendum 3.5(55.4/4)
Delete the paragraph:
X'Image
X'Image denotes the result of calling function S'Image with Arg being X, where S is the nominal subtype of X.
!corrigendum 3.5(59)
Replace the paragraph:
29 For any value V (including any nongraphic character) of an enumeration subtype S, S'Value(S'Image(V)) equals V, as do S'Wide_Value(S'Wide_Image(V)) and S'Wide_Wide_Value(S'Wide_Wide_Image(V)). None of these expressions ever raise Constraint_Error.
by:
29 For any value V (including any nongraphic character) of an enumeration subtype S without a specified Put_Image (see 4.10), S'Value(S'Image(V)) equals V, as do S'Wide_Value(S'Wide_Image(V)) and S'Wide_Wide_Value(S'Wide_Wide_Image(V)). None of these expressions ever raise Constraint_Error.
!corrigendum 4.10(0)
Insert new clause:
Static Semantics
For every subtype S of a non-universal type T, the following type-related operational attribute is defined:
S'Put_Image
S'Put_Image denotes a procedure with the following specification:
procedure S'Put_Image (Arg : in T; Stream : not null access Ada.Streams.Root_Stream_Type'Class);
The default implementation of S'Put_Image writes (using Wide_Wide_String'Write) an image of the value of Arg; that is, a Wide_Wide_String representing the value in display form.
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.
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 Scalar_Type'Put_Image (Arg : Scalar_Type; Stream : access Ada.Streams.Root_Stream_Type'Class) is begin Wide_Wide_String'Write (<described below>, Stream); end Scalar_Type'Put_Image;
where the Wide_Wide_String value written out to the stream is defined as follows:
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 left parenthesis followed by "ACCESS", a space, and a sequence of graphic characters, other than space or right parenthesis, representing the location of the designated object, followed by a right parenthesis, as in "(ACCESS FF0012AC)".
For an array type T, the default implementation of T'Put_Image generates an image based on (named, not positional) array aggregate syntax (with '[' and ']' as the delimiters) using calls to the Put_Image procedures of the index type(s) and the element type to generate images for values of those types.
The case of a null array is handled specially, using ranges for index bounds and "<>" as a syntactic component-value placeholder.
The order in which components are written for a composite type is the same canonical order in which 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. Then S'Put_Image is called, where S is the specific type identified by Arg'Tag.
For a type extension, the default implementation of T'Put_Image depends on whether there exists a noninterface 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_Image aspect has been specified.
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 (except that for a protected type, the initial left parenthesis is followed by "PROTECTED with "). 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.
The image written out for a record having no components (including any interface type) is "(NULL RECORD)". The image written out for a componentless protected type is "(PROTECTED NULL RECORD)". In the case of a protected type T, a call to the default implementation of T'Put_Image begins only one protected (read-only) action.
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 Task_Identification.Image with the id of the given task and then passing that String to Characters.Conversions.To_Wide_Wide_String.
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 every subtype S of a type T, the following attributes are defined:
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
S'Wide_Wide_Image calls S'Put_Image passing Arg (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 via Wide_Wide_String'Read. The lower bound of the result is 1.
S'Wide_Image
S'Wide_Image denotes a function with the following specification:
function S'Wide_Image(Arg : S'Base) return Wide_String
The function returns a Wide_String corresponding to the result of a call on S'Wide_Wide_Image with a parameter of Arg. The lower bound of the result is one. The result has the same sequence of graphic characters as that returned by 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 a String corresponding to the result of a call on S'Wide_Wide_Image with a parameter of Arg. The lower bound of the result is one. The result has the same sequence of graphic characters as that returned by 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).
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.
Implementation Permissions
An implementation may transform the image generated by the default implementation of S'Put_Image for a composite subtype S in the following ways:
!corrigendum H.4(23)
Insert after the paragraph:
No_Reentrancy
During the execution of a subprogram by a task, no other task invokes the same subprogram.
the new paragraphs:
Dynamic Semantics
The following restriction_parameter_identifier is language defined:
Max_Image_Length
Specifies the maximum length for a Wide_Wide_Image attribute result. Violation of this restriction results in the raising of Program_Error at the point of the invocation of an image attribute.
!corrigendum H.4(23.8/2)
Insert after the paragraph:
the new paragraph:
If a Max_Image_Length restriction applies to any compilation unit in the partition, then for any subtype S, S'Wide_Wide_Image shall be implemented within that partition without any dynamic allocation.
!ACATS test
** TBD.
!appendix

From: Gregory D Moncreaff
Sent: Thursday, October 13, 2011  6:59 PM

Having worked with other language technologies, specifically C# and Java,

I was wondering if any consideration was being given to the idea of providing
some form of default rendering of record types via an attribute?

Typically one would expect it to report all components (recursively) of record
using the type primitive existing image attributes.

Access types would not be traversed to avoid recursion. Only the valid
components of a discriminated record would be reported.

Ideal format would be of something that could itself be used as a record
assignment by components.

Optionally providing the ability of overriding this attribute would be nice, but
not necessary.

Special care would need to be taken if String's had special ASCII characters
within them by concatenating the quotable portions of the string with the
specials.

Does this seem reasonable?

****************************************************************

From: Randy Brukardt
Sent: Thursday, October 13, 2011  9:16 PM

...
>I was wondering if any consideration was being given to the idea of
>providing some form of default rendering of record types via an
>attribute?

Yes, of course. We've considered a number of additional forms of 'Image and
'Value. We never got any consensus on whether they are important enough.

>Typically one would expect it to report all components (recursively) of
>record using the type primitive existing image attributes.

In what format?? (Aggregates, presumably.) Why only records, why not arrays?

>Access types would not be traversed to avoid recursion. Only the valid
>components of a discriminated record would be reported.

What gets output for a non-null access type parameter. Whatever it is, it
wouldn't mean the same thing in an aggregate, which is bad.

>Ideal format would be of something that could itself be used as a
>record assignment by components.

What is this? An aggregate I can imagine, I don't even know what "record
assignment by components" means (I imagine a series of assignment statements
when I read that, but I can't imagine how you could use that as an 'Image).

>Optionally providing the ability of overriding this attribute would be
>nice, but not necessary.

We've discussed this idea in the past, too. We also considered *only* providing
this (see below for why).

>Special care would need to be taken if String's had special ASCII
>characters within them by concatenating the quotable portions of the
>string with the specials.

A String is just an array in Ada, there is nothing special about it. And what
about components that are other arrays (arrays of integer, arrays of float,
arrays of record)? Task components? Protected type components?

>Does this seem reasonable?

Not particularly, for some of the reasons given above. As a built-in attribute,
the compiler would have to generate it for all types (whether it is used or not,
since it can't know whether some other package will use it). And given the
recursive definition you are giving, it would become very, very large for a lot
of types (even stopping on access types). Imagine a record containing a matrix
component, for one example.

For a compiler (like Janus/Ada) that is designed to make small size code, this
would be a problem. (At least it would not have any runtime impact unless used.)

I do think there might be something worth doing for 'Image (I don't think we
rejected it for technical reasons as much as importance). But an automatically
recursing 'Image isn't it, IMHO.

****************************************************************

From: Simon Wright
Sent: Friday, October 14, 2011  2:23 AM

> I was wondering if any consideration was being given to the idea of providing
> some form of default rendering of record types via an attribute?

Gregory might find the ASIS-based  Auto_Text_IO useful -
http://www.sigada.org/WG/asiswg/ASIS_Clients.html#Leake

****************************************************************

From: Steve Baird
Sent: Thursday, January 25, 2018  7:24 PM

I'd like to get a consensus on intent before attempting wording.

For statements in the list below, I'd like confirmation.
For questions, I'd like answers.

1) Image is to be defined for all types (including
    limited types) and can be overridden in pretty much
    the same way that streaming attributes can be
    overridden (but see #8 below). Unlike streaming attributes,
    there are no availability issues - 'Image is always available.

2) For scalar types, behavior is unchanged (except in the
    user-defined case).
    In all (non-user-defined) cases, you get
    no line-breaking or any sort of formatting.
    [We are avoiding pretty-printer wars as much as possible.]

3) For task and access types, the string is implementation
    dependent. For example, the image for any value of such
    a type might be "<>". Or it might be something more useful.
    As mentioned earlier, users can override.

3) For untagged records, we use named-notation aggregate syntax
    (order of fields follows positional aggregate rules)

      type T is record Xx, Yy, Zz : Some_Type; end record;
      Obj : T := ... ;

      pragma Assert (Obj'Image =
        "(Xx => " & Obj.Xx'Image
        & ", Yy => " & Obj.Yy'Image
        & ", Zz => " & Obj.Zz'Image
        & ")"

    Ditto for specific tagged records; in particular, the
    tag value is not mentioned at all in that case. Nothing
    special for protected records.

    In the no-components case, image is "(null record)".

4) What do we do for class-wide? It seems like we need to
    mention the tag or the name of the specific type or
    something like that. Perhaps using qualified expression
    syntax, with Ada.Tags.External_Name (Obj'Tag) as the
    qualifier? Record aggregate syntax is used (as opposed to
    extension aggregate syntax). [It is ok if this displays
    two components with the same name; ordering resolves
    the ambiguity in this corner case.]

    There is also the issue of distributed overhead, similar
    to the case of a user who declares a tagged type and never
    uses its streaming operations; can we ignore this concern?

5) What about arrays? It would be very verbose to use
    named notation syntax, as in

      "(1 => 123, 2 => 456, 3 => 789, ..., 9999 => 0)"

    but we have to get the bounds in there somehow.
    Perhaps display it sort of like a record, as in

      "(First(1) => 1, Last(1) => 3, First(2) => 1, Last(2) => 2, "
      & "((1, 2), (3, 4), (5, 6)))"

    Do we want to do anything different in the case where the
    first named subtype is constrained? One might argue
    that there is no need to display bounds in that case.
    But then what happens with an aggregate or a slice which
    doesn't have the bounds of the first named subtype?

    There is also a question about null arrays, both
    single- and multi-dimensional. Perhaps these might
    be displayed as

      "(First => 1, Last => 0, ())"

      "(First(1) => 1, Last(1) => 3, First(2) => 1, Last(2) => 0,"
      & " ((), (), ())"

      "(First(1) => 1, Last(1) => 0, First(2) => 1, Last(2) => 3,"
      & " ()"


    Do we want to do anything special for the image of
    a string type and use some variant of string-literal
    syntax? Probably, although string-type is the wrong
    thing to test for because that would allow something
    like
       type Element is ('A', 'B', None_Of_The_Above);
       type I_Am_A_String_Type is array (1 .. 10) of Element;
    and we don't want to use string-literal syntax for some
    values of a given type and not for others.

    A big advantage of using verbose named-notation
    syntax is that it would then be more natural to use range
    notation in the case where consecutive elements have
    the same image (with the usual permissions to avoid
    having to invoke the Image function twice if arguments
    are known to be equal).

    So we might see
       "(1 => 123, 2 .. 999 => 0, 1000 => 456)"

    Named-notation syntax is probably the way to go, even though
    (as noted earlier) it can lead to a lot of redundant text in
    some cases. If we do that, then we'd need consistent syntax
    for the null array case (single- and multi-dimensional).

6) Some images begin with leading blanks and some don't (that's
    already true, so we have to deal with both cases). Do we want
    to take any steps to avoid ugly double-blanks? For example,
    would the image of a record with two integers look like
      "(X => 123, Y => 456)"
    or like
      "(X =>  123, Y =>  456)" -- note the two additional spaces
    ? See the Assert pragma in item #3 above.

7) What about compatibility issues?

    Given a bunch of overloaded parameterless functions named
    Foo, could there be a situation where we currently accept
      Foo'Image
    but it would become ambiguous with the new rules?
    I think the answer is no, and there is no problem here.
    Nonetheless, it seems worth mentioning.

8) The same relationship between 'Image, 'Wide_Image, and
     'Wide_Wide_Image holds for any type as holds today. Only
     'Wide_Wide_Image is user-specifiable and the others
     follow suit as usual. If a mention of "user-specified
     Image attribute" or somesuch in this discussion appears
     to violate this rule, that is a case of preferring
     clarity over precision - to repeat: Image cannot be
     specified, Wide_Wide_Image can be specified, and
     specifying Wide_Wide_Image changes the behavior of
     Wide_Image and Image.

9) Inheritance of user-specified Image attributes follows
    the same rules as for streaming attributes.

10) Evaluation of an Image attribute never yields a
     static string if the attribute is user-defined.
     For a scalar type, at least, this means that we
     probably want to prohibit

       package Pkg is
          type T is range 1 .. 10;
       private
          function WWI (X : T) return Wide_Wide_String;
          for T'Wide_Wide_Image use WWI;
       end Pkg;

     because clients outside would have to look into the
     private part to see that T'Image(5) is not a static string.

****************************************************************

From: Randy Brukardt
Sent: Thursday, January 25, 2018  8:02 PM

...
> 3) For task and access types, the string is implementation
>     dependent. For example, the image for any value of such
>     a type might be "<>". Or it might be something more useful.
>     As mentioned earlier, users can override.

You have two #3s here. :-)

For a task, one could imagine using the task id somehow. (At least, that was my
first thought.) Not completely useful (especially for 'Value), but it would
clearly allow telling tasks apart and would be useful for debugging.

For access values, one could mandate using the image of the associated
Integer_Address in, say square brackets. (That would be familiar to anyone used
to an Intel assembler.)

One of the main purposes of the predefined version is debugging, and allowing
the image to be nothing is not useful for debugging. So perhaps it is better to
specify something, even if that something isn't enough to use in 'Value.

> 3) For untagged records, we use named-notation aggregate syntax
>     (order of fields follows positional aggregate rules)
>
>       type T is record Xx, Yy, Zz : Some_Type; end record;
>       Obj : T := ... ;
>
>       pragma Assert (Obj'Image =
>         "(Xx => " & Obj.Xx'Image
>         & ", Yy => " & Obj.Yy'Image
>         & ", Zz => " & Obj.Zz'Image
>         & ")"
>
>     Ditto for specific tagged records; in particular, the
>     tag value is not mentioned at all in that case. Nothing
>     special for protected records.
>
>     In the no-components case, image is "(null record)".

One needs to specify the case of the component names in this aggregate. I'd
expect the assertion to fail, because those names will probably be all UPPER
CASE or all lower case -- but never mixed case. (Most likely, copy the
enumeration rule.)

For the purposes of 'Value, some types would have to be disallowed as there may
not be unique UPPER CASE versions of the ids. But leave that worry to the author
of 'Value.

> 4) What do we do for class-wide? It seems like we need to
>     mention the tag or the name of the specific type or
>     something like that. Perhaps using qualified expression
>     syntax, with Ada.Tags.External_Name (Obj'Tag) as the
>     qualifier? Record aggregate syntax is used (as opposed to
>     extension aggregate syntax). [It is ok if this displays
>     two components with the same name; ordering resolves
>     the ambiguity in this corner case.]

The qualified expression syntax seems fine. One would want to be able to have a
'Value for it, at least if the components are all distinct. (That obviously
doesn't matter for 'Image).

>     There is also the issue of distributed overhead, similar
>     to the case of a user who declares a tagged type and never
>     uses its streaming operations; can we ignore this concern?

Yes. All good compilers ... sorry Tuck. Janus/Ada removes unused subprograms at
link-time, even if they occur in tags. (Yes, there is a way to write a shared
generic such that we have to turn off this optimization, but I've never seen
such a generic written by anyone -- including me -- to date.) So this is
possible, and this "dead code" overhead can be made zero if it is an actual
concern. This can be a real problem for tagged types (we implemented this to
make the "hello world" CLAW program more reasonably sized; I believe it changes
a 1.5M executable into a 0.5M executable, so this isn't trivial).

> 5) What about arrays? It would be very verbose to use
>     named notation syntax, as in
>
>       "(1 => 123, 2 => 456, 3 => 789, ..., 9999 => 0)"
>
>     but we have to get the bounds in there somehow.
>     Perhaps display it sort of like a record, as in
>
>       "(First(1) => 1, Last(1) => 3, First(2) => 1, Last(2) => 2, "
>       & "((1, 2), (3, 4), (5, 6)))"
>
>     Do we want to do anything different in the case where the
>     first named subtype is constrained? One might argue
>     that there is no need to display bounds in that case.
>     But then what happens with an aggregate or a slice which
>     doesn't have the bounds of the first named subtype?
>
>     There is also a question about null arrays, both
>     single- and multi-dimensional. Perhaps these might
>     be displayed as
>
>       "(First => 1, Last => 0, ())"
>
>       "(First(1) => 1, Last(1) => 3, First(2) => 1, Last(2) => 0,"
>       & " ((), (), ())"
>
>       "(First(1) => 1, Last(1) => 0, First(2) => 1, Last(2) => 3,"
>       & " ()"
>
>
>     Do we want to do anything special for the image of
>     a string type and use some variant of string-literal
>     syntax? Probably, although string-type is the wrong
>     thing to test for because that would allow something
>     like
>        type Element is ('A', 'B', None_Of_The_Above);
>        type I_Am_A_String_Type is array (1 .. 10) of Element;
>     and we don't want to use string-literal syntax for some
>     values of a given type and not for others.
>
>     A big advantage of using verbose named-notation
>     syntax is that it would then be more natural to use range
>     notation in the case where consecutive elements have
>     the same image (with the usual permissions to avoid
>     having to invoke the Image function twice if arguments
>     are known to be equal).
>
>     So we might see
>        "(1 => 123, 2 .. 999 => 0, 1000 => 456)"
>
>     Named-notation syntax is probably the way to go, even though
>     (as noted earlier) it can lead to a lot of redundant text in
>     some cases. If we do that, then we'd need consistent syntax
>     for the null array case (single- and multi-dimensional).

You seem to have answered your own question here. And I tend to agree. 'Image of
large data structures is never going to be very useful (what do you do with 20
pages of output), so it probably makes sense to just use the syntax that
provides the most information and least chance of getting it wrong.

> 6) Some images begin with leading blanks and some don't (that's
>     already true, so we have to deal with both cases). Do we want
>     to take any steps to avoid ugly double-blanks? For example,
>     would the image of a record with two integers look like
>       "(X => 123, Y => 456)"
>     or like
>       "(X =>  123, Y =>  456)" -- note the two additional spaces
>     ? See the Assert pragma in item #3 above.

Not sure here. It would be a pain to try to eliminate the leading blanks for
numeric 'Image, so I probably would say leave the extra blanks. (Or maybe, skip
putting a blank after "=>", as it will still be syntactically correct either
way.) One can always user-define it if you need it perfect.

> 7) What about compatibility issues?
>
>     Given a bunch of overloaded parameterless functions named
>     Foo, could there be a situation where we currently accept
>       Foo'Image
>     but it would become ambiguous with the new rules?
>     I think the answer is no, and there is no problem here.
>     Nonetheless, it seems worth mentioning.

Attribute prefixes have to resolved sans context (with the exception of 'Access
and any others with special rules). So it would have to be ambiguous now if Foo
is overloaded with no parameters.

...
> 10) Evaluation of an Image attribute never yields a
>      static string if the attribute is user-defined.
>      For a scalar type, at least, this means that we
>      probably want to prohibit
>
>        package Pkg is
>           type T is range 1 .. 10;
>        private
>           function WWI (X : T) return Wide_Wide_String;
>           for T'Wide_Wide_Image use WWI;
>        end Pkg;
>
>      because clients outside would have to look into the
>      private part to see that T'Image(5) is not a static string.

Luckily, string attributes are never static -- see 4.9(7) -- and we didn't
change that in part because we knew this AI was coming -- so this is a lot of
worry about nothing.

****************************************************************

From: Raphaël Amiard
Sent: Friday, January 25, 2018  8:23 AM

I agree wholeheartedly with this proposal, and Randy's suggestions, FWIW.

>...
>
>3) For task and access types, the string is implementation
>    dependent. For example, the image for any value of such
>    a type might be "<>". Or it might be something more useful.
>    As mentioned earlier, users can override.

I wonder: In my opinion we want to make a lot of that implementation dependent
(I mean it's good if there are some guide lines, but that's it).

I don't think we want users to start relying on the output of 'Image as some
kind of interchange format, so we should be clear on that in any way.

I'm also wondering, and I know we discussed it live but I don't see any
mention of that in your mail Steve: What about 'Value ? I think we said that
'Value won't be implemented for complex types, but it would be better to state
it clearly I guess.

If we don't implement 'Value, I would lean forward making most of the rules
you mention implementation dependent (for example the one about named
parameters in arrays), with the ARM just giving advice/guidelines/how do we call
that again

****************************************************************

From: Steve Baird
Sent: Friday, January 25, 2018  11:49 AM

> ...
>> 3) For task and access types, the string is implementation
>>      dependent. For example, the image for any value of such
>>      a type might be "<>". Or it might be something more useful.
>>      As mentioned earlier, users can override.
>
> You have two #3s here. :-)
>
> For a task, one could imagine using the task id somehow. (At least,
> that was my first thought.) Not completely useful (especially for
> 'Value), but it would clearly allow telling tasks apart and would be useful
> for debugging.

I agree, Task_Identification.Image of the task id is what we want for tasks.

Note that no changes involving 'Value are proposed in this AI.
As Raphael points out, it would probably be good to mention this explicitly
(i.e., to talk about what we are not talking about).

I've omitted in this reply all of your subsequent 'Value-related comments.

> For access values, one could mandate using the image of the associated
> Integer_Address in, say square brackets. (That would be familiar to
> anyone used to an Intel assembler.)

Fair enough, although if we are going to require something then I'd rather see
the address displayed in hex.

>> 3) For untagged records, we use named-notation aggregate syntax
>>      (order of fields follows positional aggregate rules)
>>
>>        type T is record Xx, Yy, Zz : Some_Type; end record;
>>        Obj : T := ... ;
>>
>>        pragma Assert (Obj'Image =
>>          "(Xx => " & Obj.Xx'Image
>>          & ", Yy => " & Obj.Yy'Image
>>          & ", Zz => " & Obj.Zz'Image
>>          & ")"
>>
>>      Ditto for specific tagged records; in particular, the
>>      tag value is not mentioned at all in that case. Nothing
>>      special for protected records.
>>
>>      In the no-components case, image is "(null record)".
>
> One needs to specify the case of the component names in this
> aggregate. I'd expect the assertion to fail, because those names will
> probably be all UPPER CASE or all lower case -- but never mixed case.
> (Most likely, copy the enumeration rule.)

Good point.

I agree - upper case. We certainly don't want the case that was used in the
declaration(s) of the type to have any effect on the runtime behavior of a
program.

>> 5) What about arrays? It would be very verbose to use
...
>>      Named-notation syntax is probably the way to go, even though
>>      (as noted earlier) it can lead to a lot of redundant text in
>>      some cases. If we do that, then we'd need consistent syntax
>>      for the null array case (single- and multi-dimensional).
>
> You seem to have answered your own question here. And I tend to agree.
> 'Image of large data structures is never going to be very useful (what
> do you do with 20 pages of output), so it probably makes sense to just
> use the syntax that provides the most information and least chance of
> getting it wrong.

It's worth noting that when we display an index value, we of course use the
Image attribute of the index type.

>> 6) Some images begin with leading blanks and some don't (that's
>>      already true, so we have to deal with both cases). Do we want
>>      to take any steps to avoid ugly double-blanks? For example,
>>      would the image of a record with two integers look like
>>        "(X => 123, Y => 456)"
>>      or like
>>        "(X =>  123, Y =>  456)" -- note the two additional spaces
>>      ? See the Assert pragma in item #3 above.
>
> Not sure here. It would be a pain to try to eliminate the leading
> blanks for numeric 'Image, so I probably would say leave the extra
> blanks. (Or maybe, skip putting a blank after "=>", as it will still
> be syntactically correct either way.) One can always user-define it if you
> need it perfect.

Changing the behavior of numeric 'Image would be grossly incompatible; that
seems out of the question to me.

I was thinking more about looking for a leading space on a component image and
conditionally preceding it with either a "=> " or a "=>" when generating the
image of an enclosing composite object.

===

I was thinking some more about the Image/Wide_Image/Wide_Wide_Image rules.

90% of the time, all that anyone is interested in is the Image attribute and
it is somewhat clunky to have to specify the Wide_Wide_Image aspect (or even
mention Wide_Wide_String at all).

But we want to retain consistency between the 3 image attributes; we don't
want, for example, to allow users to explicitly specify Image and Wide_Image
aspects for one type.

I originally proposed one solution: only Wide_Wide_Image is specifiable.

How about, instead, allowing any *one* of the three aspects Image, Wide_Image,
Wide_Wide_Image to be specified? Whatever aspect is specified determines the
behavior of all three attributes. [Alternatively, we could say that only Image
is specifiable but the specified value can be a function returning any of the
three predefined string types; there are advantages to this approach - we don't
have to worry about defining what happens in a case like
      type T1 is ... with Wide_Image => ... ;
      type T2 is new T1 with Image => ... ; ].

****************************************************************

From: Steve Baird
Sent: Friday, January 25, 2018  2:11 PM

More thoughts on this.

> It's worth noting that when we display an index value, we of course
> use the Image attribute of the index type.

"the Image attribute" => "the appropriate image attribute".

If we are in the middle of generating, say, a Wide_Wide_String as part of
evaluating Some_Array'Wide_Wide_Image, then we want to use
Index_Type'Wide_Wide_Image (as opposed to Index_Type'Image).

> I agree, Task_Identification.Image of the task id is what we want for
> tasks.

Discriminated task types should display the discriminant values somehow.
Perhaps extension-aggregate-ish syntax? Something like

    (task <task id image> with D1 => This, D2 => that)

and then, for consistency, undiscriminated image is

    (task <task id image>) .

Or perhaps we drop the word "task", but then the parens look odd in the
undiscriminated task case. Do we drop them?

>  Nothing special for protected records.

Presumably Some_Protected_Object'Image behaves like a call to a protected
function with respect to locking.

>    Named-notation syntax is probably the way to go...
>    If we do that, then we'd need consistent syntax
>    for the null array case (single- and multi-dimensional).

If we define syntax for null array aggregates, then we should use whatever is
agreed upon. Otherwise, how about

     "(1 .. 0 => <>)"

     "(1 .. 3 => (1 .. 0 => <>))"

     "(1 .. 0 => (1 .. 3 => <>))"
? Or perhaps "()" instead of "<>".

====

It needs to be explicitly stated that
    Some_Object'Image
is defined when the object is of a non-numeric type.

****************************************************************

From: Randy Brukardt
Sent: Friday, January 25, 2018  2:56 PM

> I'm also wondering, and I know we discussed it live but I don't see any
> mention of that in your mail Steve: What about 'Value ? I think we said that
>'Value won't >be implemented for complex types, but it would be better to
> state it clearly I guess.

We decided only to consider 'Value separately. (And assigned that AI to
Tucker.) We didn't decide yes or no on that.

> If we don't implement 'Value, I would lean forward making most of the rules
> you mention implementation dependent (for example the one about named
> parameters in arrays), with the ARM just giving advice/guidelines/how do we
> call that again

That's undecided at this time. But my preference would be to leave the
possibility open for the future, even if we decide not to do it this time.
Therefore, I would prefer to lock down the formats for as much as possible.
If we made them implementation-dependent, then we could never implement 'Value
(nor could a user write their own portable 'Value).

****************************************************************

From: Randy Brukardt
Sent: Friday, January 25, 2018  3:06 PM

...
> Note that no changes involving 'Value are proposed in this AI.
> As Raphael points out, it would probably be good to mention this
> explicitly (i.e., to talk about what we are not talking about).
>
> I've omitted in this reply all of your subsequent 'Value-related
> comments.

My point of mentioning 'Value in my comments is that I want the possibility
of implementing that preserved as much as possible. So, if there is a syntax
that would work for 'Value, and one that would not work for 'Value, I strongly
lean toward the one that would allow 'Value. Note that "allowing 'Value" is
the same as "allowing users to write a portable 'Value-like subprogram". I
agree that whether or not we support 'Value this time (or ever) is not
relevant to this AI.

I think that is fair game to talk about whether or not the suggested format
could support 'Value (or similar user-written routines).

> > For access values, one could mandate using the image of the
> > associated Integer_Address in, say square brackets. (That would be
> > familiar to anyone used to an Intel assembler.)
>
> Fair enough, although if we are going to require something then I'd
> rather see the address displayed in hex.

The only issue with that is that we don't have a hex image routine anywhere.
Integer_Address'Image is well-defined.

...
> >> 6) Some images begin with leading blanks and some don't (that's
> >>      already true, so we have to deal with both cases). Do we want
> >>      to take any steps to avoid ugly double-blanks? For example,
> >>      would the image of a record with two integers look like
> >>        "(X => 123, Y => 456)"
> >>      or like
> >>        "(X =>  123, Y =>  456)" -- note the two additional spaces
> >>      ? See the Assert pragma in item #3 above.
> >
> > Not sure here. It would be a pain to try to eliminate the leading
> > blanks for numeric 'Image, so I probably would say leave the extra
> > blanks. (Or maybe, skip putting a blank after "=>", as it will still
> > be syntactically correct either way.) One can always user-define it
> > if you need it perfect.
>
> Changing the behavior of numeric 'Image would be grossly incompatible;
> that seems out of the question to me.

I agree, but I was not suggesting that.

> I was thinking more about looking for a leading space on a component
> image and conditionally preceding it with either a "=> " or a "=>"
> when generating the image of an enclosing composite object.

I think that is too much work, especially as it is value-dependent for
Integer'Image.

My suggestion was simply to always generate "=>" (with no trailing space),
as that is lexically and syntactically correct, and it avoids the double
spacing. Otherwise, just don't worry about that -- this is mainly for
debugging anyway, perfection not required.

> ===
>
> I was thinking some more about the
> Image/Wide_Image/Wide_Wide_Image rules.
>
> 90% of the time, all that anyone is interested in is the Image
> attribute and it is somewhat clunky to have to specify the
> Wide_Wide_Image aspect (or even mention Wide_Wide_String at all).
>
> But we want to retain consistency between the 3 image attributes; we
> don't want, for example, to allow users to explicitly specify Image
> and Wide_Image aspects for one type.
>
> I originally proposed one solution: only Wide_Wide_Image is
> specifiable.
>
> How about, instead, allowing any *one* of the three aspects Image,
> Wide_Image, Wide_Wide_Image to be specified?
> Whatever aspect is specified determines the behavior of all three
> attributes. [Alternatively, we could say that only Image is
> specifiable but the specified value can be a function returning any of
> the three predefined string types; there are advantages to this
> approach - we don't have to worry about defining what happens in a
> case like
>       type T1 is ... with Wide_Image => ... ;
>       type T2 is new T1 with Image => ... ; ].

Whatever the rule is, it can allow specifying only one. In this latter
Bairdian case, I'd expect the second one to totally override all three.
I'll leave the exact rule to you.

****************************************************************

From: Steve Baird
Sent: Friday, January 25, 2018  3:29 PM

> So, if there is a syntax
> that would work for 'Value, and one that would not work for 'Value, I
> strongly lean toward the one that would allow 'Value.

I agree.

>>> For access values, one could mandate using the image of the
>>> associated Integer_Address in, say square brackets. (That would be
>>> familiar to anyone used to an Intel assembler.)
>>>
>>
>> Fair enough, although if we are going to require something then I'd
>> rather see the address displayed in hex.
>
> The only issue with that is that we don't have a hex image routine anywhere.
> Integer_Address'Image is well-defined.

Requiring (as opposed to allowing) something that isn't very useful would be
bad. I'd rather leave it implementation dependent than to require
decimal-format display for addresses. My first choice is requiring hex.

> My suggestion was simply to always generate "=>" (with no trailing
> space), as that is lexically and syntactically correct, and it avoids
> the double spacing. Otherwise, just don't worry about that -- this is
> mainly for debugging anyway, perfection not required.

In a situation where one space would be ideal, I'd rather see two spaces than
none. So I'd rather unconditionally generate "=> " instead of "=>" if those
are the only two choices. Note that there is a similar issue with index values
in array aggregates (and these can appear in at least 3 different contexts -
after a left paren, a comma, or a "..").

> Whatever the rule is, it can allow specifying only one. In this latter
> Bairdian case, I'd expect the second one to totally override all three.

Agreed.

****************************************************************

From: Randy Brukardt
Sent: Friday, January 25, 2018  9:51 PM

...
> >>> For access values, one could mandate using the image of the
> >>> associated Integer_Address in, say square brackets. (That would be
> >>> familiar to anyone used to an Intel assembler.)
> >>>
> >>
> >> Fair enough, although if we are going to require something then I'd
> >> rather see the address displayed in hex.
> >
> > The only issue with that is that we don't have a hex image routine
> > anywhere. Integer_Address'Image is well-defined.
> >
>
> Requiring (as opposed to allowing) something that isn't very useful
> would be bad.

On modern 32-bit machines, neither is very useful. Data point: When Janus/Ada
got ported to 32-bit machines, no 32-bit hex value routine was available and
someone took the lazy way out when programming the symbol table dump. The
decimal numbers, as you say, aren't very useful. No one can memorize a
ten-digit number, so looking for the values by hand is impossible, especially
as they all look similar. And searching is not fun, simply because there is a
lot of chance of error in typing a 10 digit number.

So we changed to hex. And guess what? The effect is the same: looking for
values by hand isn't possible in general, because memorizing an 8 digit number
isn't substantially easier than 10. And typing an 8-digit hex number for
searching is nearly as hard as a 10 digit decimal number (needing to use both
numbers and letters rather than just the number pad).

This gets even worse on modern OSes using address-space randomization, because
the first few hex digits vary more than they used to. And also for 64-bit
machines, where the number of digits is way too many to do anything with when
reading (in either format).

I gave up on both last winter and reprogrammed the routine to show the symbol
record unit/id pair instead. This is usually a pair of 2 digit numbers (in test
programs, anyway, they'd be longer in a full-sized program but luckily one
rarely has to debug those without a smaller reproducer). That's much easier to
look for manually (plus it gives some information about where to look), and
easier to search for with a program (as it's shorter). The downside is that it
requires dereferencing the pointer to be displayed, so a corrupt pointer can
crash the dump -- but a corrupt pointer is a critical bug and the failing dump
shows precisely where to look (wherever the dump stops), so that's hardly an
issue for this use.

Ergo, I'd expect most serious use of access Image to replace it with an
user-defined version. For one-off debugging, what it is hardly matters (so long
as values that are different can be recognized).

Aside: should the image of a null access value be "null" or "[00000000]" (if
hex) or "[ 0]" (if 'Image)??


****************************************************************

From: Jean-Pierre Rosen
Sent: Saturday, January 27, 2018  1:28 AM

> The only issue with that is that we don't have a hex image routine
> anywhere. Integer_Address'Image is well-defined.

If the (hex) image uses based notation, it can be fed back to 'Value

****************************************************************

From: Tucker Taft
Sent: Saturday, January 27, 2018  11:29 AM

> ...
> Discriminated task types should display the discriminant values somehow.
> Perhaps extension-aggregate-ish syntax? Something like
>
>   (task <task id image> with D1 => This, D2 => that)
>
> and then, for consistency, undiscriminated image is
>
>   (task <task id image>) .
>
> Or perhaps we drop the word "task", but then the parens look odd in
> the undiscriminated task case. Do we drop them?

I like the word "task" being there, and always using parentheses for composite
types.

> Nothing special for protected records.

I would think you would have "(protected <id-of-some sort> with disc1 => X,
disc2 => Y, comp1 => Z, ...)" to be consistent with tasks, and to make it
clear that this is not your normal record.

> Presumably Some_Protected_Object'Image behaves like a call to a
> protected function with respect to locking.
>
>>   Named-notation syntax is probably the way to go...
>>   If we do that, then we'd need consistent syntax
>>   for the null array case (single- and multi-dimensional).
>
> If we define syntax for null array aggregates, then we should use
> whatever is agreed upon. Otherwise, how about
>
>    "(1 .. 0 => <>)"
>
>    "(1 .. 3 => (1 .. 0 => <>))"
>
>    "(1 .. 0 => (1 .. 3 => <>))"
> ? Or perhaps "()" instead of "<>".

"<>" seems better than "()" given the general Ada allergy to empty parentheses.

****************************************************************

From: Steve Baird
Sent: Wednesday, February 28, 2018  8:03 PM

I still don't have real RM wording for this one, but here is a more detailed
outline than what we had before for this AI, incorporating feedback from the
last meeting and subsequent discussions with Bob and Tuck. [This is the
!proposal section of version /02 of the AI - Editor.]

First, a summary of what we plan for the default (as opposed to
user-specified) implementations of T'Image for a possibly-nonscalar type T.
Much of this has already been discussed, but there is some new stuff (e.g.,
the treatment of type extensions).

The completely new stuff that has not previously been discussed on the ARG
list is the discussion of the Put attribute in the second part of this
message.

Feedback, as always, is most welcome.

****************************************************************

From: Tucker Taft
Sent: Thursday, March  1, 2018  6:52 AM

I preferred the proposal to include the words "task ..." or "protected ..."
in the 'Image for such types.  You wrote:

   For task types -
      Undiscriminated: "(<task_id_image>)"
      Discriminated: "(D1 => 123, D2 => 456, <task_id_image>)"
   For protected types -
      Nothing special. Same as any record type.
      Protected_Obj'Image is a protected function (this matters, for example,
      for locking).

Earlier I had seen a proposal of approximately:

   (task <task_id_image>) -- no discriminants

   (task <task_id_image> with D1 => 123, D2 => 456)

and for protected types, the analogous thing:

   (protected <protected_id_image>)  -- no discriminants or private components
   (protected <pid> with D1 => ... , C1 => ...) -- discriminants and/or components

I think these have a nice symmetry, and will reduce confusion with other
aggregates.

Clearly protected objects have some kind of identity (typically some sort of
internal semaphore ID), and that is something that would be of interest.  Just
dumping the value of the private components would be losing significant
information.

****************************************************************

From: Randy Brukardt
Sent: Thursday, March  1, 2018  9:37 PM

> Earlier I had seen a proposal of approximately:
>
>    (task <task_id_image>) -- no discriminants
>
>    (task <task_id_image> with D1 => 123, D2 => 456)

I think you made that proposal, so I'm pretty sure you saw it. ;-)

But I agree with this, especially as a task id might just be a small integer
which would make no sense without context.

> and for protected types, the analogous thing:
>
>    (protected <protected_id_image>)  -- no discriminants or private components
>    (protected <pid> with D1 => ... , C1 => ...) -- discriminants and/or components

I agree with the "protected" part, but there is no such thing as a
<protected_id>; protected types are just records with a predefined blob used
by the task supervisor. One could use the address if someone insisted on an
<id>, but this doesn't seem different than any other record type in that in
some cases you might need to display the identity. In that case, you should
dump the address as well as the image. So I don't think there should be any
<protected_id> here.

In the case of tasks, most of them have no other components so the task id is
needed to even get an idea of the type. That's unlikely for protected objects.
If we'd prefer consistency, I'd rather drop the id from the tasks rather than
force a non-existent thing into the protected case.

> I think these have a nice symmetry, and will reduce confusion with
> other aggregates.
>
> Clearly protected objects have some kind of identity (typically some
> sort of internal semaphore ID), and that is something that would be of
> interest.  Just dumping the value of the private components would be
> losing significant information.

I strongly disagree with this: Janus/Ada exposes none of this stuff even to
the rest of the compiler. The compiler just sees a private type of a
particular size. We'd have to define new task supervisor operations
specifically for this purpose if we needed to expose something else -- but
the "something else" doesn't even exist. The address of the protected object
serves to identify it in any case that is needed.

I'd be surprised if other compilers differed on this. These guys -
particularly because they have discriminants - are much more like a record
with some special operations when accessed than a task (which is an active
structure). Perhaps there is some mutex that the underlying OS gives an Id
to, but that has nothing to do with Ada.

The idea of a Task_Id is well-defined in Ada; there's an entire section in
the Standard talking about it. And that defines an Image function. That's
what would appear in 'Image.

Imagining a whole new mechanism (one that is nonexistent in at least some
compilers) just for Image is waaaay over the top.

****************************************************************

From: Tucker Taft
Sent: Thursday, March  1, 2018  10:06 PM

Perhaps we should always just include its address. Clearly two otherwise
identical protected objects are still fundamentally distinct, since they
each have their own specific lock. That is all I was trying to accomplish
with the protected ID.

***************************************************************

From: Randy Brukardt
Sent: Thursday, March  1, 2018  11:24 PM

OK, I guess, but isn't that fundamentally true of any limited type? You've
often made the point that the object identity of a limited object is an
important part of its abstraction. I was just wondering why protected
objects ought to be special in this way.

***************************************************************

From: Tucker Taft
Sent: Friday, March  2, 2018  2:55 AM

I agree this is true of all "immutably limited" types.  But the large majority
of immutably limited types are that because they contain a task or a protected
object, so adding such an identifier to a protected object seemed to solve
most of the problem.  I wouldn't be averse to a more general solution, but I
don't have a proposal for that.

***************************************************************

From: Steve Baird
Sent: Wednesday, March 28, 2018  6:57 PM

Still no wording.

Here are the results of some discussions I've had with Randy and Tuck
since the summary I sent out a month ago. This includes both
decisions (tentatively) made and questions raised.

====

1)  For a task type T, T'Image yields

    "(task <task_id_image>)"

or, if discriminants are involved,

    "(task <task_id_image> with D1 => 123, D2 => 456)"

2) For a protected type, there is nothing analogous to
the task stuff (because there is nothing analogous to
a task_id for protected types). Protected types just get displayed
like any other record.

3) The default implementation of Put for a protected type would
be implemented as something like

    procedure Put (X : T; S : access Counted_Stream'Class) is
       Ignored : constant Dummy_Type := X.<Put_Helper> (S);
    begin
       null;
    end;

where <Put_Helper> is an anonymous compiler-generated protected
function. The idea here is to write out to the stream a consistent
snapshot of the state of the protected record, using only one
protected action to access all components. The definition given
in the RM only needs to say that the default implementation of
T'Image where T is a protected type involves calling a
protected function.

One could imagine making this protected function visible (perhaps
via some new attribute), but let's wait until there is some
demand for this.

4) Recall that in this new scheme [Wide_[Wide_]]Image is not a
user-specifiable attribute. Instead, a new attribute (tentatively
named Put) can be specified and Image and friends are defined
in terms of Put.

Do we want to name this new attribute "Put" or "Put_Image" ?

5) In the absence of a user-specified Put operation, should
new discriminants for a derived untagged type have an effect
on the image? Presumably yes (at least that's how the
streaming attributes work).

So the assertion in this 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);

***************************************************************

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! ;-)

***************************************************************

From: Steve Baird
Sent: Wednesday, June 6, 2018  8:05 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:

Thanks. It all sounds good.

> ===================================
>
> 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).
>

Good catch. Your fix is indeed what I intended.

> (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.)

Really? I guess I can't argue that this one is even simpler than pragma Page,
so ok.

> (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.

It's there for the same reason that we provide the bounded containers.

> (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.

Good point.

> (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.

Like you, I'm not sure what to do here. Some thought is required.

> (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:

Sounds good.

> 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.

Yes, both occurrences of "non-universal" in the wording I proposed should be
similarly updated as you suggest.

> (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.)

Good questions.

I'd say don't make any changes along these lines in the !wording yet and we
can hash it out when we discuss the AI.

Thanks for the feedback,

***************************************************************

From: Randy Brukardt
Sent: Thursday, June 7, 2018  5:12 PM

...
> > (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.
>
> It's there for the same reason that we provide the bounded containers.

Sure, but we need to describe that, and how to avoid the dynamic allocation
implicit in the standard definition.

Something like:

We provide the Bounded_Stream package in order that 'Image can be used in
environments where dynamic allocation is banned. In such an environment, the
user ought to <<do this, that, and the other - put a real description
here>>. That forced the compiler to use Bounded_Stream rather than
here>>Stream to implement 'Image, <<more descriptive text>>.

...
> > (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.
> >
>
> Like you, I'm not sure what to do here. Some thought is required.

Given that, I'm going to leave fixing all of seven of these issues to you (I'm
over budget as it is). Please revise the AI with the changes (if I haven't
posted the corrected version yet when you get back from your trip, ask me for
it first).

...
> > (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.

If we had more time, I would have suggested splitting them out and treating
them separately. But at this point, that probably would make more work than be
helpful.

> > 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.)
>
> Good questions.
>
> I'd say don't make any changes along these lines in the !wording yet
> and we can hash it out when we discuss the AI.

Yes, this is fine. I just wanted to raise the issue as these packages are
generally useful beyond just implementing Put_Image. We ought to think about
those more general uses, even if we don't end up making any changes for that.

***************************************************************

From: Jeff Cousins
Sent: Monday, June 11, 2018  8:20 AM

Some comments Steve:

“The default implementation of S'Put_Image writes out (using
Wide_Wide_String'Write and or Wide_Wide_String'Output)” – maybe “and/or” or
just “or”?

“The Max_Image_Elements attribute may be specified for any type type T either
via an attribute_definition_clause, via an and aspect_specification specifying
the Put_Image” – duplicate “type” and duplicate “an”.

“(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 –),” – what are the – meant to be?

“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.” – if 248-1 is approved, we could use “null array”
rather than “<>”.  “<>” tends to indicate “something” (even if we’re not
saying exactly what here) rather than “nothing”, e.g. in 214-1 “<>”
indicates NOT null (pointer).

“For a (specific) type extension, the default implementation of T'Put_Image
depends on whether there exists a non-interface ancestor” – I like the
use of English English, but I’m sure Gary would object to the hyphen.

“In the case of a protected type T, a call to the default implementation
of T'Put_Image begins only one protected (readonly) action.“ – “read-only”.

Item (Item'First .. Last)'Length” (two places) – what is meant by this??

***************************************************************

From: Randy Brukardt
Sent: Monday, June 11, 2018  9:34 PM

...
  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 –),” – what are the – meant to be?

That's most likely the Unicode @endash, which doesn't cut-and-paste into
pure ASCII properly. It should just appear here as "-". That happens also
for the angled quote marks (which should never appear in Ada code samples)
among other things. I try to fix them, but it's a losing battle.

***************************************************************

From: Steve Baird
Sent: Wednesday, June 13, 2018  5:46 PM

>> (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.)
>>
>
> Really? I guess I can't argue that this one is even simpler than
> pragma Page, so ok.
>
Ok, use J.15.12 (pragma Relative_Deadline) or D.2.2 (pragma
Priority_Specific_Dispatching) as templates (in particular, with respect to
fonts) and replace the above with

     Syntax

     The form of a Default_Max_Image_Elements pragma is
     as follows:

       pragma Default_Max_Image_Elements (stream_offset_expression);

    Name Resolution Rules
       The expected type for a stream_offset_expression is
       Ada.Streams.Stream_Offset

(do we, by convention, omit the "Ada." in "Ada.Streams"?)

    Legality Rules:
       Default_Max_Image_Elements is a configuration pragma, and shall
       not be used other than as a configuration pragma.
       The stream_offset_expression shall be a static expressions in
       the range -1 .. Ada.Streams.Stream_Element_Offset'Last.

       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.

    Static semantics
       [A Default_Max_Image_Elements pragma participates in
       determining the Max_Image_Elements aspect(s) of zero or more
       types as described above.]

>> (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.
>>
>
> It's there for the same reason that we provide the bounded containers.
>

Note that the only text along these lines that we have for bounded containers
is A.18's AARM text
    "Similarly, a separate bounded version is provided in order to give
    more predictable memory usage."

So immediately after the proposed implementation advice

    Bounded_Stream objects should be implemented without implicit
    pointers or dynamic allocation.

We add

    [AARM: The Counted_Streams.Bounded package is provided in order to
    make available an alternative to the Counted_Streams.Unbounded
    package which gives more predictable memory usage.]


>> (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.
>>
>
> Good point.
>

In the current RM, we have

   Implementation Note: If the machine supports negative zeros for signed
   integer types, it is not specified whether " 0" or "–0" should be
   returned for negative zero. We don't have enough experience with such
   machines to know what is appropriate, and what other languages do. In
   any case, the implementation should be consistent.

occurring immediately after

    The image of an integer value is ... either a minus sign or a space.

So that is also where the implementation note goes in the new wording.

Similarly, in the current RM we have

    Implementation Note: For an enumeration type T that has “holes”
    (caused by an enumeration_representation_clause), T'Wide_Image should
    raise Program_Error if the value is one of the holes (which is a
    bounded error anyway, since holes can be generated only via
    uninitialized variables and similar things).

occurring immediately after

     The image of an enumeration value is ... “NUL” — the quotes are not
     part of the image).

so that's also where it goes in the new wording.

And in the current RM we have

    To be honest: Leading zeros are present in the exponent only if
    necessary to make the exponent at least two digits.

    Reason: This image is intended to conform to that produced by
    Text_IO.Float_IO.Put in its default format.

    Implementation Note: The rounding direction is specified here to
    ensure portability of output results.

occurring immediately after

    The image of a floating point value is ...  a negatively signed zero.

so that's also where it goes in the new wording.

And in the current RM we have

     Reason: This image is intended to conform to that produced by
     Text_IO.Fixed_IO.Put.

     Implementation Note: The rounding direction is specified here to
     ensure portability of output results.

    Implementation Note: For a machine that supports negative zeros, it
    is not specified whether " 0.000" or "–0.000" is returned. See
    corresponding comment above about integer types with signed zeros.

occurring immediately after

    The image of a fixed point value is ... the decimal point.

so that's also where it goes in the new wording.

>> (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.
>>
>
> Like you, I'm not sure what to do here. Some thought is required.
>

How about:

  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)))
   except with each sequence of spaces and line breaks replaced
   with a single space (with two spaces in the case of the spaces
   between a comma and an integer literal).

This isn't ideal; I'm (very) open to suggestions.

=======
>> “The default implementation of S'Put_Image writes out (using
>> Wide_Wide_String'Write and or Wide_Wide_String'Output)”
> – maybe “and/or”  or just “or”?

Or maybe just eliminate the reference to Wide_Wide_String'Output, so it
becomes just "using Wide_Wide_String'Write". I'm not sure what I was thinking
of when I mentioned 'Output.

> duplicate
> “type” and duplicate “an”.

Good catch.


>  what are the – meant to be?

I think Randy explained this stuff.

Alternatively, a comic-strip character hit his thumb with a hammer.

> if 248-1 is approved, we could use “null array” rather than “<>”.

I thought about that and decided that we (or at least I) don't want to use
that syntax even if the AI is approved because it doesn't allow specifying the
bounds.

We can discuss this further, of course, if there is interest.

>  depends  on whether there exists a non-interface ancestor” – I like
>> the use of English English, but I’m sure Gary would object to the hyphen.

Good catch. The current RM currently has 3 uses of "noninterface" and
no uses of "non-interface".


> T'Put_Image begins only one protected (readonly) action.“ – “read-only”.

Agreed. Take the hyphen I used in "non-interface" and move it over here.


> “Item (Item'First .. Last)'Length” (two places) – what is meant by this??

In the first occurrence, we've got

    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;

The postcondition says that the final Element_Count is equal to the
old Element_Count minus the number of stream elements that were read.
The expression in question
     Item (Item'First .. Last)'Length
yields the number of stream elements that were read (at least that
was my intent).

The second occurrence is the same thing except in the Bounded package
instead of the Unbounded package.

***************************************************************

From: Randy Brukaardt
Sent: Thursday, June 14, 2018  5:17 PM

> >> (C2)
...
> Ok, use J.15.12 (pragma Relative_Deadline) or D.2.2 (pragma
> Priority_Specific_Dispatching) as templates (in particular, with
> respect to fonts) and replace the above with

I take it from this that you are expecting me (your overworked editor :-) to
make these updates? I'll do them, but I surely don't want to duplicate effort.

>      Syntax
>
>      The form of a Default_Max_Image_Elements pragma is
>      as follows:
>
>        pragma Default_Max_Image_Elements (stream_offset_expression);
>
>     Name Resolution Rules
>        The expected type for a stream_offset_expression is
>        Ada.Streams.Stream_Offset
>
> (do we, by convention, omit the "Ada." in "Ada.Streams"?)

Usually, a convention I hate and often forget. My recollection was that it was
in response to a complaint that Ada 9x was too wordy; it eliminated some words
without actually requiring any effort to do so. And it has no descernable
effect on the size of the Standard (any gains made disappear in clause breaks
and the like). Grump.

...
> >> (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.
> >>
> >
> > It's there for the same reason that we provide the bounded containers.
> >
>
> Note that the only text along these lines that we have for bounded
> containers is A.18's AARM text
>     "Similarly, a separate bounded version is provided in order to give
>     more predictable memory usage."
>
> So immediately after the proposed implementation advice
>
>     Bounded_Stream objects should be implemented without implicit
>     pointers or dynamic allocation.
>
> We add
>
>     [AARM: The Counted_Streams.Bounded package is provided in order to
>     make available an alternative to the Counted_Streams.Unbounded
>     package which gives more predictable memory usage.]

Fine, but you totally missed my point. You have a pragma and a package and
some other disconnected things, but nowhere you do you layout the model. At a
minimum, we need something like:

   The default model of Put_Image uses unbounded streams, which necessarily
   involves some dynamic memory allocation. Since Ada is widely used by
   systems that require predictable memory usage, we provide an alternative
   model for Put_Image that provides that. Such a user should apply
   Silly_Pragma (** too lazy to look it up **) as a configuration pragma to
   their entire system. This causes Bounded_Stream (*** and other facts?? **)
   to be used for all calls to Put_Image rather than Unbounded_Streams,
   providing the needed memory predicability.

I'm certain this requires more fleshing out (there's some value associated
with Silly_Pragma, it needs to be mentioned here).

...
> >> 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.
> >>
> >
> > Like you, I'm not sure what to do here. Some thought is required.
> >
>
> How about:
>
>   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)))
>    except with each sequence of spaces and line breaks replaced
>    with a single space (with two spaces in the case of the spaces
>    between a comma and an integer literal).
>
> This isn't ideal; I'm (very) open to suggestions.

It's OK enough by me, absent better ideas.


====
...
> >  what are the – meant to be?
>
> I think Randy explained this stuff.
>
> Alternatively, a comic-strip character hit his thumb with a hammer.

LoL.

...
> > “Item (Item'First .. Last)'Length” (two places) – what is meant by this??
>
> In the first occurrence, we've got
>
>     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;
>
> The postcondition says that the final Element_Count is equal to the
> old Element_Count minus the number of stream elements that were read.
> The expression in question
>      Item (Item'First .. Last)'Length
> yields the number of stream elements that were read (at least that was
> my intent).
>
> The second occurrence is the same thing except in the Bounded package
> instead of the Unbounded package.

Sure, but I wondered why you wrote 'Length rather than just writing the
answer. That is, for any array with integer indices,

    Arr(A..B)'Length == (if A <= B then B - A + 1 else 0)

The attribute form requires evaluating the prefix and the condition, but in
this case we know that Last + 1 >= Item'First, so the evaluating neither is
necessary. (And I doubt that a compiler can figure that out -- it would
require detailed rummaging in the body of the routine -- SPARK may be able
to, of course.)

So I probably would have written:

    Last - Item'First + 1 -- Number of characters read (or returned?)

for this value. I suppose your original expression is closer to
self-documenting, but even that isn't the case judging from Jeff's
question.

***************************************************************

From: Steve Baird
Sent: Thursday, June 14, 2018  6:06 PM

>>>> (C2)
> ...
>> Ok, use J.15.12 (pragma Relative_Deadline) or D.2.2 (pragma
>> Priority_Specific_Dispatching) as templates (in particular, with
>> respect to fonts) and replace the above with
>
> I take it from this that you are expecting me (your overworked editor :-)
> to make these updates? I'll do them, but I surely don't want to duplicate
> effort.

I accept your generous offer.

>
> ...
>>>> (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.

>
> Fine, but you totally missed my point. You have a pragma and a package and
> some other disconnected things, but nowhere you do you layout the model.
> At a minimum, we need something like: ...
>

I'll agree that we need some such text after you show me the corresponding
text for the bounded containers (and this is not just rhetorical - there is
a real chance that the wording is there and I overlooked it). If we didn't
need such wording in the case of the containers, then IMO we don't need it
here.

>
> So I probably would have written:
>
>      Last - Item'First + 1 -- Number of characters read (or returned?)
>
> for this value. I suppose your original expression is closer to
> self-documenting, but even that isn't the case judging from Jeff's
> question.

I say stick with what I proposed for now in the AI and we can flip a coin in
Lisbon. Either way is fine with me, but I have a weak preference for the way I
originally wrote it.

Thanks for the feedback,

***************************************************************

From: Randy Brukardt
Sent: Thursday, June 14, 2018  6:17 PM

> I'll agree that we need some such text after you show me the
> corresponding text for the bounded containers (and this is
> not just rhetorical - there is a real chance that the wording
> is there and I overlooked it). If we didn't need such wording
> in the case of the containers, then IMO we don't need it here.

These aare completely different cases, IMHO. You don't need to use a
configuration pragma to use a bounded container; you just use it if you
like. You could do that with the bounded marshalling stream, of course, but
the point here is to allow Image to be used without forcing dynamic
allocation. The AI needs to say that somewhere!

Moreover, I'm talking about adding text into the !discussion to explain what
the heck this pragma and Bounded_Stream type are doing there in the first
place. It doesn't need to be in the RM (you often seem to be so fixed on the
details that nothing else matters, but I want to be able to read one of
these AIs in ten years and have some idea why we chose the design we did --
and it's clear that others do read AIs for that sort of information).
*Nothing* should appear in an AI without some explanation of why its there
and what it's for.

***************************************************************

From: Randy Brukardt
Sent: Thursday, June 14, 2018  6:21 PM

> I'll agree that we need some such text after you show me the
> corresponding text for the bounded containers (and this is not just
> rhetorical - there is a real chance that the wording is there and I
> overlooked it). If we didn't need such wording in the case of the
> containers, then IMO we don't need it here.

Ignoring how silly a request this is, here's the start of the !discussion in
AI05-0001-1:

  The bounded forms are intended to bring determinism to the storage
  requirements of the various container forms. To this end, each bounded form
  includes Implementation Advice that no dynamic allocation or pointers are
  used to implement them. Thus, the bounded forms should be usable even in
  high-integrity contexts where dynamic allocation is forbidden.

I am looking for something on this line explaining how the pragma and the
stream work together to provide this behavior for Image. Few people are going
to be able to figure it out on their own.

***************************************************************

From: Steve Baird
Sent: Thursday, June 14, 2018  6:33 PM

> Moreover, I'm talking about adding text into the !discussion to
> explain what the heck this pragma and Bounded_Stream type are doing
> there in the first place. It doesn't need to be in the RM (you often
> seem to be so fixed on the details that nothing else matters, but I
> want to be able to read one of these AIs in ten years and have some
> idea why we chose the design we did -- and it's clear that others do read
> AIs for that sort of information).
> *Nothing*  should appear in an AI without some explanation of why its
> there and what it's for.

Ok, I completely agree about !discussion . I thought you were talking about
AARM wording.

I'll propose something shortly.

Incidentally, since we are talking about things other than the !wording
section, the !proposal section currently begins with

   T'Image is defined for all non-abstract types

and this should probably be replaced with something like

   T'Image is defined for (almost) all types.

***************************************************************

From: Steve Baird
Sent: Thursday, June 14, 2018  7:13 PM

> Ok, I completely agree about !discussion . I thought you were talking
> about AARM wording.
>
> I'll propose something shortly.

!discussion

The expected (although not required) implementation of the package
Ada.Streams.Counted_Streams.Unbounded involves dynamic storage allocation of some
kind, perhaps accompanied with uses of controlled types.

For some applications with high integrity/reliability requirements, those
requirements (more specifically, requirements about predictable memory
utilization) might preclude use of this package.

Nonetheless, we would like such applications to be able to use T'Image for a
non-scalar type T without having to override the default implementation of
T'Put_Image.

That is the motivation for introducing
    a) The package Ada.Streams.Counted_Streams.Bounded and its
       associated implementation advice.
    b) The aspect (and attribute) Max_Image_Elements
    c) The pragma Default_Max_Image_Elements.
    d) The interaction (for a given type T) between
       T'Max_Image_Elements and the default implementation
       of T'Put_Image .

An application can specify T'Max_Image_Elements either explicitly or via a
Default_Max_Image_Elements configuration pragma. Having done that, the default
implementation of T'Put_Image will reference Counted_Streams.Bounded instead
of Counted_Streams.Unbounded.

This will achieve the desired goal.

The cost is that the burden is on the user to choose a "good" value for
T'Max_Image_Elements. If the value is too small, then a call to T'Put_Image
may fail; if the value is too big, then the storage requirements of a call
to T'Put_Image may be unnecessarily large.

====

Put_Image is user-specifiable; Wide_Wide_Image is not.

One could imagine instead allowing user-specified Wide_Wide_Image attributes
and not bothering to define User_Put_Image at all.

The drawback of this approach is that it would could introduce, at least for
some compilers, lots of copying.

Given
    type T is record F1, F2, F3 : Integer; end record;

the default implementation of T'Wide_Wide_Image could have been defined to be
something like

      return "(F1 => " &
               Arg.F1'Wide_Wide_Image &
               ", F2 => " &
               Arg.F2'Wide_Wide_Image &
               ", F3 => &
               Arg.F3'Wide_Wide_Image &
               ")";

but that's a lot of concatenation; the situation for arrays would be even worse.

Furthermore, the two Ada.Streams.Counted_Streams packages (Bounded and
Unbounded) seem like they will be useful in their own right.

***************************************************************

From: Randy Brukardt
Sent: Thursday, June 14, 2018  8:20 PM

...
> Incidentally, since we are talking about things other than the
> !wording section, the !proposal section currently begins with
>
>    T'Image is defined for all non-abstract types
>
> and this should probably be replaced with something like
>
>    T'Image is defined for (almost) all types.

Humm. You describe Put_Image as working like streams. You have no rules for
abstract types, that seems weird so I went to look at the stream attribute
rules. It turns out that all of the abstract type rules have to do with
function 'Input, so those don't apply here.

But stream attributes do have 13.13.2(38.1/4):

The subprogram name given in such an attribute_definition_clause or
aspect_specification shall statically denote a subprogram that is not an
abstract subprogram. Furthermore, if a specific stream-oriented attribute is
specified for an interface type, the subprogram name given in the
attribute_definition_clause or aspect_specification shall statically denote a
null procedure.

You don't have such a rule, but it seems needed. (We don't want to be calling
abstract subprograms!) The second part seems to come from the fact that the
only primitive concrete operation of an interface is a null procedure. (I
didn't look up the exact reason for it, it could have come from any one of
6 AIs - streams were a mess years ago!)

***************************************************************

From: Steve Baird
Sent: Friday, June 15, 2018  7:34 PM

Good catches.

I agree that we should be consistent with the treatment of the stream-oriented
attributes here. Would it be worth trying to factor this out in order to avoid
duplication? Perhaps a general 13.1.1 rule that, unless otherwise specified
for a particular aspect, the subprogram named in an aspect specification for a
subprogram-valued aspect shall not be abstract? Then we'd have to go find and
remove all the existing wording that would become redundant as a result of
this change.

It wouldn't bother me to outlaw specifying Put_Image for an interface type,
except that I agree that we want to be consistent with the streaming stuff. So
I agree with your suggestion that we impose a "must be a null procedure" rule.

***************************************************************

From: Steve Baird
Sent: Friday, June 15, 2018  7:41 PM

> It wouldn't bother me to outlaw specifying Put_Image for an interface
> type

I take it back; that would cause contract problems for generics with formal
types where the corresponding actual might or might not be an interface type.

***************************************************************

From: Randy Brukardt
Sent: Friday, June 15, 2018  7:54 PM

> I agree that we should be consistent with the treatment of the
> stream-oriented attributes here. Would it be worth trying to factor
> this out in order to avoid duplication? Perhaps a general 13.1.1 rule
> that, unless otherwise specified for a particular aspect, the
> subprogram named in an aspect specification for a subprogram-valued
> aspect shall not be abstract? Then we'd have to go find and remove all
> the existing wording that would become redundant as a result of this
> change.

It might make sense (not that I'm volunteering). The existing rule like that
is 13.3(6), so I would think it would make the most sense to extend that.
Alternatively, we might want to move that existing rule into 13.1 (since it
should apply regardless of the syntax of specification), and then extend it.
That would eliminate one more use of the blanket equivalence rule -- the
fewer uses of that, the better.

I.e.

For the specification of an aspect that denotes a subprogram, the subprogram
shall not be abstract, the profile shall be mode conformant with the one
required for the aspect, and the convention shall be Ada. Additional
requirements are defined for particular aspects.

OTOH, the blanket rule doesn't work in reverse (aspect rules don't
automatically apply to attribute_definition_clauses), so it's unclear that
would work as written above. I'd have to look at how 13.1 works to get this
wording right - I'll leave that to you (along with finding any wording that is
unneeded after adding this).

> It wouldn't bother me to outlaw specifying Put_Image for an interface
> type, except that I agree that we want to be consistent with the
> streaming stuff. So I agree with your suggestion that we impose a
> "must be a null procedure" rule .

Yeah, it took a long time to get the rules for streams right, the less of that
pain we have to repeat the better.

***************************************************************

From: Steve Baird
Sent: Monday, June 18, 2018  6:39 PM

>> I agree that we should be consistent with the treatment of the
>> stream-oriented attributes here. Would it be worth trying to factor
>> this out in order to avoid duplication? Perhaps a general 13.1.1 rule
>> that, unless otherwise specified for a particular aspect, the
>> subprogram named in an aspect specification for a subprogram-valued
>> aspect shall not be abstract? Then we'd have to go find and remove
>> all the existing wording that would become redundant as a result of
>> this change.
>
> It might make sense (not that I'm volunteering). The existing rule
> like that is 13.3(6), so I would think it would make the most sense to extend that.
> Alternatively, we might want to move that existing rule into 13.1
> (since it should apply regardless of the syntax of specification), and then extend it.
> That would eliminate one more use of the blanket equivalence rule --
> the fewer uses of that, the better.

Agreed. Even if we don't clean up the equivalence stuff at this point, let's
not make it worse.

So suppose we add the following new paragraph in 13.1.1 immediately after
18.1/4 (i.e., just before getting into the "nonoverridable"
rules):

   Unless otherwise specified for a particular aspect, the subprogram
   named in an aspect_specification, an attribute_definition_clause
   or a pragma which specifies a subprogram-valued aspect shall not be
   abstract.

   Unless otherwise specified for a particular aspect,
   if a subprogram-valued aspect is specified for an interface type,
   the subprogram name given in the aspect_specification,
   attribute_definition_clause, or pragma shall statically denote a null
   procedure. This rule does not apply to the four class-wide
   stream-oriented attributes [(i.e., Read'Class, Write'Class,
   Input'Class, and Ouput'Class)].

In addition to the new Put_Image aspect that is introduced in this AI, I think
this rule would also apply to the following already-defined aspects:

    1) Read/Write/Input/Ouput['Class]
    2) Stable_Properties['Class]
    3) Constant_Indexing/Variable_Indexing
    4) Default_Iterator

I could easily have missed some; for example, if you look for aspect
definitions in K.1 which mention "subprogram", "function", "procedure" or
"entry", you will not find Default_Iterator.

So I went looking for existing wording that ought to be removed because the
proposed change would render it redundant.

1) Of course there is the streaming rule that started this whole
    business, 13.13.2(38.1/4). That paragraph would need to be removed.

2) For Stable_Properties, I didn't find any such rule (which seems like
    an oversight in the Stable_Properties definition). We probably also
    don't want to allow specifying Stable_Properties (as opposed to
    Stable_Properties'Class) for an abstract type, but that's a separate
    question.

3) For Constant_Indexing/Variable_Indexing, I also don't think any
    wording change is needed (and, with #2, I think this new wording
    plugs some holes).

    This case is (sort of) handled by the existing 4.1.6 rule
      A generalized_indexing is illegal if the equivalent prefixed view
      (see below) is illegal.
    which will catch the case of a non-dispatching call to an abstract
    subprogram. But that wording doesn't help catch anything at the
    point of the aspect specification (and specifying an abstract
    subprogram for a nonoverridable aspect doesn't seem like something
    we want to allow).

4) Same situation as #3, including the fact that this is another
    nonoverridable aspect. The situation is actually worse because we
    don't have anything analogous to the "is illegal if the equivalent
     ... is illegal" rule that we have in #3.

So in summary, it looks like this new wording plugs some holes in
3 out of 4 cases and the only wording that would need to be removed is
13.13.2(38.1/4).

As always, any review is welcome.

And yes, I know this is way past the deadline.

***************************************************************

From: Randy Brukardt
Sent: Tuesday, June 19, 2018  4:27 PM

You are very confused about Stable_Properties. It takes a "list of functions"
(or, if the new AI is approved, "an aggregate of function names"), not a
"function", so regardless of whatever wording you are writing, it does not
apply to Stable_Properties. Whether Stable_Properties needs an abstract rule
of it's own is a separate question (it might not, since the name is required
to be a "property function", and I don't recall the rules that needs right
now. (I'm too tired to look, answering mail and going to bed...Jet Lag does
that to one.) I don't think it needs to be tied into the null procedure rule,
since again it has to be a property *function*.

***************************************************************

From: Randy Brukardt
Sent: Friday, June 29, 2018  7:43 PM

I answered this one originally when I was jet lagged right after arriving in
Lisbon. Let me finish the thought...

...
> So suppose we add the following new paragraph in 13.1.1 immediately
> after 18.1/4 (i.e., just before getting into the "nonoverridable"
> rules):
>
>    Unless otherwise specified for a particular aspect, the subprogram
>    named in an aspect_specification, an attribute_definition_clause
>    or a pragma which specifies a subprogram-valued aspect shall not be
>    abstract.
>
>    Unless otherwise specified for a particular aspect,
>    if a subprogram-valued aspect is specified for an interface type,
>    the subprogram name given in the aspect_specification,
>    attribute_definition_clause, or pragma shall statically denote a null
>    procedure. This rule does not apply to the four class-wide
>    stream-oriented attributes [(i.e., Read'Class, Write'Class,
>    Input'Class, and Ouput'Class)].

Generally, rules that apply to all kinds of aspects belong in 13.1; 13.1.1 is
about rules that only apply to aspect_specifications. Otherwise, this looks
fine to me.

> In addition to the new Put_Image aspect that is introduced in this AI,
> I think this rule would also apply to the following already-defined
> aspects:
>
>     1) Read/Write/Input/Ouput['Class]
>     2) Stable_Properties['Class]
>     3) Constant_Indexing/Variable_Indexing
>     4) Default_Iterator
>
> I could easily have missed some; for example, if you look for aspect
> definitions in K.1 which mention "subprogram", "function", "procedure"
> or "entry", you will not find Default_Iterator.
>
> So I went looking for existing wording that ought to be removed
> because the proposed change would render it redundant.
>
> 1) Of course there is the streaming rule that started this whole
>     business, 13.13.2(38.1/4). That paragraph would need to be removed.
>
> 2) For Stable_Properties, I didn't find any such rule (which seems like
>     an oversight in the Stable_Properties definition). We probably also
>     don't want to allow specifying Stable_Properties (as opposed to
>     Stable_Properties'Class) for an abstract type, but that's a separate
>     question.

I partially previously answered this one. But we do need a rule that disallows
abstract functions for Stable_Properties (it seems OK for
Stable_Properties'Class), and also abstract types for Stable_Properties.

So:

Add before 7.3.4(10/5):

"The aspect Stable_Properties shall not be specified for an abstract type."

AARM Ramification: The above rule does not apply to Stable_Properties'Class
aspects.

Add after 7.3.4(13/5):

"Furthermore, a stable property function used in a Stable_Properties aspect
shall not be abstract."

AARM Ramification: The above rule does not apply in Stable_Properties'Class
aspects.

> 3) For Constant_Indexing/Variable_Indexing, I also don't think any
>     wording change is needed (and, with #2, I think this new wording
>     plugs some holes).
>
>     This case is (sort of) handled by the existing 4.1.6 rule
>       A generalized_indexing is illegal if the equivalent prefixed view
>       (see below) is illegal.
>     which will catch the case of a non-dispatching call to an abstract
>     subprogram. But that wording doesn't help catch anything at the
>     point of the aspect specification (and specifying an abstract
>     subprogram for a nonoverridable aspect doesn't seem like something
>     we want to allow).

Right. The new rule seems like an improvement; if no possible call would be
legal, why allow the aspect specification?

> 4) Same situation as #3, including the fact that this is another
>     nonoverridable aspect. The situation is actually worse because we
>     don't have anything analogous to the "is illegal if the equivalent
>      ... is illegal" rule that we have in #3.

We have 5.5.2(6.2/4), which makes the iterator illegal if the Default Iterator
function call is illegal; so there is no hole. (There *was* a reason for this
generically defined rule; it was originally added to catch constant containers
when the parameter is "in out").

Again, the new rule seems like an improvement, but it's not strictly
necessary.

> So in summary, it looks like this new wording plugs some holes in
> 3 out of 4 cases and the only wording that would need to be removed is
> 13.13.2(38.1/4).
>
> As always, any review is welcome.
>
> And yes, I know this is way past the deadline.

I was too tired to complain. ;-)

**************************************************************

From: Steve Baird
Sent: Friday, October 5, 2018  5:02 PM

The attached is a new version of this AI, incorporating the feedback from the
Lisbon meeting.

It is actually 2 AIs (one of them hasn't been assigned a number yet) because
part of that Lisbon feedback was the suggestion that the AI should be split into
two parts. The other AI just defines some new predefined units,
Ada.Streams.FIFO_Streams and a couple of child units thereof. [This is
version /05 of this AI; the split AI was assigned AI12-0293-1 - Editor.]

As usual, thanks to Randy for some helpful preliminary review. Also as usual,
don't blame him for any flaws.

**************************************************************

From: Randy Brukardt
Sent: Monday, October 15, 2018  6:56 PM

> The attached is a new version of this AI, incorporating the
> feedback from the Lisbon meeting.
>
> It is actually 2 AIs (one of them hasn't been assigned a number
> yet) because part of that Lisbon feedback was the suggestion
> that the AI should be split into two parts. The other AI just
> defines some new predefined units, Ada.Streams.FIFO_Streams
> and a couple of child units thereof.

That will be AI12-0293-1.

> As usual, thanks to Randy for some helpful preliminary
> review. Also as usual, don't blame him for any flaws.

Of course. :-) Some nitpicks:

>    For scalars - same image that Wide_Wide_Image has always generated
>     since it was introduced in Ada95.

Wide_Wide_Image was introduced in Ada 2005. Ada 95 had Wide_Image (only). Some
of the details of Image have been changed in recent Ada versions as well
(especially for Character et. al.). So I'm not sure of the best possible
replacement here (just saying "Ada 2005" doesn't seem to have the intended
impact).

>   For class-wide types, the image obtained from the specific
>      type is prefixed with the name of the tag
>      and a "'", yielding qualified expression syntax, as in
>      "My_Pkg.My_Tagged_Type'(ABC => True, DEF => 123.45)".

Is this the name of the type of the tag, or the external name of the tag? (The
previous version was clear that it was the external name.) I'd add "external" in
this text if that's the intent. But I'm not certain it ought to be: the external
name might not have anything to do with a type name and it might not work well
as an expanded name.

>   S'Put_Image denotes a procedure with the following specification:
>       S'Put_Image
>           (Arg    : T;
>            Stream : not null access Ada.Streams.Root_Stream_Type'Class);

This is got to be the first Ada procedure I've seen without the keyword
"procedure"! Compare to the declarations in 13.13.2. ("procedure" should go
before the last S'Put_Image here).

>   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.

The lead-in text has disappeared here; we have no idea what X is here. I left
the text from the previous version in the posted AI.

>That is the motivation for introducing
>    a) The package Ada.Streams.Counted_Streams.Bounded and its
>       associated implementation advice.
>    b) The aspect (and attribute) Max_Image_Elements
>    c) The pragma Default_Max_Image_Elements.
>    d) The interaction (for a given type T) between
>       T'Max_Image_Elements and the default implementation
>       of T'Put_Image .

(a) is now in AI12-0293-1, and I believe that (b), (c), and (d) have been
replaced by a restriction. There is a bunch of other discussion text that tries
to explain (b), (c), and (d). That all needs to be replaced by text explaining
how to use the restriction. I could have fixed (a), but the rest is too much.


I did remove a double space before "of", and add a missing closing bracket ].
And used the number 293 rather ??? in a couple of places. Otherwise, I left the
original AI unchanged.

**************************************************************

From: Steve Baird
Sent: Tuesday, October 16, 2018  6:28 PM

> Some nitpicks:
>
>>     For scalars - same image that Wide_Wide_Image has always generated
>>      since it was introduced in Ada95.
>
> Wide_Wide_Image was introduced in Ada 2005. Ada 95 had Wide_Image
> (only). > Some of the details of Image have been changed in recent Ada
> versions as well (especially for Character et. al.). So I'm not sure
> of the best possible replacement here (just saying "Ada 2005" doesn't seem
> to have the intended impact).

I suggest "the same image that Wide_Wide_Image already generated before
this AI".

>>    For class-wide types, the image obtained from the specific
>>       type is prefixed with the name of the tag
>>       and a "'", yielding qualified expression syntax, as in
>>       "My_Pkg.My_Tagged_Type'(ABC => True, DEF => 123.45)".
>
> Is this the name of the type of the tag, or the external name of the tag?
> (The previous version was clear that it was the external name.) I'd
> add "external" in this text if that's the intent. But I'm not certain
> it ought to be: the external name might not have anything to do with a
> type name and it might not work well as an expanded name.

I think this lack of precision is fine in the !proposal section, particularly
since this question is answered in the !wording section, where is says that
Wide_Wide_Expanded_Name is called. I suggest that no action is needed for
this one.

>>    S'Put_Image denotes a procedure with the following specification:
>>        S'Put_Image
>>            (Arg    : T;
>>             Stream : not null access
>> Ada.Streams.Root_Stream_Type'Class);
>
> This is got to be the first Ada procedure I've seen without the
> keyword "procedure"! Compare to the declarations in 13.13.2.
> ("procedure" should go before the last S'Put_Image here).

I agree. The word "procedure" is missing and should be added.

>>    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.
>
> The lead-in text has disappeared here; we have no idea what X is here.
> I left the text from the previous version in the posted AI.

Good catch! I don't know what happened to
   For a prefix X that denotes an object of a non-universal type T, the
   following attributes are defined:
but I agree that it ought to be there.

>> That is the motivation for introducing
>>     a) The package Ada.Streams.Counted_Streams.Bounded and its
>>        associated implementation advice.
>>     b) The aspect (and attribute) Max_Image_Elements
>>     c) The pragma Default_Max_Image_Elements.
>>     d) The interaction (for a given type T) between
>>        T'Max_Image_Elements and the default implementation
>>        of T'Put_Image .
>
> (a) is now in AI12-0293-1, and I believe that (b), (c), and (d) have
> been replaced by a restriction. There is a bunch of other discussion
> text that tries to explain (b), (c), and (d). That all needs to be
> replaced by text explaining how to use the restriction. I could have
> fixed (a), but the rest is too much.


Good point. This stuff was updated in the !wording but not in the !discussion.

Here is a possible replacement:
====
That is the motivation for introducing the Max_Image_Length restriction. The
desired goal can be achieved by specifying a Max_Image_Length restriction.

The cost is that the burden is on the user to choose a "good" value for the
restriction. If the value is too small, then a call to T'Put_Image may violate
the restriction (at runtime); if the value is too big, then the storage
requirements of a call to T'Put_Image may be unnecessarily large.
====

> I did remove a double space before "of", and add a missing closing
> bracket ]. And used the number 293 rather ??? in a couple of places.
> Otherwise, I left the original AI unchanged.

Thanks.

**************************************************************

From: Randy Brukardt
Sent: Tuesday, October 16, 2018  7:50 PM

OK, made these updates to the AI (version /06).

****************************************************************

From: Randy Brukardt
Sent: Tuesday, October 16, 2018  7:50 PM

Just happened to notice one more nitpick:

> 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.
> Then Corresponding_Specific_Type'Put_Image is called. [At the
> implementation level this will typically require a dispatching call.]

I don't think that the typical reader cares what the implementation might or
might not do to implement the default version of this. So this "Redundant"
statement (which is missing the "Redundant" lead-in) makes more sense as an
AARM implementation note.

So I've changed this to:

  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.
  Then Corresponding_Specific_Type'Put_Image is called.

  AARM Implementation Note: This will typically require a dispatching call.

---

I also added "Redundant" in front of square brackets in the actual wording
(not AARM notes). Else someone could easily confuse that with a deletion.

****************************************************************

From: Steve Baird
Sent: Tuesday, October 16, 2018  8:36 PM

>   makes more sense as an AARM implementation note.

Agreed.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 14, 2019  9:36 PM

For the record:

The first bullet of the Implementation Permission reads:

If S is a composite subtype, the leading character of the image of a component 
value or index value is a space, and the immediately preceding character is an 
open parenthesis, then the space may be omitted. The same transformation is 
also permitted if the leading character of the component image is a space (in
which case one of the two spaces may be omitted).

which is interesting because we require arrays to be generated with square 
brackets. So apparently, we can't use this permission on an array aggregate. 
We clearly need to allow brackets here!

If S is a composite subtype, the leading character of the image of a component 
value or index value is a space, and the immediately preceding character is an 
open parenthesis {or bracket}, then the space may be omitted. The same 
transformation is also permitted if the leading character of the component 
image is a space (in which case one of the two spaces may be omitted).

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 14, 2019  11:29 PM

Another For the Record:

There is a note at the end of 3.5 that says:

For any value V (including any nongraphic character) of an enumeration subtype 
S, S'Value(S'Image(V)) equals V, as do S'Wide_Value(S'Wide_Image(V)) and 
S'Wide_Wide_Value(S'Wide_Wide_Image(V)). None of these expressions ever raise 
Constraint_Error. 

This is clearly a lie: all I need to do to make this False is:
    type Bad is (...)
       with Put_Image => Silly;
    procedure Silly (Arg : in Bad; not null access
Ada.Streams.Root_Stream_Type'Class) is
    begin
       raise Constraint_Error;
    end Silly;

So we need to mention that the Put_Image is the default:

For any value V (including any nongraphic character) of an enumeration 
subtype S {without a specified Put_Image (see 4.10)}, S'Value(S'Image(V)) 
equals V, as do S'Wide_Value(S'Wide_Image(V)) and 
S'Wide_Wide_Value(S'Wide_Wide_Image(V)). None of these expressions ever raise 
Constraint_Error. 

Arguably, this note belongs more in 4.10, but until we support a matching 
'Value, there is no obvious place for it. So it can stay here for Ada 2020.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 14, 2019  11:41 PM

nother minor issue:

The lead in for Put_Image and the Image family is:

For every subtype S of a non-universal type T, the following type-related 
operational attributes are defined:

But the Image attributes aren't redefinable, so calling them "operational 
attributes" is dubious.

So I split the headers, into separate ones for Put_Image and Image. 

Once that was done, there was no remaining reason to leave the definition of 
Image in between the definition of the Put_Image attribute and the several 
pages of text defining its default behavior. Moving the Image attributes down 
puts that text together.

This of course assumes that we agree on some introductory text for this 
subclause (else the point of the subclause won't show up until the last page), 
but I don't think that is optional anyway.

****************************************************************

From: Randy Brukardt
Sent: Friday, February 15, 2019  12:59 AM

The current description of the Image attributes is:

      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 via Wide_Wide_String'Read; the lower bound of that
      result is 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).

----

Note that the latter two start with "The function returns an image of the 
value of Arg as ...". In Ada 2012 (and probably before), "image" is a defined 
term, and it is defined as what Wide_Wide_Image returns.

But the wording above (nor anything else) defines such a term. That makes 
those introductory sentences nonsense. It also makes the first use of 
"defined" in the latter two descriptions dubious -- Wide_Wide_Image is a 
function, it doesn't define a "sequence of characters".

My first thought was to get rid of these introductory sentences, since what 
is returned is the result of Put_Image, suitably converted. Since that's 
user-defined, it could be nothing useful at all. This seems functionally
correct:

        The function returns the result of a call on S'Wide_Wide_Image 
        with a parameter of Arg as a String. The lower bound of the result is 
        one. The result has the same sequence of graphic characters as that 
        returned by 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).

I'm not sure if this is descriptive enough. An alternative would be to rewrite 
the Wide_Wide_Image and define the term "image" there. But even then, I find 
it dubious to talk about the characters "defined" for Wide_Wide_Image, because 
it defines nothing other than to return the result of another call.

I'll use this for now, pending further suggestions.

Aside: The description of Wide_Wide_Image never says what happens to Arg. We 
need to add at a minimum "passing Arg" to "calls Put_Image".

Aside2: The description of Wide_Wide_Image starts "The implementation of 
S'Wide_Wide_Image calls...". What else would we be talking about? That's just 
noise, we can just say "S'Wide_Wide_Image calls...".

****************************************************************

[From the AARM review of Justin Squirek (October 2020) - Editor.]

13/5: Another minor suggestion involving parenthesis:

"...generates an image based on (named, not positional) array aggregate..."

to

"...generates an image based on named (not positional) array aggregate..."

19/5: Similar to the last suggestion

"...generates an image based on (named, not positional) record aggregate 
syntax..."

to

"...generates an image based on named (not positional) record aggregate 
syntax..."

[Editor's response: This is formally a change in normative semantics, but it
is clear from the parenthisized wording that this is the intended semantics,
so it is better to say that normatively. Thus I processed it as an Editorial
Review change in AI12-0020-1.]

****************************************************************


Questions? Ask the ACAA Technical Agent