Version 1.3 of ai12s/ai12-0329-1.txt

Unformatted version of ai12s/ai12-0329-1.txt version 1.3
Other versions for file ai12s/ai12-0329-1.txt

!standard 13.13.1(9/5)          19-04-09 AI12-0329-1/02
!standard 13.13.1(9.1/5)
!class Amendment 19-04-05
!status Amendment 1-2012 19-04-09
!status ARG Approved 9-0-2 19-04-09
!status work item 19-04-05
!status received 19-04-03
!priority Low
!difficulty Easy
!subject Naming of FIFO_Streams packages
!summary
The package family is named Storage, with children Unbounded and Bounded. The abstract type is named Storage_Stream_Type.
!problem
The FIFO_Streams packages seem misnamed:
(1) There's nothing about the interface that limits it to FIFO operations. It is limited to in-memory operations, so perhaps that property should be emphasized with the name. Additionally, a Stream is inherently FIFO, so its weird to emphasize that property.
(2) The use of Unbounded_<something> is inconsistent with the names used for the containers.
(3) Repeating "Streams" in the package names is also inconsistent with the containers (we don't have packages "Vector_Container" and "Tree_Container").
Also, the type FIFO_Stream is inconsistent with the naming of other language-defined stream types, which all end with "Stream_Type".
!proposal
(See Summary.)
!wording
The root package of this subsystem is called
Ada.Streams.Storage
with a type
Storage_Stream_Type
There are two child packages, Ada.Streams.Storage.Unbounded and Ada.Streams.Storage.Bounded. The type names in the children are not changed; they remain Stream_Type.
See !corrigendum below for the detailed wording changes.
!discussion
"Unbounded_String" is an exception to the meta-rule that we don't use "Unbounded" in names, but that clearly couldn't have been called "String", so some other name was required.
We orginally proposed:
Ada.Streams.Storage
Storage_Stream_Type Ada.Streams.Storage.FIFO
Stream_Type
Ada.Streams.Storage.Bounded_FIFO
Stream_Type
But that was ultimately rejected as a stream is inherently FIFO, so that also is redundant information. Once we drop that, we have no name for the concrete child implementation level at all. It doesn't add anything, since the parent defines the necessary details. Thus, we dropped back to the Unbounded and Bounded names without any qualification.
Ideally, the names chosen for language-defined packages would work well for both the use-adverse and the use-lovers of the Ada community. Note that everyone has to write the full expanded package name in the context clause, so shorter, less redundant names help everyone. It does pay to repeat some information in the type names, as use-lovers will not have any context to make the name clear.
E-Mail discussions seemed to settle on naming this family of packages "Storage" in some way, based on the existing Storage_IO package.
We also need to consider the type names, particularly of the abstract type.
Some people preferred to repeat Stream in each of the package names. Your author thinks this is rather redundant (he's sick and tired of having to write Ada.Strings.Unbounded_Strings.Unbounded_String, and this would be worse), but for the record:
Ada.Streams.Storage_Streams
Storage_Stream_Type Ada.Streams.Storage_Streams.FIFO_Streams
Stream_Type
Ada.Streams.Storage_Streams.Bounded_FIFO_Streams
Stream_Type
We also considered "Buffers" rather than "Storage" (but Ada already uses "Storage" for this use),
!corrigendum 13.13.1(9)
Insert after the paragraph:
The Write operation appends Item to the specified stream.
the new paragraphs:
Three additional packages provide stream implementations that do not make use of any file operations. These packages provide the same operations, with Streams.Storage providing an abstract interface, and two child packages providing implementations of that interface. The difference is that for Streams.Storage.Bounded, the maximum storage is bounded.
The library package Ada.Streams.Storage has the following declaration:
package Ada.Streams.Storage with Pure, Nonblocking is
type Storage_Stream_Type is abstract new Root_Stream_Type with private;
function Element_Count (Stream : Storage_Stream_Type) return Stream_Element_Count is abstract;
procedure Clear (Stream : in out Storage_Stream_Type) is abstract;
private ... -- not specified by the language end Ada.Streams.Storage;
The library package Ada.Streams.Storage.Unbounded has the following declaration:
package Ada.Streams.Storage.Unbounded with Prelaborated, Nonblocking is
type Stream_Type is new Storage_Stream_Type with private with Default_Initial_Condition => Element_Count (Stream_Type) = 0;
overriding procedure Read ( Stream : in out Stream_Type; Item : out Stream_Element_Array; Last : out Stream_Element_Offset) with Post => (declare Num_Read : constant Stream_Element_Count := Stream_Element_Count'Min (Element_Count(Stream)'Old, Item'Length); begin Last = Num_Read + Item'First - 1 and Element_Count (Stream) = Element_Count (Stream)'Old - Num_Read);
overriding procedure Write ( Stream : in out Stream_Type; Item : in Stream_Element_Array) with Post => Element_Count (Stream) = Element_Count (Stream)'Old + Item'Length;
overriding function Element_Count (Stream : Stream_Type) return Stream_Element_Count;
overriding procedure Clear (Stream : in out Stream_Type) with Post => Element_Count (Stream) = 0;
private ... -- not specified by the language end Ada.Streams.Storage.Unbounded;
The library package Ada.Streams.Storage.Bounded has the following declaration:
package Ada.Streams.Storage.Bounded with Pure, Nonblocking is
type Stream_Type (Max_Elements : Stream_Element_Count) is new Storage_Stream_Type with private with Default_Initial_Condition => Element_Count (Stream_Type) = 0;
overriding procedure Read ( Stream : in out Stream_Type; Item : out Stream_Element_Array; Last : out Stream_Element_Offset) with Post => (declare Num_Read : constant Stream_Element_Count := Stream_Element_Count'Min (Element_Count(Stream)'Old, Item'Length); begin Last = Num_Read + Item'First - 1 and Element_Count (Stream) = Element_Count (Stream)'Old - Num_Read);
overriding procedure Write ( Stream : in out Stream_Type; Item : in Stream_Element_Array) with Pre => Element_Count (Stream) + Item'Length <= Stream.Max_Elements or else (raise Constraint_Error), Post => Element_Count (Stream) = Element_Count (Stream)'Old + Item'Length;
overriding function Element_Count (Stream : Stream_Type) return Stream_Element_Count with Post => Element_Count'Result <= Stream.Max_Elements;
overriding procedure Clear (Stream : in out Stream_Type) with Post => Element_Count (Stream) = 0;
private ... -- not specified by the language end Ada.Streams.Storage.Bounded;
The Element_Count functions return the number of stream elements that are available for reading from the given stream.
The Read and Write procedures behave as described for package Ada.Streams above. Stream elements are read in FIFO (first-in, first-out) order; stream elements are available for reading immediately after they are written.
The Clear procedures remove any available stream elements from the given stream.
!corrigendum 13.13.1(9.1/1)
Insert after the paragraph:
If Stream_Element'Size is not a multiple of System.Storage_Unit, then the components of Stream_Element_Array need not be aliased.
the new paragraph:
Implementation Advice
Streams.Storage.Bounded.Stream_Type objects should be implemented without implicit pointers or dynamic allocation.
!ASIS
No change is needed.
!ACATS test
Any tests for the original AI (AI12-0293-1) would apply here as well.
!appendix

From: Randy Brukardt
Sent: Wednesday, April 3, 2019  1:43 AM

Brad's AARM Review says:

13.13.1 (12/5) package Ada.Streams.FIFO_Streams

I don't see why the same interface couldn't be used for other types of 
streams, such as LIFO_Streams. This suggests to me that the top-level 
abstract package is misnamed.

I think it would be much better to name the package as;

package Ada.Streams.Stream_Buffers

   or even better just as
   
package Ada.Streams.Buffers

which better captures that these streams are in-memory buffers (without file 
operations).

This truly is a restriction of the package, since the package is Nonblocking and 
cant be derived to be a Nonblocking=>False package, which would be needed to 
support file operations.

The FIFO property of the interface is just in-name only, since anyone could 
derive from these packages to create abstractions that are non-FIFO.

Then the two child packages could be named more specifically for FIFO 
semantics

package Ada.Streams.Buffers.Bounded_FIFO_Streams

and

package Ada.Streams.Buffers.FIFO_Streams

Which also is more consistent with the naming of the container packages, eg 
Bounded_Vectors, rather than just Bounded or Unbounded.

Also, we dont typically name packages with "Unbounded", there is no 
Unbounded_Vectors package, so with this renaming, we could remove "Unbounded" 
from the package name, to also be more consistent with the Ada Containers.

==================================

Generally, we don't revisit settled naming decisions. However, Brad makes some 
good points about the naming (especially about the generality of the base 
interface, and about the inconsistency with the naming of the containers).

I also admit that I've never felt that we had the right names for these 
packages, but I've stayed silent mainly because I don't have a better 
alternative. But now is the time to consider if different names would be 
better, as it will be too late before long.

As such, I'd like to take a poll to see if there is any will to discuss the 
names of these package again. The package names in the advisory list came from 
the ARG meeting where these names were chosen. It wouldn't surprise me if we 
ended up with some combination of names if we actually do discuss this.

[Editor's note: The actual poll and voting results are not provided here.]

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

From: Randy Brukardt
Sent: Wednesday, April 3, 2019  1:43 AM

> Comments: [on the poll ballot - Editor.]

Given that all of these packages are under "Streams", there isn't any need for 
the individual child names to include "Streams". Indeed, that's almost certain 
to be redundant noise. Even people who *love* use clauses have to give the 
entire name in the with clause and the use clause. And no one wants to write 
streams 3 or 4 times!

In particular, the vast majority of units will with only one of these 
packages, so the intermediate names don't matter much. Someone could "use"
Ada.Streams and then use the intermediate names in use clauses, I guess, but 
there wouldn't be much point (why save a handful of characters and make your 
program harder to understand?).

Thus, I prefer relatively short names are every level. For me, who would 
hardly ever "use" one of these packages, the less redundancy in the full 
name the better:

     My_Buffer : Ada.Streams.FIFO_Streams.Unbounded.Stream_Type; -- Current name: 3 Streams.

     My_Buffer : Ada.Streams.Storage.FIFO.Stream_Type; -- My write-in: 2 streams.

     My_Buffer : Ada.Streams.Buffers.FIFO_Streams.Stream_Type; -- Brad's name: 3 streams.

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

From: Steve Baird
Sent: Wednesday, April 3, 2019  5:42 PM

> Comments: [on the poll ballot - Editor.]

These comments may serve mostly as a reminder of why we don't want to reopen 
this discussion, but I'll press on nonetheless.

I agree with Brad that FIFO belongs as part of the names of the concrete 
packages, not as part of the name of the package that defines the abstract 
type. The thing that distinguishes the abstract type from its parent is the 
addition of the Element_Count operation (and the less important Clear 
operation), so I feel that Counted_Streams makes sense for that package.

It's been suggested that we want a name that indicates that no file operations 
are involved, but (as with the FIFO property) that isn't at all implied by the 
abstract interface and does not make sense for naming the package that declares
the abstract type. Thus, I don't like any of the Buffered_Streams or 
Storage_Streams proposals.

So I am left with only my write-in candidate to vote for.

There is more to this than changing the names of the packages: we have to look 
at the names of the stream types too. It wouldn't make sense, for example, to 
have a type
     Ada.Streams.Buffers.FIFO_Stream
which is what we would get if all we change is the package name.

So we really need a proposal for 3 package names and 3 stream type names . I 
don't like type names that end in "_Type" (e.g., Stream_Type), but just naming
all the types "Stream_Type" is an option. We have formal parameters named 
"Stream", so we don't want to use that name.

I often like plural package names where the package exports a type with a 
corresponding singular name, as in
     package Miniature_Cars is
        type Car is private;
        ...
     end Miniature_Cars;
or
    package Horses is
       type Horse is private;
       ...;
    end Horses;

So with the package names proposed above, the type names could be
    Counted_Streams.Counted_Stream
    Counted_Streams.FIFO_Streams.FIFO_Stream
    Counted_Streams.Bounded_FIFO_Streams.FIFO_Stream

(this proposal follows the example of Vectors and Bounded_Vectors with respect 
to using the same type name in the bounded and unbounded versions).

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

From: Randy Brukardt
Sent: Wednesday, April 3, 2019  6:13 PM

...
>It's been suggested that we want a name that indicates that no file 
>operations are involved, but (as with the FIFO property) that isn't at 
>all implied by the abstract interface ...

As Brad pointed, it *is* implied by the contracts, which surely are part of
the abstract interface. So I tend to disagree on this one. If we decided to
change the contracts so that external (blocking) stuff was allowed, then I'd
have more sympathy. (There's really no reason that the abstract stream has to
be Nonblocking; that's only a requirement of actual packages. Unless you think
that someone is going to try (in a nonblocking context) to dispatch through 
this interface rather than directly binding to the primitives of the specific 
types -- which seems silly for performance reasons alone.)

...
> There is more to this than changing the names of the
> packages: we have to look at the names of the stream types too. It 
> wouldn't make sense, for example, to have a type
>      Ada.Streams.Buffers.FIFO_Stream
> which is what we would get if all we change is the package name.

Agreed. I didn't realize that this was even the name of a type, it's clearly 
wrong regardless of any package naming. I suspect that I forgot to change that
name with the others. All other existing streams end with "_Stream_Type" (or 
are just "Stream_Type"), and consistency alone would say that it should at a 
minimum be "FIFO_Stream_Type".

> So we really need a proposal for 3 package names and 3 stream type 
> names . I don't like type names that end in "_Type"
> (e.g., Stream_Type), but just naming all the types "Stream_Type" is an 
> option. We have formal parameters named "Stream", so we don't want to 
> use that name.

I understand some people have this perspective, and they should do whatever 
makes sense for their code in their code, but for the language-defined 
libraries, I think it is pretty important that we consistently use names.
The basic stream type is "Root_Stream_Type", and I'd argue that anything 
derived from it in the language should be named in a similar style.

...
> So with the package names proposed above, the type names could be
>     Counted_Streams.Counted_Stream
>     Counted_Streams.FIFO_Streams.FIFO_Stream
>     Counted_Streams.Bounded_FIFO_Streams.FIFO_Stream

I would score these at about a -200. Containing a form of "Stream" four times 
is madness. Remember that one is going to have to use the full name of the 
package in a context clause, so you would have something like:

    with Ada.Streams.Counted_Streams.Bounded_FIFO_Streams;

which mentions Streams at least two more times than necessary!

The primary reason I would like to reconsider these names is to avoid this 
madness, not make it worse.

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

From: Steve Baird
Sent: Wednesday, April 3, 2019  6:33 PM

> As Brad pointed, it*is*  implied by the contracts, which surely are 
> part of the abstract interface. So I tend to disagree on this one. If 
> we decided to change the contracts so that external (blocking) stuff 
> was allowed, then I'd have more sympathy.

Good point. So I withdraw my objection to Buffered_Streams.

> The basic stream type is "Root_Stream_Type", and I'd argue that 
> anything derived from it in the language should be named in a similar style.

Fair enough. I can live with naming all three types "Stream_Type" (or perhaps 
FIFO_Stream_Type for the two concrete types; what really matters is that the 
two should be the same).

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

From: Richard Wai
Sent: Wednesday, April 3, 2019  10:41 PM

I note that "storage" has a very clear meaning in Ada, and is also used for 
very similar ends as a FIFO in the package Ada.Storage_IO. For this reason I
strongly agree with Storage_Streams.FIFO and family. The "buffer"
terminology is common in the broader computing community, but I think using 
that here will only blur existing consistency. I for one am a huge proponent 
of orthogonality. I think the existence of Storage_IO especially makes the 
case for Storage_Streams.

I think the FIFO distinction needs to be kept, because LIFO buffers have their 
use, as do circular buffers. So simply calling them "Storage_Streams.Unbounded"
seems too ambiguous. It should be clear exactly what effect any given Write has
on a subsequent Read. I also second the others who commented that the unbounded
package is usually the parent of the bounded, and the unbounded is the 
"original".

On a more technical note, it would make a lot of sense to implement these kinds
of stream objects with some form of a Storage Pool, which makes the Storage 
name even more relevant. At the end of the day, we're going to be dealing with
Storage_Elements as part-in-parcel of using the Streams "subsystem".

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

From: Tucker Taft
Sent: Wednesday, April 3, 2019  11:55 PM

I would agree that "Storage" is better than "Buffer" given the existing 
Storage_IO.

I don't have time to do the full ballot at the moment, and am willing to let 
Randy and Steve make the decision.

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

From: Erhard Ploedereder
Sent: Friday, April 5, 2019  4:07 AM

Some comments:

re: parent pkg Buffers. What other child packes are planned for the near 
future? If none, this is bad; if so, this is good.

re: FIFO and queues. I expect that a queue is always FIFO or <some order, 
FO>, such as priority-ordered. A LIFO queue is a stack and hence completely 
misnamed. So, I doubt the need for the FIFO qualification.

Consistency across libraries is important.

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

From: Brad Moore
Sent: Friday, April 5, 2019  9:45 AM

> Comments: [on the poll ballot - Editor.]

Given that we already have Storage_IO, the Storage_Streams suggestion stands 
out above all the others, in my mind, while addressing my original concerns.

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

From: Jeff Cousins
Sent: Friday, April 5, 2019  3:14 PM

> Comments: [on the poll ballot - Editor.]

Though Iím sure Randy and Steve would come up with something sensible.

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

Questions? Ask the ACAA Technical Agent