Version 1.1 of ai12s/ai12-0384-2.txt

Unformatted version of ai12s/ai12-0384-2.txt version 1.1
Other versions for file ai12s/ai12-0384-2.txt

!standard 4.10(0)          20-10-14 AI12-0384-2/01
!class Amendment 20-10-14
!status work item 20-10-14
!status received 20-10-09
!priority Low
!difficulty Medium
!subject Fixups for Put_Image and Text_Buffers
!summary
Add operations to associate with a Text_Buffer an adjustable level of indentation. Eliminate the End_Of_Line function. Add operations for putting and getting the content of the Text_Buffer as a UTF_8 String or as a UTF_16 Wide_String. Provide functions Get, Wide_Get, and Wide_Wide_Get rather than procedures for retrieving the whole buffer to match what is needed by '*_Image, with implementation-defined substitutions in Get and Wide_Get for unrepresentable characters, as appropriate for 'Image and 'Wide_Image (intended to match Ada 2012 implementation-defined behavior for things like Enum'Image and Wide_Character'Image).
Move the various Get routines to the child packages, as they are not needed in the root package. Remove the requirement to raise Constraint_Error on buffer overflow in the Bounded child, and instead provide a query function to determine whether the buffer overflowed.
Allow Put_Image on an Unchecked Union. Give implementors a bit more flexibility about whether to support Put_Image on types on which Text_Buffers themselves depend. Clarify that T'Put_Image on a private type breaks privacy, and displays the same thing that the full type would display.
!problem
As part of implementing the Put_Image attribute (AI12-0020-1) and the Text_Buffers package (AI12-0340-1), a certain number of issues were identified with the proposed features. In particular:
(1) Defining the Put_Image for a composite type is likely to result in multiple lines of output. It seems highly desirable that such output is reasonably indented, to reflect the nesting of components and subcomponents. As currently defined the Put_Image attribute takes only the Text_Buffer and the value whose image is to be produced. If we want to provide some level of indenting, we need to incorporate into the Text_Buffer some notion of a current level of indentation.
(2) The Get and Wide_Get procedures currently produce implementation-defined results when the characters are not representable directly as Character or Wide_Character, respectively. But what we really need are functions to be used by 'Image and 'Wide_Image, because the implementation-defined substitutions might involve multiple characters replacing what was a single original character, at least in some implementations. There also seems no need for these Get functions in the Root_Buffer_Type, so we move them to the child packages Unbounded and Bounded.
(3) It would also be useful if UTF_8 and UTF_16 could be used for filling and emptying Text_Buffers, since we anticipate that many implementations will use UTF_8 or UTF_16 internally for representing identifiers in their symbol tables, and perhaps also for the characters in a Text_Buffer. This can also make the process "loss-less" while permitting efficient internal representation.
(4) There seems no particular advantage in having the Put procedures of the Bounded child package raise Constraint_Error on buffer overflow. A more common use-case is to want the buffer to silently stop storing characters, but keep a flag to indicate that an overflow occurred, so perhaps an ellipsis ("...") could be displayed at the end. Any Put_Image routine could check the flag should it so choose, and any user of a Bounded buffer could raise an exception after any call on Put_Image that produced an overflow situation.
(5) Providing a "peek-ahead" capability via End_Of_Line for a newline character sequence is not particularly useful unless characters are being removed from the buffer one character at a time. And even then, other "peek-ahead" would also be needed (e.g. for white space, commas, brackets, etc.) to do any sort of complex parsing as might be required by a general 'Value implementation.
(6) An AARM note says that Put_Image on an Unchecked_Union will raise Program_Error. It might be nice if some other behavior were permitted.
!proposal
(1) We propose to add indentation to the root interface, because it is not easy to add indentation in an extension, given that the various Put_Image routines are only passed Root_Buffer_Type'Class. We propose a Current_Indent function, and Increase/Decrease_Indent procedures, as primitives, which determine how many spaces are inserted at the beginning of the buffer, and at the beginning of each nonempty line.
(2) We replace the the Get, Wide_Get, and Wide_Wide_Get procedures with Get, Wide_Get, and Wide_Wide_Get functions, which (in the case of Get and Wide_Get) provide backward-compatible implementation-defined substitutions for unrepresentable characters, as appropriate for 'Image and 'Wide_Image.
(3) We add Get/Put_UTF_8 and Wide_Get/Put_UTF_16 operations.
(4) We provide a Buffer_Overflowed function for checking the state of a Bounded buffer.
(5) We remove the End_Of_Line function. We leave for future standardization sufficient peek-ahead functions to support 'Value or similar lexing and parsing uses of Text_Buffers.
(6) We give an implementation permission for the default Put_Image for an unchecked union to produce a recognizable string rather than raise Program_Error.
!wording
Modify 4.10 (7/5):
where the Wide_Wide_String value written out to the [stream]{text buffer} is defined as follows:
Modify AARM 4.10(13.a/5):
In general, the default implementation of T'Put_Image for a composite type will involve some sequence of calls to [Wide_Wide_String'Write] {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 [Wide_Wide_String'Write]{Put} 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).
Modify 4.10(16/5):
For a class-wide type, the default implementation of T'Put_Image generates an image based on qualified expression syntax. [Wide_Wide_String'Write] {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.
Add after 4.10 (23/5):
Redundant[T'Put_Image is the same for both the partial view and full view of T, if T has a partial view.]
AARM Proof: A type-related operational aspect is the same for the full view and partial view of a type. See 13.1.
Modify 4.10 (25.2/5):
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.
Modify 4.10 (28/5):
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.
Modify 4.10 (31/5):
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.
Modify 4.10 (41/5):
* 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_ and Decrease_Indent procedures.
Add after 4.10 (41/5):
* For a string type, implementations may produce an image corresponding to a string literal.
* 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.
Replace A.4.12 (3/5-25/5) with the following:
with Ada.Strings.UTF_Encoding.Wide_Wide_Strings; package Ada.Strings.Text_Buffers with Pure is
type Text_Buffer_Count is range 0 .. /implementation-defined/;
New_Line_Count : constant Text_Buffer_Count := /implementation-defined/;
type Root_Buffer_Type is abstract tagged limited private with Default_Initial_Condition => Current_Indent (Root_Buffer_Type) = 0;
procedure Put ( Buffer : in out Root_Buffer_Type; Item : in String) is abstract;
procedure Wide_Put ( Buffer : in out Root_Buffer_Type; Item : in Wide_String) is abstract;
procedure Wide_Wide_Put ( Buffer : in out Root_Buffer_Type; Item : in Wide_Wide_String) is abstract;
procedure Put_UTF_8 ( Buffer : in out Root_Buffer_Type; Item : in UTF_Encoding.UTF_8_String) is abstract;
procedure Wide_Put_UTF_16 ( Buffer : in out Root_Buffer_Type; Item : in UTF_Encoding.UTF_16_Wide_String) is abstract;
procedure New_Line (Buffer : in out Root_Buffer_Type) is abstract;
Standard_Indent : constant Text_Buffer_Count := 3;
function Current_Indent (Buffer : Root_Buffer_Type) return Text_Buffer_Count;
procedure Increase_Indent (Buffer : in out Root_Buffer_Type; Amount : in Text_Buffer_Count := Standard_Indent) with Post'Class => Current_Indent (Buffer) = Current_Indent (Buffer)'Old + Amount;
procedure Decrease_Indent (Buffer : in out Root_Buffer_Type; Amount : in Text_Buffer_Count := Standard_Indent) with Pre'Class => Current_Indent (Buffer) >= Amount or else raise Constraint_Error, Post'Class => Current_Indent (Buffer) = Current_Indent (Buffer)'Old - Amount;
private ... -- not specified by the language end Ada.Strings.Text_Buffers;
package Ada.Strings.Text_Buffers.Unbounded with Preelaborate, Nonblocking, Global => null is
type Buffer_Type is new Root_Buffer_Type with private;
function Get ( Buffer : in out Buffer_Type) return String with Post'Class => Get'Result'First = 1 and then Current_Indent (Buffer) = 0;
function Wide_Get ( Buffer : in out Buffer_Type) return Wide_String with Post'Class => Wide_Get'Result'First = 1 and then Current_Indent (Buffer) = 0;
function Wide_Wide_Get ( Buffer : in out Buffer_Type) return Wide_Wide_String with Post'Class => Wide_Wide_Get'Result'First = 1 and then Current_Indent (Buffer) = 0;
function Get_UTF_8 ( Buffer : in out Buffer_Type) return UTF_Encoding.UTF_8_String with Post'Class => Get_UTF_8'Result'First = 1 and then Current_Indent (Buffer) = 0;
function Wide_Get_UTF_16 ( Buffer : in out Buffer_Type) return UTF_Encoding.UTF_16_Wide_String with Post'Class => Wide_Get_UTF_16'Result'First = 1 and then Current_Indent (Buffer) = 0;
private ... -- not specified by the language, ... -- but will include nonabstract overridings of all ... -- inherited subprograms that require overriding. end Ada.Strings.Text_Buffers.Unbounded;
package Ada.Strings.Text_Buffers.Bounded with Pure is
type Buffer_Type (Max_Characters : Text_Buffer_Count) is new Root_Buffer_Type with private with Default_Initial_Condition => not Buffer_Overflowed (Buffer_Type);
function Buffer_Overflowed (Buffer : in Buffer_Type) return Boolean;
-- Get, Wide_Get, Wide_Wide_Get, Get_UTF_8, and Wide_Get_UTF_16 -- are declared here just as in the Unbounded child.
private ... -- not specified by the language, ... -- but will include nonabstract overridings of all ... -- inherited subprograms that require overriding. end Ada.Strings.Text_Buffers.Bounded;
Modify A.4.12 (27/5):
New_Line stores New_Line_Count characters that represent a new line into a text buffer. [End_of_Line returns True if the next characters to be retrieved from the text buffer represent a new line.] {Current_Indent returns the current indentation associated with the buffer, with zero meaning there is no indentation in effect; Increase_Indent and Decrease_Indent increase or decrease the indentation associated with the buffer.}
Modify A.4.12 (28/5):
A call to Put, Wide_Put, [or] Wide_Wide_Put{, Put_UTF_8, or Wide_Put_UTF_16} stores a sequence of characters into the text buffer{, preceded by Current_Indent(Buffer) spaces (Wide_Wide_Characters with position 32) if there is at least one character in Item and it would have been the first character on the current line}.
Modify A.4.12 (29/5):
A call to {function} Get, Wide_Get, [or] Wide_Wide_Get{, Get_UTF_8, or Wide_Get_UTF_16} returns the same sequence of characters as was present in the calls that stored the characters into the buffer{, if representable}. For a call to Get, if any character in the sequence is not defined in Character, the result is implementation defined. Similarly, for a call to Wide_Get, if any character in the sequence is not defined in Wide_Character, the result is implementation defined. {As part of a call on any of the Get functions, the buffer is reset to an empty state, with no stored characters.}
Add after A.4.12
In the case of a Buf of type Text_Buffers.Bounded.Buffer_Type, Buffer_Overflowed (Buf) returns True if the various Put procedures together have attempted to store more than Buf.Max_Characters into Buf. If this function returns True, then the various Get functions return a representation of only the first Buf.Max_Characters characters that were stored in Buf.
Modify H.4(23.e/5):
Implementation Note: [Assuming the Implementation Advice is followed, t]{T}his can be accomplished by using an object of the Text_Buffers.Bounded.Buffer_Type with the maximum characters as specified in the Max_Image_Length restriction{, with a raise of Program_Error afterward if Buffer_Overflowed (Buf) is True after the call on Put_Image (Buf, Arg)}.
!discussion
See !problem and !proposal.
We have added a reminder that private types have the same implementation of Put_Image as their full type. Another choice would be to say that Put_Image is not defined on a private type unless explicitly provided, though that would clearly make composability more of a pain, analogous to what happens with 'Write on limited types. Clearly any implementor of a private type should specify Put_Image if they are concerned about the loss of information hiding. For compatibility reasons we can't really change what Put_Image does on the full type, and making the run-time semantics of Put_Image depend on where you invoke it seems like a generally bad idea (as well as requiring defining a new kind of aspect with its own set of rules).
One could imagine other rules, such as hiding 'Image, but not hide 'Put_Image, on a private type. But there is nothing in the default 'Image that can't be learned from reading the specification of the private type, so the benefit would come from having results of 'Image not be affected by changes to the implementation of the private type. Users with a need for stable image results can define their own Put_Image to avoid such output instability.
We decided to have operations on the Bounded Buffer_Type set the Buffer_Overflowed flag rather than raise Constraint_Error, but the user of the buffer can just as easily use a pragma Assert (not Buffer_Overflowed (Buf)) afterward. To exactly specify the conditions when Constraint_Error would be raised would significantly complicate the interface, and not really provide any more safety. It would also interfere with a common situation where if an Image exceeds a maximum desired length, you are willing to use ellipses ("...") to indicate overflow.
As mentioned in the !proposal, although the original goals might have included supporting 'Value, we are no longer trying to support the implementation of user-defined 'Value operations with the current Text_Buffers. We believe a number of other operations would be needed to support the kind of parsing that would be needed for complex 'Value operations. We leave that for a future standard.
We considered providing a Character_Count function, to support this sort of use case:
X : constant Text_Buffer := (Length => Character_Count (Buf), Data => Get (Buf));
but alas each of the various *_Get functions might produce a different length array, so rather than having five separate *_Character_Count functions, we recommend the use of a local rename of the call:
Chars : String renames Get (Buf); X : constant Text_Buffer := (Length => Chars'Length, Data => Chars);
One interesting side issue with the example above is that as written the first aggregate could violate RM 6.4.1(6.18/3-6.19/3), because Get takes Buf as an in in-out parameter, and the result would depend on whether Character_Count were called before after the call on Get. But it is actually OK because presumably Length is a discriminant and Data has a per-object constraint, meaning that the expression defining Data isn't evaluated until after Character_Count returns (see RM 4.3.1(19/5)).
!ASIS
No ASIS effect.
!ACATS test
An ACATS C-Test is needed to check the various subprograms and the image attributes are implemented as expected.
!appendix

From: Tucker Taft
Sent: Friday, October 9, 2020  3:18 PM

Here is a new version of AI12-0384 (-2 version), which is a fixup relative 
to draft 26 of the Ada 202X RM 
(http://www.ada-auth.org/standards/2xaarm/html/AA-A-4-12.html).
[This is draft /01 of the AI - Editor.]

This version received a tentative "thumbs up" from Randy and Raphaël. We will 
be considering this AI for approval at the upcoming ARG meeting October 21st.

Main simplifications relative to prior version of AI12-0384 (-1 version) include: 

* eliminating all *Get procedures in favor of functions (which were all moved 
  into the Unbounded/Bounded children as they were not needed by Put_Image 
  itself);
* eliminating user control over character substitutions, with Get for String 
  and Wide_Get for Wide_String incorporating whatever substitutions 
  implementations do now for 'Image and 'Wide_Image;
* eliminating Position_In_Line as that was felt too "pretty print-ish"
* eliminating Constraint_Error on overflow in Text_Buffers.Bounded (and 
  associated Pre aspects) in favor of a "Buffer_Overflowed" flag which can be 
  tested after Put_Image;
* eliminating Character_Count function.

Additions relative to the draft 26 of the Ada 202x RM (most were already in 
AI12-0384-1) include:

* Indentation control
* Put/Get_UTF_8 and Wide_Put/Get_UTF_16
* Buffer_Overflowed flag (mentioned above) in Bounded child

Rather than showing piecemeal changes to the package specs, I included a 
complete new set of specs in this AI, to ease readability.

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

From: Arnaud Charlet
Sent: Saturday, October 10, 2020  2:57 PM

> Here is a new version of AI12-0384 (-2 version), which is a fixup relative
>  to draft 26 of the Ada 202X RM 
> (http://www.ada-auth.org/standards/2xaarm/html/AA-A-4-12.html).
> 
> This version received a tentative "thumbs up" from Randy and Raphaël.  We 
> will be considering this AI for approval at the upcoming ARG meeting 
> October 21st.

Thanks for moving things forward.

> Main simplifications relative to prior version of AI12-0384 (-1 version) 
> include: 
> 
> * eliminating all *Get procedures in favor of functions (which were 
> all moved into the Unbounded/Bounded children as they were not needed 
> by Put_Image itself);

I don't see a realistic use case for the bounded version, so am in favor of 
removing the bounded part. The rest looks OK at first sight, I need to look 
deeper into it.

Note that if a real use case is found by actual users for a bounded version, 
we can always add it later, while removing something once it's standardized 
is much more difficult.

We can discuss it live but my understanding is that the bounded version is 
meant for constrained embedded targets where memory allocation is difficult.

But these same constrained environments already do not support 
wide_wide_characters and do not support all the runtime support needed by 
Put_Image. In other words, these constrained environment will not benefit from 
the Put_Image feature in the first place which is very heavy in terms of 
runtime support. The less constrained embedded environments which can afford 
the whole Put_Image support can also afford the unbounded version.

Ergo, the bounded version isn't needed and is only adding complexity.

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

From: Richard Wai
Sent: Saturday, October 10, 2020  11:57 AM

> I don't see a realistic use case for the bounded version, so am in favor
> of removing the bounded part. The rest looks OK at first sight, I need to
> look deeper into it.

I do sympathize with your argument here, but to play devil's advocate: I 
think there can be real use-cases for the bounded case in the non-embedded 
domain. I see three primary (and complimentary) lines of reasoning. One is 
security; since we're talking about user-defined Image attributes, it is 
very possible that the output of a given 'Image may be dependent on some 
external input, or combination of inputs, and might be quite complex. There 
are plenty of DoS attacks regimens that can take advantage of unbounded 
memory allocation through these kind of avenues. Bounded types are really 
good at protecting against this class of attack. The other line is 
performance. Bounded types of high variability and long lifetimes, statically 
or dynamically allocated, can improve cache tenancy. Thirdly, and related to 
the second, for very high-volume and/or long-lived systems, bounded types can
potentially help reduce memory fragmentation, particularly when such a 
program is designed to use mostly bounded types and near-program-lifetime 
allocations.

Admittedly these are very specific and narrow use-cases, so I accept that it 
is not the strongest argument.

However there is also the argument for consistency. Ada tends to provide 
Unbounded/Bounded for these kinds of language-defined types/packages. For me 
personally, that is possibly a stronger argument for the bounded case than 
the above. 

> Note that if a real use case is found by actual users for a bounded version,
> we can always add it later, while removing something once it's standardized
> is much more difficult.

I could make the case that we are an "actual user" (we do often use bounded 
types for security and performance reasons), but this is a discussion we've 
had before, and might not see eye-to-eye on. I will reiterate for the record,
that Ada users are a superset of FSF GNAT users, who are a superset of AdaCore
users. So I think there should be caution using this as an argument against 
including the Bounded case.

> Ergo, the bounded version isn't needed and is only adding complexity.

I'm not convinced the bounded case would be overly complex to implement.

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

From: Arnaud Charlet
Sent: Saturday, October 10, 2020  12:20 PM

> I do sympathize with your argument here, but to play devil's advocate: 

OK, it's fun and fair game to play devil's advocate.

So now that you've done that: are you convinced by your devil's advocate 
arguments? :-)

> I could make the case that we are an "actual user" (we do often use 
> bounded types  for security and performance reasons), but this is a 
> discussion we've had before, and might not see eye-to-eye on. I will 
> reiterate for the record, that Ada users are a superset of FSF GNAT 
> users, who are a superset of AdaCore users.

I'm afraid that's wishful thinking when it comes to Ada 2020 where all users 
will be GNAT users.

> > Ergo, the bounded version isn't needed and is only adding complexity.
> 
> I'm not convinced the bounded case would be overly complex to implement.

I'm talking added complexity: anything extra we add does add complexity and 
better be well justified and worth it. I don't see that as being the case here 
and furthermore it's very easy to let implementation freedom here if users 
indeed do actually need this feature in the future without dictating before
hand without a real(istic) use case.

Frankly in terms of library, we'd better spend our time on other things, 
starting with providing real string (UTF8) manipulation routines as can be 
found in all other languages and as badly missing to many users, as well as 
many other generally useful libraries rather than added a bounded version of 
text_buffer for Put_Image.

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

From: Richard Wai
Sent: Saturday, October 10, 2020  12:41 PM

> So now that you've done that: are you convinced by your devil's 
> advocate arguments? :-)

Yes. I think they are stronger arguments for bounded than yours against, to be 
explicit.

> I'm afraid that's wishful thinking when it comes to Ada 2020 where all users
> will be GNAT users.

Enjoy that while it lasts!

In any case it is dangerous to make language design decisions based on the 
(possibly naive) declaration of dominance by a single vendor.

I don't see why AdaCore can't just leave the bounded case out of their 
implementation - this is a route that has already been taken with parallel.

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

From: Arnaud Charlet
Sent: Saturday, October 10, 2020  1:01 PM

> I don't see why AdaCore can't just leave the bounded case out of their 
> implementation - this is a route that has already been taken with parallel.

That's indeed what we'll likely do if we can't agree although that's certainly 
not our preferred option, it's not like we enjoy leaving Ada 202x features 
out, we're only doing it for good reasons.

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

From: Jean-Pierre Rosen
Sent: Saturday, October 10, 2020  12:41 PM

> I'm afraid that's wishful thinking when it comes to Ada 2020 where all 
> users will be GNAT users.
I am extremely concerned by that statement.
1) PTC has an Ada 2012 compiler, and might want to keep up
2) It would be extremely harmful to Ada to consider that anyway, it's just
   AdaCore's private language.

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

From: Arnaud Charlet
Sent: Saturday, October 10, 2020  1:03 PM

> I am extremely concerned by that statement.
> 1) PTC has an Ada 2012 compiler, and might want to keep up

Right, and perhaps the ARG should ask them on their view on this feature.

> 2) It would be extremely harmful to Ada to consider that anyway, it's 
> just AdaCore's private language.

If it were AdaCore's private language we wouldn't be discussing here.
Ada is clearly an official and ISO language and that's a great property.

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

From: Tucker Taft
Sent: Saturday, October 10, 2020  4:14 PM

The Bounded child is used when the Max_Image_Length restriction is in place.  
See Ada 202X RM H.4(23.20/5) and H.4(23.e/5).  If AdaCore chooses not to 
support that restriction, then they could also choose not to support the 
Bounded child, I suppose.

In my experience it is pretty frequent to want to bound the output, 
particularly for debugging, but also for cases when producing some kind of 
user-oriented message where messages beyond a certain length are not user 
friendly.  CodePeer, for example, does this in several places.  So it isn't 
just for resource-constrained environments.

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

From: Arnaud Charlet
Sent: Sunday, October 11, 2020  12:59 PM

> The Bounded child is used when the Max_Image_Length restriction is in place.
> See Ada 202X RM H.4(23.20/5) and H.4(23.e/5).  If AdaCore chooses not to 
> support that restriction, then they could also choose not to support the 
> Bounded child, I suppose.

OK. So what about we move the Bounded child to annex H then since the two 
indeed go together?

> In my experience it is pretty frequent to want to bound the output, 
> particularly for debugging, but also for cases when producing some kind of 
> user-oriented message where messages beyond a certain length are not user 
> friendly.  CodePeer, for example, does this in several places.  So it isn't
> just for resource-constrained environments.

