4.10 Image Attributes
{
AI12-0315-1} 
An 
image of a value is a string representing the value in display 
form.
 The attributes Image, Wide_Image, and Wide_Wide_Image 
are available to produce the image of a value as a String, Wide_String, 
or Wide_Wide_String (respectively). User-defined images for a given type 
can be implemented by overriding the default implementation of the attribute 
Put_Image. 
 
Static Semantics
{
AI12-0020-1} 
{
AI12-0315-1} 
For every subtype S of a type T other than 
universal_real or 
universal_fixed, 
the following type-related operational attribute is defined:
 
S'Put_Image
{
AI12-0020-1} 
{
AI12-0320-1} 
{
AI12-0340-1} 
S'Put_Image denotes a procedure with the following specification: 
 
procedure S'Put_Image
   (Buffer : in out 
             Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
    Arg   : in T);
{
AI12-0315-1} 
{
AI12-0340-1} 
The default implementation of S'Put_Image writes (using Wide_Wide_Put) 
an 
image of the value of 
Arg.
 
Aspect Description for Put_Image: 
Procedure to define the image of a given type.
Discussion: In contrast, the Image, Wide_Image, 
and Wide_Wide_Image attributes and their associated aspects can not be 
specified. The behavior of any of these attributes is defined in terms 
of calls to the corresponding Put_Image procedure, so changes in their 
behavior may be accomplished via a Put_Image specification.
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 there should be no change in the 
behavior of existing programs as a result of these changes. 
{
AI12-0020-1} 
{
AI12-0419-1} 
The behavior of the default implementation of S'Put_Image depends on 
the class of T.
 
procedure Scalar_Type'Put_Image
  (Buffer : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
   Arg    : in Scalar_Type) is
begin
   Buffer.Wide_Wide_Put (<described below>);
end Scalar_Type'Put_Image;
where the Wide_Wide_String 
value written out to the text buffer is defined as follows:
{
AI12-0020-1} 
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.
 
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. 
Discussion: We allow S'Put_Image when 
S is universal_integer or root_integer, because the details 
of the desired string do not depend on properties of an integer type. 
While S'Put_Image cannot be called directly for these types (as they 
cannot be named), it can be called as part of evaluating an Image attribute. 
Note that other rules of the language ensure that an implementation can 
evaluate any universal_integer attribute using type root_integer; 
therefore, Constraint_Error could be raised by the evaluation of an Image 
attribute if the value of the prefix is outside of the range of root_integer. 
{
AI12-0020-1} 
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).
 
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). 
{
AI12-0020-1} 
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.
 
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. 
Reason: {
AI12-0315-1} 
We do not allow S'Put_Image when S is 
universal_real, as the details 
of the desired string depend on the properties of the (specific) type 
of S. Specifically, 
universal_real does not have a defined value 
for S'Digits. 
 
{
AI12-0020-1} 
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.
 
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.
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. 
Reason: {
AI12-0315-1} 
We do not allow S'Put_Image when S is 
universal_fixed, as the 
details of the desired string depend on the properties of the (specific) 
type of S. Specifically, 
universal_fixed does not have a defined 
value for S'Aft. 
 
{
AI12-0020-1} 
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)".
 
To be honest: {
AI12-0315-1} 
S'Put_Image is defined for 
universal_access, but it can never 
be called (as no legal 
prefix 
of Image has that type, and that type cannot be named preventing direct 
calls). 
 
{
AI12-0020-1} 
{
AI12-0419-1} 
{
AI12-0435-1} 
{
AI22-0088-1} 
{
AI22-0118-1} 
For a nonnull type extension,
 or an untagged derived type declared with a known_discriminant_part, 
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 directly specified
 [(visibly or 
privately)]. 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 a nonderived record type. 
{
AI22-0118-1} 
if T is a nonnull type extension, 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; 
Discussion: 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. 
Reason: {
AI22-0088-1} 
The default implementation for Put_Image does not 
respect privacy in general, so extension aggregate syntax is used by 
default even if the aspect specification for the ancestor is only given 
in the private part.  
{
AI22-0118-1} 
if T is an untagged derived type with a known_discriminant_part, 
T'Put_Image invokes the Put_Image for its parent type on a conversion 
of the parameter of type T to the parent type.  
  {
AI22-0118-1} 
If no such ancestor exists, then the default implementation 
of T'Put_Image is the same as described below for a nonderived record 
or protected type. 
{
AI12-0419-1} 
For a specific, nonderived composite type:
 
This paragraph 
was deleted.{
AI12-0020-1} 
{
AI12-0132-1} 
If the default implementation of Put_Image writes 
components, the order in which components are written 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.] 
Discussion: {
AI12-0020-1} 
{
AI12-0384-2} 
In general, the default implementation of T'Put_Image for a composite 
type will involve some sequence of calls to Put and its Wide and Wide_Wide 
variants and calls to the Put_Image procedures of component types and, 
in the case of an array type, index types. The Put calls may pass in 
either literal values (such as "(", ")", "'(", 
" => ", 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). 
 
