!standard 13.13.02 (09) 00-07-31 AI95-00108/08 !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. Default stream attributes are never inherited; rather, the default implementation for the derived type is used. 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: 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.) If an untagged derived type includes a known discriminant part, the number of discriminants can change. If we inherit the parent's attribute definition, we could write the wrong number of discriminants. Consider: type Parent (D1, D2 : Integer := 1) is ...; type Child (D : Integer := 2) is new Parent (D1 => D, D2 => D); Clearly the default implementation of Parent'Write writes two discriminant values. How many discriminants does Child'Write write? (One.) 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 (new) 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. We must take care, however, that all of the components have the appropriate attributes. For a limited type extension, the extension component could be of a type that does not have an implementation of Write or Read. In that case, we must take care to insure that the attribute for the new type does handle the extension component. We do this by requiring an attribute to be directly specified if it has a limited extension component that does not have an implementation of Write or Read and the parent type has a (specified) implementation of Write or Read. (An alternative would be to inherit the original operation unmodified, but this would silently ignore the extension components. This could cause hard-to-find bugs as the components would probably revert to default values when they are input.) This rule is similar to the way that functions of type extensions are inherited: they aren't inherited, they must be overridden (except that we only invoke it when we can't do the right thing automatically, which minimizes the places where existing code becomes illegal). To see how this works in practice, consider the following example: package P is type T is limited tagged ...; for T'Read use ...; type Der is new T with null record; -- OK (no extension components, -- T'Read is effectively inherited) type Der_Int is new T with -- OK (non-limited extension components, -- T'Read is inherited with the additional -- components added) record Int : Integer; end record; protected type Protect_Type is ... -- Note: no 'Read specified. type Der_Protect_Type is new T with -- Illegal unless -- Der_Protect_Type'Read is specified; -- we can't compose T'Read, as -- Protect_Type'Read can't be called. record PT : Protect_Type; end record; end P; Simply making the operation uncallable doesn't work, as the operations can be dispatched. If, in the above example, Der_Protect_Type couldn't be called, problems would arise if T'Class'Read was called on a Der_Protect_Type object. Clearly, the properties of the default implementation for the stream attributes can change for derived types (as in the example given in the question). Thus, we always want to use a "fresh" default implementation for an attribute, rather than inheriting a default implementation from the parent type. For language-defined nonlimited private types, the International Standard 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 access values, 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 8652/0009 [AI-00137]) to say whether operational attributes are inherited depends on the attribute. This simplifies the wording by eliminating the need to describe a long list of exceptions to an inheritance rule that we want only in some cases, and provides future flexibility. !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, whether operational aspects are inherited by a derived type depends on each specific aspect. When operational aspects are inherited by a derived type, aspects that were directly specified before the declaration of the derived type, or (in the case where the parent is derived) that were inherited by the parent type from the grandparent type are inherited. An inherited operational aspect is overridden by a subsequent operational item that specifies the same aspect of the type. !corrigendum 13.1(18) @dinsa @xbullet @dinst If an operational aspect is @i for an entity (meaning that it is either directly specified or inherited), then that aspect of the entity is as specified. Otherwise, the aspect of the entity has the default value for that aspect. !corrigendum 13.3(75) @drepl @xhang<@xtermS'External_Tag denotes an external string representation for S'Tag; it is of the predefined type String. External_Tag may be specified for a specific tagged type via an @fa; the expression of such a clause shall be static. The default external tag representation is implementation defined. See 3.9.2 and 13.13.2.> @dby @xhang<@xtermS'External_Tag denotes an external string representation for S'Tag; it is of the predefined type String. External_Tag may be specified for a specific tagged type via an @fa; the expression of such a clause shall be static. The default external tag representation is implementation defined. See 3.9.2 and 13.13.2. The value of External_Tag is never inherited; the default value is always used unless a new value is directly specified for a 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 untagged derived types, the Write and Read attributes of the parent type are inherited as specified in 13.1; otherwise, the default implementations of these attributes are used. The default implementations of Write and Read attributes execute as follows: 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 canonical order, which 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 type extensions, the Write or Read attribute for the parent type is called, followed by the Write or Read attribute of each component of the extension part, in canonical order. For a limited type extension, if the attribute of any ancestor type of @i has been directly specified and the attribute of any ancestor type of the type of any of the extension components which are of a limited type has not been specified, the attribute of @i shall be directly specified. !corrigendum 13.13.02(25) @drepl Unless overridden by an @fa, these subprograms execute as follows: @dby For untagged derived types, the Output and Input attributes of the parent type are inherited as specified in 13.1; otherwise, the default implementations of these attributes are used. The default implementations of Output and Input attributes execute as follows: !corrigendum 13.13.02(36) @drepl 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. @dby 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 or (for a type extension) the attribute has been specified for an ancestor type. 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.@hr @i<@s8>@hr 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. This rule applies across partitions if the implementation conforms to the Distributed Systems Annex. !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. **************************************************************** From: Randy Brukardt Sent: Thursday, June 01, 2000 6:34 PM Despite Tucker's violation of the our corrigendum rule (if you want a wording change, you have to propose one), I've made an attempt to rewrite this AI to address his concerns. I've also added points 3 and 5 from AI-195 to the discussion of this AI, as they are addressed in the corrigendum wording. Here is my latest cut at the wording: Replace 13.1(15) by the following (the first paragraph is unchanged from the previous Corrigendum): 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, whether operational aspects are inherited for a derived type depends on the specific aspect. When operational aspects are inherited for a derived type, aspects that were directly specified before the declaration of the derived type, or (in the case where the parent is derived) that were inherited by the parent type from the grandparent type are inherited. An inherited operational aspect is overridden by a subsequent operational item that specifies the same aspect of the type. Add after 13.1(18): If an operational aspect is specified for an entity (meaning that it is either directly specified or inherited), then that aspect of the entity is as specified. Otherwise, the aspect of the entity has the default value determined by the specific aspect. Replace 13.3(75) by: S'External_Tag S'External_Tag denotes an external string representation for S'Tag; it is of type String. External_Tag may be specified for a specific tagged type via an attribute_definition_clause; the expression of such a clause shall be static. The default external tag representation is implementation-defined. See 3.9.2 and 13.13.2. The value of External_Tag is never inherited[; the default value is always used unless it is directly specified for a type]. Replace 13.13.2(9) by: For untagged derived types, the Write or Read attribute of the parent type is inherited if it was directly specified for some ancestor type; otherwise, the default implementation of the attribute is used. For other derived types, the Write or Read attribute is not inherited; the default implementation is always used. The default implementation of Write and Read attributes is defined as follows: 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 T is an array type. If T is a discriminated type, discriminants are included only if they have defaults. If T is a tagged type, the tag is not included. For 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. Replace 13.13.2(25) by: For untagged derived types, the Output or Input attribute of the parent type is inherited if it was directly specified for some ancestor type; otherwise, the default implementation of the attribute is used. For other derived types, the Output or Input attribute is not inherited; the default implementation is always used. The default implementation of the Output and Input operations execute as follows: Replace 13.13.2(36) by: The stream-oriented attributes may be specified for any type via an attribute_definition_clause. All nonlimited types have default implementations for these operations. An attribute_reference for one of these attributes is illegal if the type is limited, unless the attribute has been specified by an attribute_definition_clause or (for a type extension) all of the attributes called by the default implementation can be referenced by this rule. For an attribute_definition_clause 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. (The changes previously proposed for 13.13.2(26-27) are removed.) ----- Notes: I used square brackets above in the manner of the AARM. These don't appear in the corrigendum. 13.1(18) is in fact wrong for 'Read/'Write/'Input/'Output as the default value is determined by the various rules; it certainly is not "chosen in an unspecified manner". Another reason to define operational attributes... 13.3(75) needed to be changed to say that 'External_Tag values are never inherited. 13.13.2(9) needed to say that default definitions are never inherited, only specified ones. (This is point 5 from the unfinished AI-195 -- the discriminants included may be different, and we don't want to write both sets). This could be removed (given that AI-195 wasn't finished), but doing so doesn't help the wording much. It also needed to name the "default implementations" (or some similar term); otherwise, it gets very awkward. Finally, (of course), it needed to say that untagged types inherit these aspects, while tagged types do not. Note that all type extensions inherit their components. See below for more on this. 13.13.2(25) needed wording similar to 13.13.2(9). Note that this wording is repeated here in case it needs to be different from that in 13.13.2(9) [which would be the case if I lose the argument over 195 pt. 3 for instance]; these attributes are sufficiently different to treat them separately. 13.13.2(36) needed wording to allow calling Read and Write for limited type extensions when all of the attributes that make up the extension exist. This purposely is a different conclusion than the unfinished AI-195 pt. 3 comes to. However, just inheriting existing attributes (thus silently ignoring any extension components) seems to be more likely to cause bugs than provide anything useful. Ada 95 goes pretty far to avoid silently dropping extension components, yet a distributed system using these attributes could very well end up ignoring the extensions completely. This rule (combined with the new 13.13.2(9)) allows limited extensions to work properly so long as all of the attributes are well defined. If any of them are not defined (either because they are limited and are not specified), then the attributes cannot be called. This seems to provide the maximum compatibility with the old, buggy rules (we get inheritance for null extensions, and we get inheritance with extension if all of the components are non-limited or have specified attributes), while preventing the bugs caused by silently ignoring components. I suspect that this change would find/fix more bugs than breaking correct programs. And the fix is easy if a user *really* wants inheritance without the extension components: just add an attribute_clause for the appropriate routine (presumably inherited as well - it has to be primitive for the parent type). **************************************************************** From: Tucker Taft Sent: Thursday, June 01, 2000 9:25 PM > Despite Tucker's violation of the our corrigendum rule (if you want a > wording change, you have to propose one), I've made an attempt to rewrite > this AI to address his concerns. I've also added points 3 and 5 from AI-195 > to the discussion of this AI, as they are addressed in the corrigendum > wording. Thanks for taking the time to do this. See below for comments. > > Here is my latest cut at the wording: > > Replace 13.1(15) by the following (the first paragraph is unchanged from the > previous Corrigendum): > > 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, whether operational aspects are inherited for a derived type > depends on the specific aspect. When operational aspects are inherited for a > derived type, aspects that were directly specified before the declaration of > the derived type, or (in the case where the parent is derived) that were > inherited by the parent type from the grandparent type are inherited. An > inherited operational aspect is overridden by a subsequent operational item > that specifies the same aspect of the type. Do you think it would be useful to establish a default? E.g., unless stated otherwise in this standard, operational attributes are (not?) inherited by derived types. I wonder whether this whole thing could be simplified by defining something like "an aspect supports inheritance" to mean all of the gobbledygook about being specified before the point of derivation. Then there is no need to repeat all that stuff everytime. Otherwise, I fear there will be little bugs in your wording (see below for examples) when all we are trying to say is that it supports inheritance. > Add after 13.1(18): > > If an operational aspect is specified for an entity (meaning that it is > either directly specified or inherited), then that aspect of the entity is > as specified. Otherwise, the aspect of the entity has the default value > determined by the specific aspect. Is the above paragraph really necessary? This sounds like a "to be pedantic" section to be included in the AARM only. Perhaps if it was combined with establishing a default rule on operational attribute inheritance, it wouldn't sound so silly. > Replace 13.3(75) by: > > S'External_Tag S'External_Tag denotes an external string representation for > S'Tag; it is of type String. External_Tag may be specified for a specific > tagged type via an attribute_definition_clause; the expression of such a > clause shall be static. The default external tag representation is > implementation-defined. See 3.9.2 and 13.13.2. The value of External_Tag is > never inherited[; the default value is always used unless > it is directly specified for a type]. > > Replace 13.13.2(9) by: > > For untagged derived types, the Write or Read attribute of the parent type > is inherited if it was directly specified for some ancestor type; otherwise, > the default implementation of the attribute is used. For other derived > types, the Write or Read attribute is not inherited; the default > implementation is always used. Why say "For other derived types" when "For tagged derived types" is equivalent? Another reason to switch to this wording is that the above paragraph has "otherwise..." and then "For other ..." That seems bound to cause confusion. Perhaps even better than "For tagged derived types" might be "For type extensions..." This paragraph also seems to have one of the "little bugs" I mentioned above because it says it is "inherited if it was directly specified for some ancestor type" but omits the discussion about the specification happening before the derivation. Again, I think switching to something simple like "For untagged derived types, the Write and Read attributes support inheritance; for tagged derived types, the attributes are not inherited." > The default implementation of Write and Read attributes is defined as > follows: > 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 T is > an array type. If T is a discriminated type, discriminants are included only > if they have defaults. If T is a tagged type, the tag is not included. For > 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. Remember that discriminants are also "components." For tagged types, they never have defaults, so it is safe to say "... of each non-inherited non-discriminant component..." (safe to say, yes; easy to say, no ;-). Or even better: "... of each component of the extension part ..." > Replace 13.13.2(25) by: > > For untagged derived types, the Output or Input attribute of the parent type > is inherited if it was directly specified for some ancestor type; otherwise, > the default implementation of the attribute is used. For other derived > types, the Output or Input attribute is not inherited; the default > implementation is always used. Again, why not say "For tagged derived types..." (or "For type extensions..."). Also another one of the "little bugs" appears here. Again, an alternative is "For untagged derived types, the Output and Input attributes support inheritance; for tagged derived types, the Output and Input attributes are not inherited." > > The default implementation of the Output and Input operations execute as > follows: > > Replace 13.13.2(36) by: > > The stream-oriented attributes may be specified for any type via an > attribute_definition_clause. All nonlimited types have default > implementations for these operations. An attribute_reference for one of > these attributes is illegal if the type is limited, unless the attribute has > been specified by an attribute_definition_clause or (for a type extension) > all of the attributes called by the default implementation can be referenced > by this rule. This doesn't seem quite right. Suppose the type is a limited private extension of a type with specified stream attributes. How do you know whether it is legal to call the attributes on the extension? I suggest the following: If a limited tagged type specifies a Write or Read attribute, then the corresponding attribute may be legally called on any non-abstract descendant. However, the default implementation of the stream attribute on such a descendant is (effectively) abstract if its parent type or an extension component does not have a legally callable corresponding attribute, in which case the attribute *must* be directly specified. (This is analogous to the rule for functions with controlling results.) Furthermore, I would suggest that Output and Input piggy back automatically on Write and Read, even for limited types: If the Read attribute of a type can legally be called, then the Input attribute has a non-abstract default implementation; similarly, if the Write attribute of a type can legally be called, then the Output attribute has a non-abstract default implementation. > ... For an > attribute_definition_clause 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. > > > (The changes previously proposed for 13.13.2(26-27) are removed.) > ... > 13.13.2(36) needed wording to allow calling Read and Write for limited type > extensions when all of the > attributes that make up the extension exist. See above for comments on the "privacy violation" aspects of this proposal. I think it can be fixed by adopting rules analogous to those for functions with controlling results. **************************************************************** From: Randy Brukardt Sent: Friday, June 02, 2000 5:12 PM > > Replace 13.1(15) by the following (the first paragraph is unchanged from the > > previous Corrigendum): > > > > 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, whether operational aspects are inherited for a derived type > > depends on the specific aspect. When operational aspects are inherited for a > > derived type, aspects that were directly specified before the declaration of > > the derived type, or (in the case where the parent is derived) that were > > inherited by the parent type from the grandparent type are inherited. An > > inherited operational aspect is overridden by a subsequent operational item > > that specifies the same aspect of the type. > > Do you think it would be useful to establish a default? > E.g., unless stated otherwise in this standard, operational attributes > are (not?) inherited by derived types. Not really. It wouldn't save much more than one line in the current situation (the added line in 13.3(75).) OTOH, it might be helpful if we ever try to add another one of these. What does everyone else think? > I wonder whether this whole thing could be simplified by defining something > like "an aspect supports inheritance" to mean all of the gobbledygook > about being specified before the point of derivation. Then there is > no need to repeat all that stuff everytime. Otherwise, I fear there > will be little bugs in your wording (see below for examples) when > all we are trying to say is that it supports inheritance. I thought that too; in fact, that was what I originally tried to do. And failed to come up with anything that made sense. That was partially because I couldn't come up with a term that seemed to have the right meaning. "An aspect supports inheritance" probably would work for defining the term, but I don't see how to use it after it was defined. I was thinking that these two paragraphs defines formally what it means to inherit an aspect. Then the use of the word "inherits" in other places was meant to invoke these paragraphs. I suppose we could try something like: --- If a type related aspect is @i @defn2(inherit, an aspect) for a derived type, only aspects that were directly specified before the declaration of the derived type, or (in the case where the parent is derived) that were inherited by the parent type from the grandparent type are inherited. If a subtype related aspect is @i for a derived subtype, only aspects of the parent subtype that were directly specified before the declaration of the derived type, or (in the case where the parent is derived) that were inherited by the parent type from the grandparent type, but only if the parent subtype statically matches the first subtype of the parent type are inherited. An inherited aspect is overridden by a subsequent aspect item that specifies the same aspect of the type or subtype. Aspects of representation are always inherited [as described above]. In contrast, whether operational aspects are inherited depends on the specific aspect. ---- This wording could stand improvement! If you don't like this, please suggest something better! Please? :-) > > Add after 13.1(18): > > > > If an operational aspect is specified for an entity (meaning that it is > > either directly specified or inherited), then that aspect of the entity is > > as specified. Otherwise, the aspect of the entity has the default value > > determined by the specific aspect. > > Is the above paragraph really necessary? This sounds like a "to be pedantic" > section to be included in the AARM only. Perhaps if it was combined > with establishing a default rule on operational attribute inheritance, > it wouldn't sound so silly. Well, it's necessary, because you pointed out that "specified" has a specific meaning. However, that meaning is only defined for representation aspects in 13.1(16-18), and we can't reuse those paragraphs to define it for operational aspects (because of 13.1(18), which is just outright wrong for stream attributes [and always has been - there should have been an AI on that, too, except that no one ever really believed it.]) And we need to use "specified" in 13.13.2, so leaving it undefined is not really an option. Without the definition of "specified", it's pretty silly, but then again, so are 13.1(16-18), and someone thought *they* needed to be in the RM. A suggestion for an improvement here is welcome as well... > > Replace 13.13.2(9) by: > > > > For untagged derived types, the Write or Read attribute of the parent type > > is inherited if it was directly specified for some ancestor type; otherwise, > > the default implementation of the attribute is used. For other derived > > types, the Write or Read attribute is not inherited; the default > > implementation is always used. > > Why say "For other derived types" when "For tagged derived types" is > equivalent? Because that was the way it previously was done (except in reverse). I certainly have no objection to this change (I'll make it in the AI). > Another reason to switch to this wording is that the above > paragraph has "otherwise..." and then "For other ..." > That seems bound to cause confusion. > Perhaps even better than "For tagged derived types" might be > "For type extensions..." I don't like that change, because it always leads me to ask "what about tagged derived types that aren't extensions?". Of course, after thinking about it, I remember that there aren't any such things, but it *always* breaks my train of thought. > This paragraph also seems to have one of the "little bugs" I mentioned > above because it says it is "inherited if it was directly specified > for some ancestor type" but omits the discussion about the specification > happening before the derivation. Again, I think switching to something > simple like "For untagged derived types, the Write and Read attributes > support inheritance; for tagged derived types, the attributes are > not inherited." No, that phrase "if it was directly specified for some ancestor type" is intended to be ADDED to all of the stuff in 13.1(15/1). It is trying to deal with the changing discriminants problem, which means we never want to inherit a default implemented aspect. (That's point 5 of AI-00195.) It seems that the revised wording for 13.1(15/1) seems to say that only specified aspects are inherited. Indeed, the original wording seems to say this as well. In that case, point 5 of AI-00195 is just a confirmation -- it doesn't change anything except some poorly worded discussion material in AI-00108. Assuming the previously proposed change for 13.1(15/1), and assuming that default values for aspects are never inherited, then we could simply say: --- For untagged derived types, the Write or Read attribute of the parent type is inherited as specified in 13.1; otherwise, the default implementation of the attribute is used. For tagged derived types, the Write or Read attribute is not inherited; the default implementation is always used. --- Is this better? > > The default implementation of Write and Read attributes is defined as > > follows: > > 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 T is > > an array type. If T is a discriminated type, discriminants are included only > > if they have defaults. If T is a tagged type, the tag is not included. For > > 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. > > Remember that discriminants are also "components." For tagged types, > they never have defaults, so it is safe to say "... of each non-inherited > non-discriminant component..." (safe to say, yes; easy to say, no ;-). > Or even better: "... of each component of the extension part ..." Well, that wording is unchanged from the last three versions of this AI...but you're right of course. I've changed it to the latter version. > > Replace 13.13.2(25) by: > > > > For untagged derived types, the Output or Input attribute of the parent type > > is inherited if it was directly specified for some ancestor type; otherwise, > > the default implementation of the attribute is used. For other derived > > types, the Output or Input attribute is not inherited; the default > > implementation is always used. > > Again, why not say "For tagged derived types..." (or "For type extensions..."). > Also another one of the "little bugs" appears here. Again, an > alternative is "For untagged derived types, the Output and Input > attributes support inheritance; for tagged derived types, the > Output and Input attributes are not inherited." I would use (with all of the caveats above): ---- For untagged derived types, the Output or Input attribute of the parent type is inherited as specified in 13.1; otherwise, the default implementation of the attribute is used. For tagged derived types, the Output or Input attribute is not inherited; the default implementation is always used. ---- > > Replace 13.13.2(36) by: > > > > The stream-oriented attributes may be specified for any type via an > > attribute_definition_clause. All nonlimited types have default > > implementations for these operations. An attribute_reference for one of > > these attributes is illegal if the type is limited, unless the attribute has > > been specified by an attribute_definition_clause or (for a type extension) > > all of the attributes called by the default implementation can be referenced > > by this rule. > > This doesn't seem quite right. Suppose the type is a limited private > extension of a type with specified stream attributes. How do you > know whether it is legal to call the attributes on the extension? I wanted to define this in 13.13.2(9) so there wasn't a problem, but that would have caused nasty forward reference. I then tried here, which I didn't think about much . > I suggest the following: If a limited tagged type specifies a Write or Read > attribute, then the corresponding attribute may be legally called > on any non-abstract descendant. However, the default implementation of the > stream attribute on such a descendant is (effectively) abstract if its > parent type or an extension component does not have a legally callable > corresponding attribute, in which case the attribute *must* be > directly specified. (This is analogous to the rule for functions > with controlling results.) OK, let's try the following: The stream-oriented attributes may be specified for any type via an attribute_definition_clause. All nonlimited types have default implementations for these operations. An attribute_reference for one of these attributes is illegal if the type is limited, unless the attribute has been specified by an attribute_definition_clause or (for a type extension) the attribute has been directly specified for an ancestor type. Then add the following to 13.13.2(9): For a limited type extension, if the attribute of any ancestor type has been directly specified and the attribute of any ancestor type of any of the limited extension components has not been specified, the attribute of @i shall be directly specified. --- This is bit different than Tucker's suggestion, mainly so that there is no requirement to specify an attribute if the parent attribute wasn't specified. I also used "specified" (in the sense of 13.1(18/1) - the paragraph Tucker would like to get rid of) rather than "callable" - which would require a definition. This gets a bit messy because limited type extension's attributes can be callable without being "specified" (inherited or directly specified); but in that case, some ancestor type must have been directly specified. > Furthermore, I would suggest that Output and Input piggy back automatically > on Write and Read, even for limited types: > If the Read attribute of a type can legally be called, then the Input > attribute has a non-abstract default implementation; similarly, > if the Write attribute of a type can legally be called, then > the Output attribute has a non-abstract default implementation. This seems like a good idea, but it's going well beyond the AI, or even what is currently in AI-00195. I don't want to bog the corrigendum down at the last minute with good ideas... I suggest that we add that to AI-195. Clearly, this wouldn't conflict with the current wording (which defines that these always use the default implementation, but leaves them uncallable for limited types). But I'm not sure it is useful for the implementation burden -- Input is a function after all, and limited functions aren't very useful. **************************************************************** From: Randy Brukardt Sent: Friday, July 07, 2000 7:44 PM While editing DR-40, I noticed a minor glitch in the last sentence of 13.13.2(9). The problem is that the sentence twice uses "ancestor type" without identifying what type the ancestor type is of (and the two uses are different). I suggest adding a few extra words to fix this (the insertions are marked with {}): For a limited type extension, if the attribute of any ancestor type {of @i} has been directly specified and the attribute of any ancestor type {of the type} of any of the extension components which are of a limited type has not been specified, the attribute of @i shall be directly specified. This sentence is a real mouthful, but I believe it has the correct effect. If anyone has an improvement to this sentence, or an objection to my change, please speak up *now*. Randy. ****************************************************************