OK but in this case, you can produce that with the unbounded version, you 
don't need a bounded version for that, and you will in general want to have a 
smart truncate at the proper place rather than at a random upper bound.

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

From: Tucker Taft
Sent: Sunday, October 11, 2020  1:11 PM

>> The Bounded child is used when the Max_Image_Length restriction is in 
>> place.  See Ada 202X RM H.4(23.20/5) and H.4(23.e/5).  If AdaCore chooses 
>> not to support that restriction, then they could also choose not to support 
>> the Bounded child, I suppose.
> 
> OK. So what about we move the Bounded child to annex H then since the 
> two indeed go together?

It seems like we are making this overly complicated.  The point is to 
establish a standard, and the Bounded child has value beyond 
safety-critical systems.  Implementing this child is pretty trivial.  The 
point is to have a standard rather than having everyone reinventing the 
wheel in slightly different ways.

>> In my experience it is pretty frequent to want to bound the output, 
>> particularly for debugging, but also for cases when producing some kind of 
>> user-oriented message where messages beyond a certain length are not user 
>> friendly.  CodePeer, for example, does this in several places.  So it isn't
>> just for resource-constrained environments.
> 
> OK but in this case, you can produce that with the unbounded version, 
> you don't need a bounded version for that, and you will in general 
> want to have a smart truncate at the proper place rather than at a random 
> upper bound.

Not sure what you mean by a random upper bound.  Anyone who declares their own 
Bounded buffer object can specify their own upper bound by specifying the 
discriminant.  

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

From: Brad Moore
Sent: Tuesday, October 13, 2020  10:44 AM

I think what Arno is suggesting, or at least is a feature I have been thinking
about, is that, for an object like a container, one might want to limit the 
output to N container elements (followed by an ellipsis), rather than using 
the bounded container limit, which might be difficult for the user to 
anticipate how to translate a bounded buffer size into nicely aligned output. 
What you would likely see is that the container output is truncated randomly 
in the middle of an element output, particularly if the element is a 
composite object, which would be undesirable.

I am wondering if somehow an element limit could be incorporated into the 
interface, perhaps as an aspect, rather than relying on the bounded buffer
size to clip the results.

e.g. for a container of fruit, with "Element_Limit" set to 3, might produce 
the string, '("Banana", "Pear", "Apple", ...)'
This would work nicely and consistently for a bounded or unbounded text 
buffer. If the Fruit component is later modified to change the size of the 
component, it won't affect the output, whereas when using a bounded text 
buffer to limit the output, this likely would affect the output.

Alternatively, or in addition, a subprogram of the container could be provided 
to set the element limit.

I also think with respect to containers, there are two "views" one might want 
to present. If one cares about the inner workings of the container, and wants 
to see the details of the container object itself, (e.g. for a hash table, all
the buckets and bucket contents, etc) one might want to present a "verbose" 
view. However, if one isn't debugging the container, (most likely the typical
case) and is only interested in the elements that the container holds, a 
verbose=false would be useful, which would produce ouytput like the fruit 
container output above.
 
So perhaps a Verbose aspect would be useful here as well.
But Again, alternatively or in addition, a subprogram of the container could 
be provided to set the verbose flag. 

I am not sure if these are things that should be left for a future standard 
version, or should be considered now while we are hammering out the details 
of this interface.

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

From: Tucker Taft
Sent: Tuesday, October 13, 2020  4:13 PM

I can see some value for this, but it would be adding significant complexity, 
given that you could have containers within containers, or arbitrary tree 
structures.  At this point we are trying to provide basic functionality with
a relatively simple interface, not make the interface even more complex.  In
my experience, in many applications it makes sense to just chop, or 
potentially chop back to some punctuation.  Anything more complex than that 
is generally quite application and data-structure specific.

In an interactive graphical user interface, you can expand and contract 
individual levels, but that is not what we are talking about here.

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

From: Brad Moore
Sent: Tuesday, October 13, 2020  11:16 PM

For what it's worth, Python has this capability, which is described in their 
main tutorial here, in their tutorial section on output formatting.

    https://docs.python.org/3/tutorial/stdlib2.html#output-formatting

See the first two examples, which are similar to the capabilities that we are 
providing in this AI.

Their approach is that there is a default element limit that gets applied to 
container classes. So the setting would apply recursively to containers within
containers.

So the interface for this seems like it could potentially be very simple. 
Perhaps the interface would just be a procedure, aspect, or configuration 
pragma to override the default, e.g.  Set_Max_Image_Element_Count ( Count 
:= 0), where the default of zero is unlimited (except by other limits such
as bounded buffer size). Otherwise, the exposed interface to support this 
would be exactly as you have already described in the AI. Implementations 
could perhaps choose not to support the Set_Max_Image_Element_Count 
procedure, if the implementation burden for that is too significant, I 
suppose. 

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

From: Randy Brukardt
Sent: Tuesday, October 13, 2020  11:52 PM

Well, you'd certainly have to have a way to *read* the value (else how could 
a Put_Image routine use it?), and moreover, to make it useful you'd have to 
have a use of it for the default image for all (or at least nearly all) 
composite types (it makes no sense to treat containers and arrays differently, 
unclear what it should mean for records). Not that many people are going to be 
writing their own Put_Image implementations.

If it only applied to user-defined Put_Image routines, then there isn't any 
reason to include it in the Standard, since the user can just as well define 
their own extension of the Text_Buffer to include whatever extra features they
need. (Some people seem to expect that to be common; I don't, but either way 
it would seem to be premature standardization to define such features ONLY for 
user-defined routines.)

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

Questions? Ask the ACAA Technical Agent