{
AI12-0020-1} 
{
AI12-0419-1} 
{
AI22-0132-1} 
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 components are written in increasing 
index order at each level, using a nested syntax for a multidimensional 
array, as in a multidimensional array aggregate. 
Discussion: 
An array type 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. 
{
AI12-0020-1} 
The case of a null array is handled specially, using ranges for index 
bounds and 
"<>" as a syntactic component-value 
placeholder.
 
Discussion: 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. 
{
AI12-0020-1} 
{
AI12-0419-1} 
{
AI22-0118-1} 
{
AI22-0132-1} 
For a record type (or, as indicated above, 
certain 
composite derived types a type extension 
with no noninterface ancestor specifying Put_Image), 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
 of the component type.
  Components are displayed in the order they occur within the declarative 
region of the type (see 8.1 and 3.4). 
Discussion: 
This might generate an image such as: 
"(FOO => [1 => 'c',  2 => 'a',  3 => 't'], BAR => TRUE)"
{
AI12-0020-1} 
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.
 
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.
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);
{
AI12-0020-1} 
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.
 
{
AI12-0020-1} 
For a discriminated task type, the default implementation of T'Put_Image 
also includes discriminant values, 
 in the order 
they occur within the known_discriminant_part, 
as in: 
 
"(TASK <task_id_image> with D1 =>  123, D2 =>  456)"
{
AI12-0020-1} 
{
AI12-0384-2} 
For a class-wide type, the default implementation of T'Put_Image generates 
an image based on qualified expression syntax. Wide_Wide_Put 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.
 
Implementation Note: This will typically 
require a dispatching call. 
Discussion: 
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. 
{
AI12-0020-1} 
{
AI12-0384-2} 
[T'Put_Image is the same for both the partial view and full view of T, 
if T has a partial view.]
 
Proof: {
AI12-0384-2} 
A type-related operational aspect is the same for the full view and partial 
view of a type. See 
13.1. 
 
{
AI12-0435-1} 
In the 
parameter_and_result_profile 
for the default implementation of Put_Image, the subtype of the 
Arg 
parameter is the base subtype of 
T if 
T is a scalar type, 
and the first subtype otherwise. For an 
aspect_specification 
or 
attribute_definition_clause 
specifying Put_Image, the subprogram name shall denote a nonabstract 
procedure whose second parameter is either of the first subtype of 
T, 
or as an option when 
T is scalar, the base subtype of 
T.
 
Ramification: Put_Image is never an abstract 
routine, even for an abstract type. Thus, Put_Image and Image can be 
called for any type. 
{
AI12-0020-1} 
For every subtype S of a type T, the following attributes are defined:
 
S'Wide_Wide_Image
{
AI12-0020-1} 
{
AI12-0340-1} 
{
AI12-0384-2} 
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 store a sequence 
of character values in a text buffer) and then returns the result of 
retrieving the contents of that buffer with function Wide_Wide_Get. The 
lower bound of the result is one. [Any exception propagated by the call 
of S'Put_Image is propagated.]
S'Wide_Image
{
AI12-0020-1} 
{
AI12-0340-1} 
{
AI12-0384-2} 
S'Wide_Image denotes a function with the following specification: 
 
function S'Wide_Image(Arg : S'Base)
  return Wide_String
S'Wide_Image calls S'Put_Image passing 
Arg (which will typically store a sequence 
of character values in a text buffer) and then returns the result of 
retrieving the contents of that buffer with function Wide_Get. The lower 
bound of the result is one. [Any exception propagated by the call of 
S'Put_Image is propagated.]
S'Image
{
AI12-0020-1} 
{
AI12-0340-1} 
{
AI12-0384-2} 
S'Image denotes a function with the following specification: 
 
function S'Image(Arg : S'Base)
  return String
S'Image calls S'Put_Image passing Arg 
(which will typically store a sequence of character values in a text 
buffer) and then returns the result of retrieving the contents of that 
buffer with function Get. The lower bound of the result is one. [Any 
exception propagated by the call of S'Put_Image is propagated.]
X'Wide_Wide_Image
{
AI12-0124-1} 
{
AI12-0020-1} 
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
{
AI12-0124-1} 
{
AI12-0020-1} 
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
{
AI12-0124-1} 
{
AI12-0020-1} 
X'Image denotes the result of calling function S'Image with 
Arg 
being X, where S is the nominal subtype of X. 
 
Implementation Permissions
{
AI12-0020-1} 
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 M of a component value or index value is a space, 
and the immediately preceding character (if any) is an open parenthesis, 
open bracket, or space, then the leading space of the image M 
may be omitted. 
Discussion: 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.
Discussion: 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.
 
Discussion: 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.
Discussion: This means that it is permitted 
to generate "(F1 | F2 => TRUE)" instead of "(F1 
=> TRUE, F2 => TRUE)". 
{
AI12-0020-1} 
{
AI12-0340-1} 
{
AI12-0384-2} 
Additional spaces (Wide_Wide_Characters with position 32), and calls 
to the New_Line operation of a text buffer, may be inserted to improve 
readability of the generated image, with the spaces inserted directly 
or via use of the Increase_Indent and Decrease_Indent procedures.
 
