!standard A.18.17 (0) 10-02-24 AI05-0184-1/03
!standard A.18.18 (0)
!standard A.18.19 (0)
!standard A.18.20 (0)
!standard A.18.21 (0)
!standard A.18.22 (0)
!class amendment 09-11-02
!status work item 09-11-02
!status received 09-11-02
!priority Medium
!difficulty Medium
!subject Compatibility of streaming of containers
!summary
Compatible streaming operations are required for bounded and unbounded
containers.
!problem
Changing between bounded and unbounded versions of the container generics
should not break programs which use streaming.
!proposal
(See summary.)
!wording
There are 6 places where we define the "Bounded" version of a container. For
example,
A.18.17(1/3):
The language-defined generic package Containers.Bounded_Vectors
provides a private type Vector and a set of operations. It provides
the same operations as the package Containers.Vectors (see A.18.2),
with the difference that the maximum storage is bounded.
Similar text exists for Bounded_Doubly_Linked_Lists, Bounded_Hashed_Maps,
Bounded_Ordered_Maps, Bounded_Hashed_Sets, and Bounded_Ordered_Sets.
Add an "Implementation Requirements" section at each of these 6 points which
follows the following template:
For each instance of Containers.Vectors and each
instance of Containers.Bounded_Vectors,
if the two instances meet the following conditions
then the output generated by either instance's
Vector'Output or Vector'Write subprograms
shall be readable by the other instance's Vector'Input
or Vector'Read, respectively:
- the Element_Type parameters of the two instances are
statically matching subtypes of the same type (note that
distinct elaborations of a type declaration result in
distinct types); and
- the output generated by Element_Type'Output or Element_Type'Write
is readable by Element_Type'Input or Element_Type'Read,
respectively (where Element_Type denotes the type of
of the two actual Element_Type parameters); and
- the preceding two conditions also hold for the Index_Type
parameters of the instances.
The condition which mentions the Index_Type parameters is:
- replaced by similar wording for Key_Type parameters for map containers;
- omitted for list and set containers (which have no extra parameters).
In that case, the "; and" of the formerly penultimate condition is
replaced with a period.
!discussion
13.13.2(54/1) already uses the phrase "shall be readable by", so we can build on
that:
For every subtype S of a language-defined nonlimited specific type T,
the output generated by S'Output or S'Write shall be readable by
S'Input or S'Read, respectively. This rule applies across partitions
if the implementation conforms to the Distributed Systems Annex.
This precedent spares us from having to precisely define that phrase.
During discussions in Brest, the possibility was raised that there is some
implementation issue in the Vector case having to do with "empty elements"
(A.18.2(14/2)) and, for example, the Insert_Space procedure. Note that the list
of operations that result is bounded errors if an empty element is encountered
does not include any of the stream operations. An implementation might or might
not choose to keep track of "emptiness" at runtime, but the streaming issues in
either case seem to be the same for the bounded and unbounded versions (note
that we are not talking here about the indefinite version). There could be an
issue if an implementation chooses to keep track of emptiness in exactly one of
the two (i.e. bounded and unbounded) cases; this requirement of streaming
compatibility might impact such an implementation. Does this warrant even an
AARM note? Perhaps just a mention in passing in the !discussion section of the
AI.
Given
procedure Recursive (N : Natural) is
type Element is new String (1 .. N);
package Inst is new Some_Container (Element, ...);
begin
if N /= 0 then Recursive (N - 1); end if; ... ;
end Recursive;
We must avoid wording which would incorrectly require any sort of
compatibility between the streaming attributes of the container type associated
with different elaborations of Recursive.Inst. It is asserted that the proposed
wording meets this requirement.
!example
(See discussion.)
!ACATS test
!appendix
From: Steve Baird
Sent: Tuesday, October 6, 2009 5:30 PM
I've got the following item on my to-do list from Brest:
Investigate and possibly create an AI to require that
streaming work between bounded and unbounded definite
forms of the same container kind.
We can begin by noting that 13.13.2(54/1) already uses the phrase "shall be
readable by", so we can build on that:
For every subtype S of a language-defined nonlimited specific type T,
the output generated by S'Output or S'Write shall be readable by
S'Input or S'Read, respectively. This rule applies across partitions
if the implementation conforms to the Distributed Systems Annex.
This existing precedent spares us from having to nail down a precise definition
of that phrase (unless we decide that it doesn't). One can only imagine what
Justice Potter Stewart might have said if asked to consider the question of
stream-wise compatibility:
I shall not today attempt further to define the kinds of material I
understand to be embraced within that shorthand description; and
perhaps I could never succeed in intelligibly doing so.
But I know it when I see it ...
There are 6 places where we define the "Bounded" version of a container. For
example,
A.18.17(1/3):
The language-defined generic package Containers.Bounded_Vectors
provides a private type Vector and a set of operations. It provides
the same operations as the package Containers.Vectors (see A.18.2),
with the difference that the maximum storage is bounded.
Similar text exists for Bounded_Doubly_Linked_Lists, Bounded_Hashed_Maps,
Bounded_Ordered_Maps, Containers.Bounded_Hashed_Sets, and Bounded_Ordered_Sets.
We could add an "Implementation Requirements" section at each of these 6 points
containing something like the following:
Let I1 be any instance of one of the two generics
Containers.Vectors and Containers.Bounded_Vectors.
Let I2 also be an instance of either one of those two generics.
If the the two instances have matching actual parameters,
then the output generated by I1.Vector'Output or I1.Vector'Write
shall be readable by I2'Vector'Input or I2'Vector'Read, respectively.
AARM note:
The term "matching" as used here is intended to be consistent
with the use in 12.6 - two subtypes match if they are statically
matching subtypes and other parameters match if they statically
denote the same entity.
This requirement only applies if the output generated by
the Output or Write attribute of the Element type is readable
by the Input or Read attribute of the Element type, respectively.
Likewise for the streaming attributes of the Index type.
====
Details:
During discussions in Brest, the possibility was raised that there
is some implementation issue in the Vector case having to do with
"empty elements" (A.18.2(14/2)) and, for example, the Insert_Space
procedure. Note that the list of operations that result in
bounded errors if an empty element is encountered does not include
any of the stream operations. An implementation might or might
not choose to keep track of "emptiness" at runtime, but the
streaming issues in either case seem to be the same for the
bounded and unbounded versions (note that we are not talking here
about the indefinite version). There could be an issue if an
implementation chooses to keep track of emptiness in exactly
one of the two (i.e. bounded and unbounded) cases; this
requirement of streaming compatibility might impact such an
implementation. Does this warrant even an AARM note? Perhaps just
a mention in passing in the !discussion section of the AI.
Does it matter if the two instances are declared at different
accessibility levels? Is there any need to relax the compatibility
requirement in that case?
Does this general approach seem like the direction we want to go?
I'd like to reach a consensus (either pro or con) before proceeding further.
****************************************************************
From: Tucker Taft
Sent: Tuesday, October 6, 2009 5:43 PM
Your proposal looks good to me, though the wording "Let I1 be ..." is not our
usual way of introducing names in a description. Usually we say something like
"Given an instance I1 of ..." or "For every instance I1 ...".
For what that's worth...
****************************************************************
From: Steve Baird
Sent: Tuesday, October 6, 2009 5:54 PM
I like the latter form - "For every instance I1", although now that you point it
out, either is an improvement on my initial wording.
****************************************************************
From: Randy Brukardt
Sent: Tuesday, October 6, 2009 7:10 PM
I agree with Tucker. I think that the basic idea is that we want to maximize
interoperability between the bounded and unbounded forms (in order that
switching between them is as painless as possible). But of course we don't want
to go too far with that such that we impose insane implementation requirements
(especially if they reduce the advantages of either form).
What you have sounds right, presuming that you don't uncover any implementation
complexities. (If it was anyone else, I wouldn't worry much, but you are so good
at finding obscure problems that I will not make the mistake of thinking that
this will work in the end.)
I wonder if you could use the existing phrase "supports external streaming" to
describe the cases that must work. I don't think we want to require anything for
element types that include access types (not that it matters a whole lot in this
case).
Humm, that really isn't enough. (If the 'Read and 'Write attributes are
specified and aren't inverses of each other, we are still hosed.) You mention
that in an AARM note, but I think that is more fundamental than a note: I think
you need to work that into the actual requirement somehow. We don't want to be
appearing to require streaming of a vector of type Foo to work when streaming of
Foo itself does not "work"; that would be silly. (I'd rather not be applying
Dewar's rule to newly created text!)
****************************************************************
From: Steve Baird
Sent: Tuesday, October 6, 2009 7:21 PM
You also might want to cover a case I thought of later, where you elaborate the
same instance more than once (e.g., in a recursive subprogram) and we don't want
to require any sort of compatibility between the streaming representations of
the two (albeit statically one) instances.
****************************************************************
From: Robert Dewar
Sent: Tuesday, October 6, 2009 7:55 PM
why not?
can you see any reason in practice why the representations would not be
compatible? If not, then it's just pedantic stuff to say they are not the same.
After all, from a formal RM point of view, when we say
X : Integer;
Y : Integer;
there is no requirement that X and Y have the same representation, but in
practice of course they do.
****************************************************************
From: Steve Baird
Sent: Wednesday, October 7, 2009 10:12 AM
I was thinking (although I failed to mention this) of the case where the
recursive subprogram also included the declaration of the element type used to
instantiate the container, as in
type T is record
C1, C2 : String (1 .. Some_Parameter);
end record;
package I is new Some_Container (T, ...);
****************************************************************
From: Steve Baird
Sent: Monday, November 2, 2009 3:53 PM
As per Randy's request that I finish off my homework from Brest, here are the
results of the ARG's 10/6-10/7 discussion of this topic in something resembling
AI form. Not much new here.
[This is version /01 of this AI - ED]
****************************************************************
From: Randy Brukardt
Sent: Monday, November 2, 2009 6:54 PM
...
> Add an "Implementation Requirements" section at each of these
> 6 points which follows the following template:
>
> For every pair of instances I1 and I2 of either of the two
> generics Containers.Vectors and Containers.Bounded_Vectors
> (I1 and I2 need not be instances of the same generic),
> if the the two instances meet the the following conditions
> then the output generated by I1.Vector'Output or I1.Vector'Write
> shall be readable by I2'Vector'Input or I2'Vector'Read, respectively:
> - the Element_Type parameters of the two instances are
> statically matching subtypes of the same type (note that
> distinct elaborations of a type declaration result in
> distinct types); and
> - the output generated Element_Type'Output or Element_Type'Write
> is readable by Element_Type'Input or Element_Type'Read,
> respectively (where Element_Type denotes the type of
> of the two actual Element_Type parameters); and
> - the preceding two conditions also hold the Index_Type
> parameters of the instances.
>
> The condition which mentions the Index_Type parameters is omitted for
> the non-vector containers (which have no Index_Type parameter).
Would you not need to have similar wording for the Key_Type parameter of maps??
I would expect that some form of the keys would need to be streamed so that the
hash table/ordering information could be reconstructed (at the least, if the
capacity is changed after the container is streamed in).
****************************************************************
From: Randy Brukardt
Sent: Monday, November 2, 2009 6:56 PM
> if the the two instances meet the the following conditions
Stuttering here?? A strange fetish for the word "the"? ;-)
I've fixed this in the posted AI.
****************************************************************
From: Steve Baird
Sent: Monday, November 2, 2009 8:00 PM
>> if the the two instances meet the the following conditions
>
> Stuttering here?? A strange fetish for the word "the"? ;-)
>
> I've fixed this in the posted AI.
>
Conservation of three-letter words.
Delete a "the" and insert a "for" into
"preceding two conditions also hold the Index_Type"
Randy Brukardt wrote:
> Would you not need to have similar wording for the Key_Type parameter
> of maps?
Right. Thanks for catching that.
****************************************************************
From: Steve Baird
Sent: Thursday, February 4, 2010 5:54 PM
It was requested that I revise the proposed wording so that "it doesn't read
like a math book".
Perhaps it should read like a children's story?
So when the users got to the stream, they found three
instantiations - a baby bounded instance,
a regular instance, and a *great big* indefinite instance.
First, they read data from the stream with
Baby_Instance.Container'Read. Next, they read
data from the stream with Regular_Instance.Container'Read.
Finally, they huffed and they puffed and they invoked
Indefinite_Instance.Container'Read. They got the same
results in all three cases and they all lived happily
ever after.
Maybe not.
So let's try replacing the beginning of the currently proposed wording
For every pair of instances I1 and I2 of either of the two
generics Containers.Vectors and Containers.Bounded_Vectors
(I1 and I2 need not be instances of the same generic),
with
For each instance I1 of Containers.Vectors and each
instance I2 of Containers.Bounded_Vectors,
Tuck pointed out that there is no need to explicitly require container-streaming
compatibility between two instances of the same generic - this follows
implicitly from the new seemingly-weaker requirement and transitivity. If I1_A
and I1_B are each compatible with I2, then they must be compatible with each
other.
Other nits noticed along the way:
Bounded_Hash_Sets alone is qualified in:
Similar text exists for Bounded_Doubly_Linked_Lists,
Bounded_Hashed_Maps, Bounded_Ordered_Maps,
Containers.Bounded_Hashed_Sets, and Bounded_Ordered_Sets.
Missing "by" in
the output generated [by] Element_Type'Output
****************************************************************
From: Steve Baird
Sent: Thursday, February 4, 2010 6:31 PM
With this change, do we also need to add an "(and vice versa)" in the immediately following text:
if the two instances meet the following conditions
then the output generated by I1.Vector'Output or I1.Vector'Write
shall be readable by I2'Vector'Input or I2'Vector'Read,
respectively {(and vice versa)}:
?
Or is it back to the drawing board with something like
For each instance of Containers.Vectors and each
instance of Containers.Bounded_Vectors,
if the two instances meet the following conditions
then the output generated by either instance's
Vector'Output or Vector'Write subprograms
shall be readable by the other instance's Vector'Input
or I2'Vector'Read, respectively
****************************************************************