!standard A.18.19 (0) 10-08-11 AI05-0184-1/04 !standard A.18.20 (0) !standard A.18.21 (0) !standard A.18.22 (0) !standard A.18.23 (0) !standard A.18.24 (0) !standard A.18.25 (0) !class amendment 09-11-02 !status Amendment 2012 10-08-11 !status ARG Approved 8-0-0 10-06-20 !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 7 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, Bounded_Ordered_Sets, and Bounded_Multiway_Trees (see AI05-0136-1). Add an "Implementation Requirements" section at each of these 7 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 the Vector'Output or Vector'Write subprograms of either instance shall be readable by the Vector'Input or Vector'Read of the other instance, 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 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, set, and tree 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 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. 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.) !corrigendum A.18.19(0) @dinsc Force a conflict; real text found in the conflict file. !corrigendum A.18.20(0) @dinsc Force a conflict; real text found in the conflict file. !corrigendum A.18.21(0) @dinsc Force a conflict; real text found in the conflict file. !corrigendum A.18.22(0) @dinsc Force a conflict; real text found in the conflict file. !corrigendum A.18.23(0) @dinsc Force a conflict; real text found in the conflict file. !corrigendum A.18.24(0) @dinsc Force a conflict; real text found in the conflict file. !corrigendum A.18.25(0) @dinsc Force a conflict; real text found in the conflict file. !ACATS test Consider creating a C-Test that streams out an unbounded vector (list, map, set, tree) and streams in a bounded vector (list, map, set, tree), verifying that the new object has the same elements, order, etc. as the original. !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 **************************************************************** [Editor's note: The proposed wording had possessive "instance's" in two places. I reordered it to remove that, as John Barnes of the UK will insist on removing it before approval anyway. Why wait for a formal complaint?] ****************************************************************