{
AI12-0384-2} 
For a string type, implementations may produce an image corresponding 
to a string literal. 
 
Ramification: {
AI22-0005-1} 
Not all values of a string type can be displayed 
this way. If the value of some component of the array argument is not 
that of a defining_character_literal of the component type of the string 
type component type, then no such “corresponding to a string literal” 
image exists. Similarly, no extension to the string literal syntax is 
intended; if the value of some component of the array argument is not 
a graphic_character, no such “corresponding to a string literal” 
image exists.  
{
AI12-0384-2} 
For an unchecked union type, implementations may raise Program_Error 
or produce some recognizable image (such as "
(UNCHECKED UNION)") 
that does not require reading the discriminants. 
 
{
AI12-0304-1} 
For each language-defined nonscalar type T, T'Put_Image may be specified.
 
Discussion: This permission applies, 
in particular, to nonscalar types declared in language-defined generic 
packages, and to any language-defined private type, even if an implementation 
chooses to complete it as a scalar type. 
Ramification: For any language-defined 
scalar type T, T'Put_Image should not be specified; the Image attribute 
needs to return the language-defined image for such types. This is important 
for compatibility: the Image attribute has been available for scalar 
types for many Ada revisions, and programs can (and do!) depend on its 
behavior. 
Implementation Requirements
{
AI12-0304-1} 
For each language-defined container type T (that is, each of the Vector, 
List, Map, Set, Tree, and Holder types defined in the various children 
of Ada.Containers), T'Put_Image shall be specified so that T'Image produces 
a result consistent with array aggregate syntax (using '[' and ']' as 
delimiters) as follows:
 
Vector images shall be consistent with the default 
image of an array type with the same index and component types.
Discussion: In particular, this means 
that the format is 	that of a named array aggregate. We have no recommendation 
on how to 	handle empty elements; if the implementation can identify 
them, it may 	wish to display them specially, but otherwise, they're 
just 	uninitialized elements. 
Map images shall be consistent with named array 
aggregate syntax, using key value images in place of discrete choice 
names. For example, [Key1 => Value1, Key2 => Value2].
Discussion: There is no recommendation 
about the order in which key/element pairs occur within a map image. 
In the case of multiple key values whose corresponding element values 
have the same image, there is no recommendation about factoring (that 
is, generating Key1 | Key2 => Some_Value instead of Key1 
=> Some_Value, Key2 => Some_Value). 
Set, List, and Holder images shall be consistent 
with positional array aggregate syntax. List elements shall occur in 
order within an image of a list. The image of an empty holder shall be 
[].
Discussion: There is no recommendation 
about the order in which set elements occur within the image of a set. 
Tree images (and images of subtrees of trees) shall 
be consistent with positional array aggregate syntax. For example, [[1, 
2], [111, 222, 333]].
{
AI12-0304-1} 
For each language-defined nonscalar type T that has a primitive language-defined 
Image function whose profile is type conformant with that of T'Image 
(for example, Ada.Numerics.Float_Random.State has such an Image function), 
T'Put_Image shall be specified so that T'Image yields the same result 
as that Image function.
 
Implementation Advice
For each language-defined private type T, T'Image 
should generate an image that would be meaningful based only on the relevant 
public interfaces, as opposed to requiring knowledge of the implementation 
of the private type.
Implementation Advice: For each language-defined 
private type T, T'Image should generate an image that would be meaningful 
based only on the relevant public interfaces.
Extensions to Ada 2012
Inconsistencies With Ada 2022
{
AI22-0118-1} 
Corrigendum: Fixed the definition of the 
default implementation of Put_Image for an untagged derived type with 
a known_discriminant_part, 
so that result doesn't display discriminants that are nonexistent (the 
discriminants of the parent type). This changes the default implementation 
of Put_Image for such types; a program could depend upon the incorrect 
display, although this seems very unlikely, as Put_Image is a new Ada 
2022 and untagged derived types with a known_discriminant_part 
are rare.  
Wording Changes from Ada 2022
{
AI22-0088-1} 
Corrigendum: Clarified that the default 
implementation of Put_Image for type extensions does not respect privacy. 
{
AI22-0110-1} 
Corrigendum: Clarified that Put_Image cannot 
be specified for interface types. This might seem to be incompatible, 
but not only is the construct useless, the only known implementation 
of Put_Image gets an internal error when specifying Put_Image for an 
interface. It is safe to say that this has never happened in user code. 
{
AI22-0132-1} 
Corrigendum: Clarified the order that the 
default implementation of Put_Image for a composite type writes the individual 
components. We originally had a blanket rule which did not make sense 
for a multidimensional array, we now have individual rules for each case. 
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe