!standard 13.13.02 (09) 00-03-07 AI95-00108/05 !standard 13.13.02 (27) !standard 13.13.02 (36) !class binding interpretation 96-04-04 !status Corrigendum 2000 99-06-02 !status WG9 approved 96-12-07 !status ARG approved 7-0-2 96-06-17 !status work item 96-04-13 !status received 96-04-04 !priority High !difficulty Hard !qualifier Error !subject Inheritance of Stream Attributes for Type Extensions !summary For a type extension, the predefined Read attribute is defined to call the Read of the parent type, followed by the Read of the non-inherited components, if any, in canonical order. The analogous rule applies to the Write attribute. The Input and Output attributes are not inherited by a type extension. The stream attributes must work properly for every language defined nonlimited type. For language defined private types, the output generated by the Write attribute is not specified, but it must be readable by the Read attribute. !question 13.1(15) says: 15 A derived type inherits each type-related aspect of its parent type that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent type from the grandparent type. A derived subtype inherits each subtype-specific aspect of its parent subtype that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent subtype from the grandparent subtype, but only if the parent subtype statically matches the first subtype of the parent type. An inherited aspect of representation is overridden by a subsequent representation item that specifies the same aspect of the type or subtype. Do these rules apply to the stream-oriented attributes Read, Write, Input, and Output? (No.) Are the stream-oriented attributes intended to work properly for language defined types such as Unbounded_String? (Yes.) !recommendation (See summary.) !wording (See corrigendum.) !discussion The general rule for inheritance of type-related representation aspects should not apply to the stream attributes of type extensions. For 'Read and 'Write, a rule analogous to the rule for tagged equality makes the most sense. For 'Input and 'Output, no inheritance makes sense; instead, they should regain their predefined meaning in terms of 'Read and 'Write. There are several problems associated with applying the normal 13.1(15) inheritance rules to the stream attributes of tagged types: 1) Inheriting a 'Read or 'Write of the parent type as-is for the 'Read or 'Write of a type extension will ignore any new components added in the extension part. A rule analogous to the one for the equality operator makes more sense. In particular, the default 'Read or 'Write for a type extension should be defined to do the 'Read or 'Write of the parent type followed by the 'Read or 'Write for each component of the type extension, in canonical order. 2) Inheriting a 'Input or 'Output of the parent type as-is for 'Input or 'Output of a type extension makes no sense, since the inherited 'Input is a function returning the parent type, and the inherited 'Output puts out the discriminants of the parent type. For these two, the only meaningful approach seems to be for the default 'Input and 'Output for a tagged type to always be defined in terms of the 'Read and 'Write for the tagged type, preceded with the discriminants, if any. For untagged derived types, there is no problem for the derived type inheriting the stream attributes. Even for tagged derived types, if the extension part is null, the 'Read and 'Write will effectively be inherited. For language defined nonlimited private types, the RM does not say whether the stream-oriented attributes must work properly. It seems that they ought to. For many such types, the default version will work properly. However, for a type like Unbounded_String, which is almost certainly implemented as a data structure involving pointers, the default versions will not work. Therefore, for these types, the implementer must provide an explicit version of the Read and Write attributes. The wording takes advantage of the newly defined "operational attributes" (see AI-00137) to say that operational attributes are never inherited. This simplifies the wording by eliminating the need to describe a long list of exceptions to an inheritance rule that we don't actually want. !corrigendum 13.1(15) @drepl A derived type inherits each type-related aspect of its parent type that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent type from the grandparent type. A derived subtype inherits each subtype-specific aspect of its parent subtype that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent subtype from the grandparent subtype, but only if the parent subtype statically matches the first subtype of the parent type. An inherited aspect of representation is overridden by a subsequent representation item that specifies the same aspect of the type or subtype. @dby A derived type inherits each type-related aspect of representation of its parent type that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent type from the grandparent type. A derived subtype inherits each subtype-specific aspect of representation of its parent subtype that was directly specified before the declaration of the derived type, or (in the case where the parent is derived) that was inherited by the parent subtype from the grandparent subtype, but only if the parent subtype statically matches the first subtype of the parent type. An inherited aspect of representation is overridden by a subsequent representation item that specifies the same aspect of the type or subtype. In contrast, operational aspects are not inherited for derived types; rather, the predefined value of each aspect is used. A predefined operational aspect can be overridden by a subsequent operational item that specifies the same aspect of the type. !corrigendum 13.13.02(9) @drepl For elementary types, the representation in terms of stream elements is implementation defined. For composite types, the Write or Read attribute for each component is called in a canonical order. The canonical order of components is last dimension varying fastest for an array, and positional aggregate order for a record. Bounds are not included in the stream if @i is an array type. If @i is a discriminated type, discriminants are included only if they have defaults. If @i is a tagged type, the tag is not included. @dby For elementary types, the representation in terms of stream elements is implementation defined. For composite types, the Write or Read attribute for each component is called in a canonical order. The canonical order of components is last dimension varying fastest for an array, and positional aggregate order for a record. Bounds are not included in the stream if @i is an array type. If @i is a discriminated type, discriminants are included only if they have defaults. If @i is a tagged type, the tag is not included. For nonlimited type extensions, the Write or Read attribute for the parent type is called, followed by the Write or Read attribute of each non-inherited component, in canonical order. For other derived types, the Write or Read attribute of the parent type is called. !corrigendum 13.13.02(26) @drepl @xbullet is an array type, S'Output first writes the bounds, and S'Input first reads the bounds. If @i has discriminants without defaults, S'Output first writes the discriminants (using S'Write for each), and S'Input first reads the discriminants (using S'Read for each).> @dby @xbullet is an untagged derived type, the Output or Input attribute of the parent type is called, if one exists.> @xbullet @xinbull is an array type, S'Output first writes the bounds, and S'Input first reads the bounds. If @i has discriminants without defaults, S'Output first writes the discriminants (using S'Write for each), and S'Input first reads the discriminants (using S'Read for each).> !corrigendum 13.13.02(27) @drepl @xbullet @dby @xinbull !corrigendum 13.13.02(36) @dinsa The stream-oriented attributes may be specified for any type via an @fa. All nonlimited types have default implementations for these operations. An @fa for one of these attributes is illegal if the type is limited, unless the attribute has been specified by an @fa. For an @fa specifying one of these attributes, the subtype of the Item parameter shall be the base subtype if scalar, and the first subtype otherwise. The same rule applies to the result of the Input function. @dinss For every subtype S of a language-defined nonlimited specific type @i, the output generated by S'Output or S'Write shall be readable by S'Input or S'Read, respectively. The object read by S'Input or S'Read shall behave as the original object for the operations declared in the language-defined descendants of the unit that declares @i. This rule applies across partitions if the implementation conforms to the Distributed Systems Annex. For every subtype S'Class of a language-defined class-wide type T'Class, the attributes S'Class'Write, S'Class'Read, S'Class'Input, and S'Class'Output have their predefined definition. !ACATS test A C-Test to check that the Read and Write attributes of an extension are defined as in this issue should be created. It should also check that the Input and Output attributes revert to the predefined versions for an extension. Tests to check that language defined nonlimited private types properly support 'Read and 'Write should also be created. !appendix !section 13.13.2(09) !subject Missing AI: 'Input/'Output inheritance !reference RM95-13.13.2(9,36) !reference RM95-13.1(15) !from Tucker Taft 95-10-30 !reference 95-5373.a Tucker Taft 95-10-30>> !discussion The general rule for inheritance of type-related representation aspects should not apply to the stream attributes of type extensions. For 'Read and 'Write, a rule analogous to the rule for tagged equality would make the most sense. For 'Input and 'Output, no inheritance makes sense; instead, they should regain their predefined meaning in terms of 'Read and 'Write. This issue was discussed at length in some Ada 95 forum or other (perhaps the GNAT team mailing list?). There are several problems associated with applying the normal 13.1(15) inheritance rules to the stream attributes of tagged types: 1) Inheriting a 'Read or 'Write of the parent type as-is for the 'Read or 'Write of a type extension will ignore any new components added in the extension part. A rule analogous to the one for the equality operator would make more sense. In particular, the default 'Read or 'Write for a type extension should be defined to do the 'Read or 'Write of the parent type followed by the 'Read or 'Write for each component of the type extension, in canonical order. 2) Inheriting a 'Input or 'Output of the parent type as-is for 'Input or 'Output of a type extension makes no sense, since the inherited 'Input is a function returning the parent type, and the inherited 'Output puts out the discriminants of the parent type. For these two, the only meaningful approach seems to be for the default 'Input and 'Output for a tagged type to always be defined in terms of the 'Read and 'Write for the tagged type, preceded with the discriminants, if any. For untagged derived types, there is no problem for the derived type inheriting the stream attributes. Even for tagged derived types, if the extension part is null, the 'Read and 'Write will effectively be inherited, given the rule suggested above. **************************************************************** !section 13.3.2(00) !subject stream attributes for unbounded string, bounded string etc. !reference RM95-13.3.2(00) !from Bob Duff !reference 96-5480.a Robert A Duff 96-4-12>> !discussion Robert Dewar pointed out this issue to me. It would seem that the stream attributes should work properly for all the language-defined non-limited types. For example, types Strings.Unbounded.Unbounded_String, Strings.Bounded.Bounded_String, etc. - Bob **************************************************************** !section 13.13.2(00) !subject Stream-Oriented attributes for language-defined private types !reference RM95-13.13.2 !from Laurent Guerby 96-07-15 !reference 96-5621.a Laurent Guerby 96-7-15>> !discussion The behaviour of the stream oriented attributes is not clearly defined for most of private (or implementation-defined) types. This can lead to erroneous execution (but nothing is said about it in the RM95) if type type has a component of an access type when some object of this type is exchanged between two partitions. An example of interest is Unbounded_String. -- Laurent Guerby , Team Ada. "Use the Source, Luke. The Source will be with you, always (GPL)." **************************************************************** From Randy Brukardt 3-7-2000 Paragraph 13.1(15.1) is not normative (it follows from other rules), and could be omitted. **************************************************************** From: Randy Brukardt Sent: Wednesday, April 12, 2000 9:57 PM While doing the (almost) final check on the Corrigendum, I noticed the following: The new paragraph 13.13.2(27.1) says: If T is a type extension, S'Output and S'Input are not inherited from the parent type; they are defined in terms of S'Read and S'Write, notwithstanding the inheritance rule stated in 13.1. But the rewritten 13.1(15) says that operational attributes are never inherited. It seems to me that this entire change can be deleted. (This is AI-00108). Additionally, the last sentence of the new 13.13.2(9) says: For other derived types, the Write or Read attribute of the parent type is inherited. Again, 13.1(15) says that operation attributes are never inherited. I think it would be better to say that the parent attribute is "called", which would be similar to the way that the implementation for type extensions are described. Any comments?? **************************************************************** From: Tucker Taft Sent: Thursday, April 13, 2000 11:09 AM I am surprised that we say that operational attributes are never inherited. It seems like this needs to be a per-attribute decision. Inheriting something like external_tag does seem unwise, but inheriting 'Read from a parent non-tagged type makes perfect sense. Perhaps we could say that operational attributes are never inherited for tagged types, though their actions may be incorporated as part of the default implementation for the type extension. However, that doesn't work for 'Read/'Write for limited tagged types, where they won't have any attribute at all if it isn't inherited. The operational attribute writeup needs some revision perhaps. **************************************************************** From: Randy Brukardt Sent: Thursday, April 13, 2000 7:14 PM Tucker said: > I am surprised that we say that operational attributes are never > inherited. It seems like this needs to be a per-attribute > decision. Inheriting something like external_tag does seem unwise, > but inheriting 'Read from a parent non-tagged type makes perfect > sense. I looked this up to see why Pascal made it this way, and discovered that I had talked him into this change at the last minute. Oh well, I'll have to go it alone. First of all, it is important to remember that operational item are a class of attributes that certainly can be extended by both implementation-defined ones and possibly by future amendments to the standard. Rules motivated solely by the behavior of the current members of the class are best avoided. (That is, after all, how we got into this mess in the first place.) So I immediately reject any wording that handles non-tagged types differently than tagged types in the definition of operational items (i.e. in 13.1(15)). I'm also concerned about defining a heavy, complex inheritance mechanism, then saying that it doesn't apply in most existing cases. I have a note saying that the current 13.1(15.1/1) is in fact non-normative: because it says there is nothing special happening. This certainly is the cleanest solution. Finally, the current wording (the predefined value of each aspect is used) in fact defers the decision as to whether or not to inherit to each attribute. That was the intent, and is what Tucker says he wants. > Perhaps we could say that operational attributes are > never inherited for tagged types, though their actions may be > incorporated as part of the default implementation for the > type extension. However, that doesn't work for 'Read/'Write for > limited tagged types, where they won't have any attribute > at all if it isn't inherited. The operational attribute > write-up needs some revision perhaps. AI-00108 makes it pretty clear that 'Read and 'Write are *never* inherited for tagged types, rather they are composed. If that is the case, then it is seems very dangerous for there to be any inherited or predefined 'Read/'Write for a limited tagged type: there may be limited components in the extension that don't have a 'Read or 'Write to call. To say that limited tagged types are not composed (the only alternative) would be inconsistent and confusing. The wording for 13.13.2(9) says "For other derived types, the Write or Read attribute of the parent type is called." (Or "inherited" instead of "called"). The intent is that here we are defining the predefined meaning for a derived type to inherit the meaning of the parent type. This wording seems too vague to me, since it isn't clear whether derived elementary types are included or not. (You have to read the entire paragraph to see the problem.) I think it ought to say something more like: "For non-tagged derived types, the Write or Read attribute of the parent type is called, if one exists." After I wrote all of the above, I noticed that inheritance of limited 'Read, etc. is moot. 13.13.2(36) says "An attribute_reference is illegal if the type is limited, unless the attribute has been specified by an attribute_definition_clause". Clearly, any "inherited" or even "predefined" attribute for a derived limited has not been specified by an attribute_definition_clause (which is a syntactic entity). Thus, while such an attribute might exist, it is always illegal to call it. Certainly, the proposed changes have no effect on that property. So, my conclusion is that the Corrigendum wording is correct for 'Read and 'Write. There does seem to be a problem for 'Input and 'Output for untagged derived types: the current wording reverts them to their predefined implementation, rather than inheriting them. That would be an gratuitous change, not supported by AI-00108. I propose to repair this problem by adding the following in front of 13.13.2(26) (and indenting (26-27) further): o If T is an untagged derived type, the Output or Input attribute of the parent type is called, if one exists. o For other types: I believe this takes care of the open problem with inheritance. Now, I'll don my fireproof suit. :-) **************************************************************** From: Tucker Taft Sent: Friday, April 14, 2000 5:56 AM > ... > After I wrote all of the above, I noticed that inheritance of limited 'Read, > etc. is moot. 13.13.2(36) says "An attribute_reference is illegal if the > type is limited, unless the attribute has been specified by an > attribute_definition_clause". Clearly, any "inherited" or even "predefined" > attribute for a derived limited has not been specified by an > attribute_definition_clause (which is a syntactic entity). Here you are wrong. "Specified" is clearly defined to include inherited. If you want to omit inherited aspects, you need to say "directly specified." ("Look it up," as they say ;-). > ... Thus, while such > an attribute might exist, it is always illegal to call it. Certainly, the > proposed changes have no effect on that property. This does not follow, given your misinterpretation of "specified." > So, my conclusion is that the Corrigendum wording is correct for 'Read and > 'Write. I understand the need to use the notion of "calling" the parent operation for type extensions, because that is just one of the things being done, since the predefined 'Read include calls on the 'Reads of the components of the extension part. Using the "call the parent" hack for untagged types seems bogus. Here we should say the attribute is inherited. So I believe that operational attributes should be inherited for untagged. For tagged, when the predefined attribute is defined component-wise, the parent attribute is incorporated by treating the parent as a "component" of the type extension, along with the actual components of the extension part. Using the "hack" of "call the parent but don't inherit" for untagged makes no intuitive sense to me. > There does seem to be a problem for 'Input and 'Output for untagged derived > types: the current wording reverts them to their predefined implementation, > rather than inheriting them. That would be an gratuitous change, not > supported by AI-00108. Removing inheritance from untagged operational attributes is a gratuitous change as far as I am concerned. Even if you wish tagged and untagged were the same, the fact is that from the point of view of "aspects," they need to be treated separately. (Look at the handling of "packed" as another example.) > I propose to repair this problem by adding the following in front of > 13.13.2(26) (and indenting (26-27) further): > > o If T is an untagged derived type, the Output or Input attribute > of the parent type is called, if one exists. Yuck. Just inherit untagged operational attributes. > o For other types: > > > I believe this takes care of the open problem with inheritance. I don't agree. **************************************************************** From: Pascal Leroy Sent: Friday, April 14, 2000 6:30 AM > Using the > "call the parent" hack for untagged types seems bogus. Here > we should say the attribute is inherited. But that doesn't quite work because the (untagged) derived type may have different discriminants than its parent. I think that part of this discussion is covered by items 3 and 5 of AI 195, which in fact corrects some of AI 108: 3 - For a derived type which is limited (tagged or not), the attributes Read and Write are inherited, and the attributes Input and Output revert to their predefined definition (i.e. they cannot be called). (This amends AI95- 00108.) 5 - For an untagged derived type with new discriminants that have defaults, the predefined stream-oriented attributes read or write the new discriminants, not the old ones. (This amends AI95-00108.) **************************************************************** From: Tucker Taft Sent: Friday, April 14, 2000 7:01 AM > But that doesn't quite work because the (untagged) derived type may have > different discriminants than its parent. I think we discussed this, and concluded that a user-defined 'Read or 'Write is inherited as is, but if there is no user-defined 'Read or 'Write, the predefined one behaves as described below. > I think that part of this discussion is covered by items 3 and 5 of AI 195, which in fact corrects some of AI 108: > > 3 - For a derived type which is limited (tagged or not), the attributes Read > and Write are inherited, and the attributes Input and Output revert to their > predefined definition (i.e. they cannot be called). (This amends AI95- > 00108.) > > 5 - For an untagged derived type with new discriminants that have defaults, > the predefined stream-oriented attributes read or write the new > discriminants, not the old ones. (This amends AI95-00108.) The above clearly indicates that saying that "operational attributes are never inherited" is misleading at best. **************************************************************** From: Randy Brukardt Sent: Friday, April 14, 2000 3:54 PM Tucker said: > Here you are wrong. "Specified" is clearly defined to include > inherited. If you want to omit inherited aspects, you need to > say "directly specified." ("Look it up," as they say ;-). I did (now). And the paragraphs in question 13.1(16-18) clearly don't apply to operational aspects. :-) I don't know if this was intentional on Pascal's part (I think so, but I'm guessing, none of my mail answers that). So that is another problem (one way or another) with this stuff. Tucker replied to me: > > So, my conclusion is that the Corrigendum wording is correct for 'Read and > > 'Write. > > I understand the need to use the notion of "calling" the parent > operation for type extensions, because that is just one of the > things being done, since the predefined 'Read include calls on > the 'Reads of the components of the extension part. Using the > "call the parent" hack for untagged types seems bogus. Here > we should say the attribute is inherited. > > ... > Using the "hack" of "call the parent but don't inherit" for untagged > makes no intuitive sense to me. It's pretty hard to argue with "seems bogus". You seem to prefer a rule of "it inherits, except when it doesn't", and I prefer to not call it inheritance. I guess I would like to see an actual suggestion of wording changes for 13.1(15-18) and 13.13.2(9 and 25) that meet the needs of the AI and have the behavior that you want. Pascal said: >I think that part of this discussion is covered by items 3 and 5 of AI 195, >which in fact corrects some of AI 108: >3 - For a derived type which is limited (tagged or not), the attributes Read >and Write are inherited, and the attributes Input and Output revert to their >predefined definition (i.e. they cannot be called). (This amends AI95- >00108.) >5 - For an untagged derived type with new discriminants that have defaults, >the predefined stream-oriented attributes read or write the new >discriminants, not the old ones. (This amends AI95-00108.) Keep in mind that AI-00195 never was approved or finished. So it isn't clear just how much of it we ought to incorporate. I now believe (having thought about this some more) that 3 is wrong for 'Read and 'Write for a type extension. That is, using the previous version is more likely to cause bugs and confusion than it is to work properly (because the extension components are not covered). Moreover, simply making a type limited could silently break code. (Breaking it with a compile-time error is at least helpful, as it points out the problem.) The situation is similar to that for a function, which we do not allow the use of the original. More from Tucker: > Even if you wish tagged and untagged were the same, the fact > is that from the point of view of "aspects," they need to be > treated separately. (Look at the handling of "packed" as > another example.) That is irrelevant to the wording of 13.1. 13.1 only has a two places where "tagged" occurs: in 13.1(10) and 13.1(11). And it is those rules that triggered AI-00137 in the first place! If they hadn't had special cases for untagged types, we probably wouldn't be having this conversation (as special-case "patches" for AI-108 probably would have made more sense). I cannot see fixing one problem by unnecessarily introducing the *exact same* problem in the fix. We *will* trip over any such rules again. So I strongly believe that any rules ought to be specific to a particular attribute or set of attributes. (Certainly the non-normative wording of "does not inherit" in 13.1 could be dumped, but I'm not quite sure what to replace it by.)Now I can imagine defining the entire inheritance blather at the start of 13.13.2, but it seems awfully heavy to do so just to say what takes two sentences to do otherwise. Tucker replied to me: > > I believe this takes care of the open problem with inheritance. > > I don't agree. I now agree there are problems here, especially because of the cases noted from the unfinished AI-00195. I don't agree that we are likely to find a resolution without a meeting, however. Tucker's argument seems to be purely based on emotion ("seems bogus", "the hack of calling..."). Honestly, mine (while clearly superior :-) isn't much better, as it is based on potential future uses of the feature. To resolve this requires roundtable discussion and additional points of view. E-Mail seems to degrade into two people dominating the discussion, and rarely develops the consensus needed. How to proceed from here? I think we only have one practical choice left, but I'll let others decide that. The choices are (in no particular order): A: Leave it as it is. -- Too many problems have been noted, that simply isn't practical. B: Put in half-baked changes discussed by e-mail. -- Past experience with the corrigendum says that these get -- heavily modified at the next meeting. Which means it is the same -- as C. C: Fix it at the next meeting. -- This would be OK, but as a practical matter means that we cannot -- meet the schedule. (Substantive changes inserted at a meeting -- should always be reconsidered afterwards, especially in the full -- context of the RM. The problems we're discussing came up because I -- did that with these changes.) To at least come close to the schedule, -- we would have to have an "extra" meeting in September/October. D: Revert AIs 108 & 137 to the pre-operational attribute version. -- This probably would work, but we would have to re-review the changes -- from those versions, as I don't think that we ever did that. So, -- more than likely, we end up with C again. E: Vote to remove AI-108 from the corrigendum. -- This can be supported based on the need to complete the recommendation -- (that is, the partial reversal of AI-00108 in AI-195 implies that -- it needs a lot more work, and not all of this work was considered in -- the current wording). After all, there seems to be more than just a -- disagreement in wording here, especially if AI-195 is factored in. -- However, doing this leaves the question of dealing with AI-137 in a -- way that doesn't interfere with the eventual solution of AI-108/195. -- E1 would be to revert it to the original pre-operational attribute form, -- which was quite simple, with the thought that it would be changed again -- "next time". But that probably ends up the same as D. E2 would be to -- "fix" it to be compatible, meaning that we still would have to come up -- with wording for 13.1(15-18) -- which is where we started. F: Vote to remove both AI-108 and AI-137 from the corrigendum. -- This would be supported by the reasons given above for AI-108, and -- an interaction argument for AI-137. This seems to be the only solution -- that would keep us on schedule. But it is pretty severe, as we're -- delaying answering these questions for more time. ****************************************************************