!standard 3.9.2(20/2) 09-05-30 AI05-0126-1/03 !standard 3.9.2(20.1/2) !standard 3.9.2(20.2/2) !class binding interpretation 08-10-22 !status Amendment 201Z 08-11-26 !status WG9 Approved 09-06-12 !status ARG Approved 8-0-0 08-11-02 !status work item 08-10-22 !status received 08-10-03 !priority Medium !difficulty Hard !subject Dispatching when there is no declared operation !summary When there is no corresponding inherited operation explicitly or implicitly declared, dispatching executes the operation that the parent type would execute. !question Consider: package P is type Root is tagged private; procedure Oper (Obj : Root'Class); private procedure Hidden (Obj : Root); end; package body P is procedure Oper (Obj : Root'Class) is begin ... Hidden (Obj); -- Dispatching end Oper; end P; with P; package Q is type Child is new P.Root with null record; end Q; with P, Q; procedure Main is X : Q.Child; begin P.Oper (X); end Main; How does the dispatching call Hidden (Obj) work? 3.9.2(20-20.2/2) says that the "action performed is determined by the properties of the corresponding dispatching operation of the specific type identified by the controlling tag value". But in this case, type Child has an inherited operation Hidden which exists but is never implicitly declared anywhere for type Child. Should the wording cover this case? (Yes.) !recommendation (See Summary.) !wording Replace 3.9.2(20/2-20.2/2) by: For the execution of a call on a dispatching operation, the action performed is determined by the properties of the corresponding dispatching operation of the specific type identified by the controlling tag value: * if the corresponding operation is explicitly declared for this type, Redundant:[even if the declaration occurs in a private part], then the action comprises an invocation of the explicit body for the operation; * if the corresponding operation is implicitly declared for this type and is implemented by an entry or protected subprogram (see 9.1 and 9.4), then the action comprises a call on this entry or protected subprogram, with the target object being given by the first actual parameter of the call, and the actual parameters of the entry or protected subprogram being given by the remaining actual parameters of the call, if any; * otherwise, the action is the same as the action for the corresponding operation of the parent type or progenitor type from which the operation was inherited. Replace the To Be Honest AARM note 3.9.2(20.a) with an AARM Ramification: "Corresponding operation" refers to the inheritance relationship between subprograms. Primitive operations are always inherited for a type T, but they may not be declared if the primitive operation is never visible within the immediate scope of the type T. If no corresponding operation is declared, the corresponding operation of the parent type is executed (an explicit body that happens to have the same name and profile is never called). Thus, any explicit declaration for an inherited corresponding operation has to be an overriding routine. !discussion "Corresponding operation" refers to the inheritance relationship between subprograms, and not any random subprogram with the same name and profile. Thus, any explicit declaration for an inherited corresponding operation has to be an overriding routine. We don't talk about overriding in this wording as we also have to take into account the original root declarations (which may have a body). AARM 3.9.2(20.a) refers to the original Ada 95 wording, and doesn't seem to be necessary with the current wording. Thus we can replace it with new wording to explain "corresponding operation". !corrigendum 3.9.2(20/2) @drepl For the execution of a call on a dispatching operation, the action performed is determined by the properties of the corresponding dispatching operation of the specific type identified by the controlling tag value. If the corresponding operation is explicitly declared for this type, even if the declaration occurs in a private part, then the action comprises an invocation of the explicit body for the operation. If the corresponding operation is implicitly declared for this type: @dby For the execution of a call on a dispatching operation, the action performed is determined by the properties of the corresponding dispatching operation of the specific type identified by the controlling tag value: @xbullet !corrigendum 3.9.2(20.1/2) @drepl @xbullet @dby @xbullet !corrigendum 3.9.2(20.2/2) @drepl @xbullet @dby @xbullet !ACATS Test It is thought that existing ACATS tests try examples like this. !appendix !topic Did key information about dispatching get lost? !reference RM05 3.9.2(20) !from Adam Beneschan 08-10-03 !discussion While looking into the language rules related to an issue brought up on comp.lang.ada, I noticed that a change in 3.9.2(20) may have caused some important information to be lost from the RM. In RM95, this paragraph reads: For the execution of a call on a dispatching operation, the body executed is the one for the corresponding primitive subprogram of the specific type identified by the controlling tag value. The body for an explicitly declared dispatching operation is the corresponding explicit body for the subprogram. The body for an implicitly declared dispatching operation that is overridden is the body for the overriding subprogram, even if the overriding occurs in a private part. The body for an inherited dispatching operation that is not overridden is the body of the corresponding subprogram of the parent or ancestor type. This makes it clear that if you dispatch to a routine, and the inherited operation for a specific type has been overridden, the dispatching operation will call the body of the overriding subprogram. (I'm not convinced that this makes everything entirely clear in some cases; say Child_1 inherits from the parent, Child_2 inherits from Child_1 and then overrides it, Child_3 inherits from Child_2 without overriding; mix in the possibility that a child could declare a *separate* operation with the same name and profile due to visibility, and it is arguable that the above language isn't enough to make it clear how the dispatching operation would work in some complex cases.) But in RM05, this paragraph was replaced by these three: For the execution of a call on a dispatching operation, the action performed is determined by the properties of the corresponding dispatching operation identified by the controlling tag value. If the corresponding operation is explicitly declared for this type, even if the declaration occurs in a private part, then the action comprises an invocation of the explicit body for the operation. If the corresponding operation is implicitly declared for this type: * if the operation is implemented by an entry or protected subprogram (see 9.1 and 9.4), then the action comprises a call on this entry or protected subprogram, with the target object being given by the first actual parameter of the call, and the actual parameters of the entry or protected subprogram being given by the remaining actual parameters of the call, if any; * otherwise, the action is the same as the action for the corresponding operation of the parent type. There's no reference to overriding at all. The language refers to the "corresponding dispatching operation", but I did some searching and couldn't find a place where this term, or anything like it, is defined, and it isn't in the index. Perhaps this is clarified somewhere else in the manual, although apparently I wouldn't know where to look. But based just on what I've found so far, there doesn't seem to be any explanation of how "dispatching" and "overriding" are connected. And, of course, this is a very important connection. **************************************************************** From: Randy Brukardt Date: Monday, October 20, 2008 9:28 PM I don't see the point. While it is valuable for a textbook to show a connection between dispatching and overriding, the standard has no such need to mix up static and dynamic concepts. "Overriding" is purely a declaration concept (which allows having multiple declarations of the "same" subprogram). This text describes how dispatching occurs - an explicit routine is called, if any, and then what happens if there is not an explicit routine. The text purposely dropped all of the blather about implicitly declared operations, because that is irrelevant to the dynamic execution of the dispatching operation. I think "corresponding" is used in its English sense, so looking for a term somewhere is not going to help anything. In this case, it means the routine that corresponds to the inherited one. Perhaps this last bullet probably could be better, but it is hardly worth rewriting in the absence of any error. (Especially as it has nothing to do with overriding). I would agree that this rewrite didn't do anything to enhance the readability/understandability of the Standard, but there is nothing *wrong* with it, so there isn't any need to spend a lot of effort on a correction. [Afterthought: In Ada 95, the term "overriding" is not indexed here, so it isn't considered important to the definition of that term.] **************************************************************** From: Adam Beneschan Date: Tuesday, October 21, 2008 4:30 PM > I think "corresponding" is used in its English sense, so looking for a > term somewhere is not going to help anything. I don't think the English sense helps. Here's the relevant definition from m-w.com (Merriam-Webster online): 1 a: having or participating in the same relationship (as kind, degree, position, correspondence, or function) especially with regard to the same or like wholes (as geometric figures or sets) I just don't see how, without some prior knowledge, one can know how to determine what sort of "same relationship" is being talked about. There has to be some context, and I am not convinced that RM05 provides that context. That's why I mentioned the need for looking for a definition for that term; there doesn't seem to be enough there to apply the straight English meaning of the word. I didn't intend to imply that the RM should be like a textbook. To me, for a Standard, it is enough that someone with a good knowledge of English and a knowledge of basic computer and programming concepts, but no prior knowledge of Ada, should be able to read the whole RM and, assuming they have an amazing mental capacity to comprehend the entire large manual all at once, determine what the Standard says about how a dispatching operation gets executed. Even if it's hard for an ordinary person like me (or, more accurately, a somewhat weird person like me) to find the answer because it require some searching around, my hypothetical Amazing Mental Capacity Person wouldn't have this problem because he/she can comprehend the entire RM at once and doesn't need to search. But it's my contention that AMCP wouldn't be able to answer this simple question: If X has type Root'Class, and Oper(X) is a dispatching operation, what body is executed when Oper(X) is called? Especially if X's specific type has another homographic but non-overriding operation named Oper, due to private parts causing the same sorts of visibility issues that led to my other recent post. *We* know what the answer is, but that's just because we already know. But I don't think the RM actually provides enough information for my AMCP to know. (Sure, if the AMCP also had the Ada 95 manual, he/she might be able to figure it out, but isn't the Ada 2005 Standard supposed to Stand on its own?) And I really do not believe that the term "corresponding" is nearly enough to provide the needed information. The problem, I think, is that since the way dispatching works in Ada has become so ingrained in us, it's hard for us to take a few steps backward to see how someone with no prior knowledge would understand the RM's language. And I realize that most people would be learning from textbooks rather than the Standard. But the Standard is supposed to Stand on its own, or so I thought; and if you need a textbook in order to interpret the Standard correctly, then I think that means there's a hole in the Standard. If I'm wrong and there *is* sufficient context in RM05 to interpret "corresponding" correctly, could someone please point out what paragraphs this context is in? I wasn't able to find them. > In this case, it means the routine > that corresponds to the inherited one. Perhaps this last bullet > probably could be better, but it is hardly worth rewriting in the > absence of any error. (Especially as it has nothing to do with overriding). I don't understand the assertion in parentheses. To answer the above question: If X has type Root'Class, and Oper(X) is a dispatching operation, what body is executed when Oper(X) is called? if X has specific type T, then loosely speaking, the body that gets executed is either the one defined for Root, or the body of a subprogram that overrides one that is inherited from Root, for T or some ancestor of T. don't see how you can answer the question without reference to the notion of overriding. > I would agree that this rewrite didn't do anything to enhance the > readability/understandability of the Standard, but there is nothing > *wrong* with it, so there isn't any need to spend a lot of effort on a correction. Sorry, I still think there's an omission. **************************************************************** From: Randy Brukardt Date: Tuesday, October 21, 2008 5:52 PM But my point is that that the bullet that is slightly unclear has nothing to do with overriding. It's all about inheritance, and only inheritance. It means something like: * otherwise, the action is the same as the action for the corresponding operation of the parent type (of the implicitly declared inherited operation). There is no difficulty at all in understanding what happens in your question: (1) Resolve Oper(X) to a single matching operation. (2) Determine the specific type of the object X (sentence 1, para 20) (3) Find the corresponding dispatching operation for the specific type (sentence 1, para 20) [this is the one inherited from the matching operation] (4) Is there an explicit declaration? If so, call that body (sentence 2, para 20). [this explicit declaration would have to be overriding, else it is an illegal homograph.] (5) Else (ignoring "implemented by" for the moment), go to the corresponding routine of the parent type and try again (from step 3). (para 20.2). Now, the only question is whether some other interpretation of "corresponding" makes sense. And I can't think of one; we use the similar wording for describing how generics are expanded (and what operations that they get), for instance. Considering "corresponding" to somehow relate unrelated things (say similar only by name) doesn't make any sense, especially considering the way the word is used in the rest of the Standard. It should be noted that your proposal in the other message does not work with this wording, so if that was accepted (I think that is unlikely, but some other solution may be considered), then something would need to be done. (In that wording, there is no inherited operation to work from.) In any case, I don't see any way to rewrite this text to include the text about inheritance. I tried it above and the result makes less sense than the original -- that's not helping. So I think you need to suggest a rewrite if you think this is important. **************************************************************** From: Randy Brukardt Date: Tuesday, October 21, 2008 6:01 PM > if X has specific type T, then loosely speaking, the body that gets > executed is either the one defined for Root, or the body of a > subprogram that overrides one that is inherited from Root, for T or > some ancestor of T. I don't see how you can answer the question > without reference to the notion of overriding. That's the textbook version. The Standard version is that it is the "corresponding explicit body". Moreover, as you pointed out in your original question, wording based solely on "overriding" doesn't even work (even before trying to factor in "implemented by"). And remember that in Ada 2005 (as corrected), an "implemented by" routine may override another, but it doesn't provide an explicit body to call. So we can't use that notion exclusively in any case. If there is an omission in these paragraphs, it's the failure to make it clear that "corresponding" here means the inheritance relationship. But I can't imagine any other relationship that it could mean. **************************************************************** From: Randy Brukardt Date: Tuesday, October 21, 2008 7:15 PM > Sorry, I still think there's an omission. In further thinking about it, I think you are right that there is an omission, but it isn't anything to do with anything that you have been talking about. The problem is that the wording as written doesn't handle the case where there is no corresponding primitive operation (that is, nothing was inherited from the parent because of privacy or whatever). In that case, we're supposed to fall into the last bullet and look at the parent, but because it is prefixed by "if the corresponding operation is implicitly declared for this type", we don't get there. That's easily fixed by adding "if the corresponding operation is implicitly declared for this type {or there is no corresponding operation for this type}:". That doesn't do anything for your complaint, so you need to propose something if you want any action. ****************************************************************