Version 1.5 of ai05s/ai05-0126-1.txt
!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); --
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)
Replace the paragraph:
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:
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;
!corrigendum 3.9.2(20.1/2)
Replace the paragraph:
- 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;
by:
- 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;
!corrigendum 3.9.2(20.2/2)
Replace the paragraph:
- otherwise, the action is the same as the action for
the corresponding operation of the parent type.
by:
- 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.
!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)
<corresponding parts of similar triangles>
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.
****************************************************************
Questions? Ask the ACAA Technical Agent