3.9.2 Dispatching Operations of Tagged Types
1/2
{
AI95-00260-02}
{
AI95-00335-01}
The
primitive subprograms of a tagged type
, the subprograms
declared by formal_abstract_subprogram_declarations,
and the stream attributes of a specific tagged type that are available
(see 13.13.2) at the end of the declaration
list where the type is declared are called
dispatching operations.
[A dispatching operation can be called using a statically determined
controlling tag, in which case the body to be executed is determined
at compile time. Alternatively, the controlling tag can be dynamically
determined, in which case the call
dispatches to a body that is
determined at run time;] such a call is termed a
dispatching call.
[As explained below, the properties of the operands and the context of
a particular call on a dispatching operation determine how the controlling
tag is determined, and hence whether or not the call is a dispatching
call. Run-time polymorphism is achieved when a dispatching operation
is called by a dispatching call.]
1.a.1/2
Reason: {
AI95-00335-01}
For the stream attributes of a type declared immediately
within a package_specification
that has a partial view, the declaration list to consider is the visible
part of the package. Stream attributes that are not available in the
same declaration list are not dispatching as there is no guarantee that
descendants of the type have available attributes (there is such a guarantee
for visibly available attributes). If we allowed dispatching for any
available attribute, then for attributes defined in the private part
we could end up executing a non-existent body.
Language Design Principles
1.a
The controlling tag determination rules are
analogous to the overload resolution rules, except they deal with run-time
type identification (tags) rather than compile-time type resolution.
As with overload resolution, controlling tag determination may depend
on operands or result context.
Static Semantics
2/3
{
AI95-00260-02}
{
AI95-00416-01}
{
AI05-0076-1}
A
call on a dispatching operation
is a call whose
name
or
prefix
denotes the declaration of
a primitive subprogram
of a tagged type, that is, a dispatching operation.
A
controlling operand in a call on a dispatching operation of a
tagged type
T is one whose corresponding formal parameter is of
type
T or is of an anonymous access type with designated type
T;
the corresponding formal parameter is called
a
controlling formal parameter. If the controlling formal parameter
is an access parameter, the controlling operand is the object designated
by the actual parameter, rather than the actual parameter itself.
If
the call is to a (primitive) function with result type
T (a function with a controlling result), then the call has
a
controlling result — the context of the call can control
the dispatching.
Similarly, if the call is to a
function with an access
result type designating T (a function
with a controlling access result), then
the call has a controlling access result, and the context can
similarly control dispatching.
2.a
Ramification: This definition implies
that a call through the dereference of an access-to-subprogram value
is never considered a call on a dispatching operation. Note also that
if the
prefix
denotes a
renaming_declaration,
the place where the renaming occurs determines whether it is primitive;
the thing being renamed is irrelevant.
3
A
name
or expression of a tagged type is either
statically tagged,
dynamically
tagged, or
tag indeterminate, according to whether, when used
as a controlling operand, the tag that controls dispatching is determined
statically by the operand's (specific) type, dynamically by its tag at
run time, or from context. A
qualified_expression
or parenthesized expression is statically, dynamically, or indeterminately
tagged according to its operand. For other kinds of
names
and expressions, this is determined as follows:
4/2
{
AI95-00416-01}
The
name
or expression is
statically tagged if it is of a specific tagged
type and, if it is a call with a controlling result
or controlling access result, it has at least one statically tagged
controlling operand;
4.a
Discussion: It is illegal to have both
statically tagged and dynamically tagged controlling operands in the
same call -- see below.
5/2
{
AI95-00416-01}
The
name
or expression is
dynamically tagged if it is of a class-wide type,
or it is a call with a controlling result
or controlling
access result and at least one dynamically tagged controlling
operand;
6/2
{
AI95-00416-01}
The
name
or expression is
tag indeterminate if it is a call with a controlling
result
or controlling access result, all
of whose controlling operands (if any) are tag indeterminate.
7/1
{
8652/0010}
{
AI95-00127-01}
[A
type_conversion
is statically or dynamically tagged according to whether the type determined
by the
subtype_mark
is specific or class-wide, respectively.]
For an
object that is designated by an expression whose expected type is an
anonymous access-to-specific tagged type, the object is dynamically tagged
if the expression, ignoring enclosing parentheses, is of the form X'Access,
where X is of a class-wide type, or is of the form new T'(...),
where T denotes a class-wide subtype. Otherwise, the object For
a controlling operand that is designated by an actual parameter, the
controlling operand is statically or dynamically tagged according
to whether the designated type
of the type of the
expression of the actual parameter
is specific or class-wide, respectively.
7.a
Ramification: A
type_conversion
is never tag indeterminate, even if its operand is. A designated object
is never tag indeterminate.
7.a.1/1
{
8652/0010}
{
AI95-00127-01}
Allocators and access attributes of class-wide
types can be used as the controlling parameters of dispatching calls.
Legality Rules
8
A call on a dispatching operation shall not have
both dynamically tagged and statically tagged controlling operands.
8.a
Reason: This restriction is intended
to minimize confusion between whether the dynamically tagged operands
are implicitly converted to, or tag checked against the specific type
of the statically tagged operand(s).
9/1
{
8652/0010}
{
AI95-00127-01}
If the expected type for an expression or
name
is some specific tagged type, then the expression or
name
shall not be dynamically tagged unless it is a controlling operand in
a call on a dispatching operation. Similarly, if the expected type for
an expression is an anonymous access-to-specific tagged type, then the
object designated by the expression shall not be
dynamically tagged unless it is expression
shall not be of an access-to-class-wide type unless it designates
a controlling operand in a call on a dispatching operation.
9.a
Reason: This prevents implicit "truncation"
of a dynamically-tagged value to the specific type of the target object/formal.
An explicit conversion is required to request this truncation.
9.b/2
Ramification: {
AI95-00252-01}
This rule applies to all expressions or
names
with a specific expected type, not just those that are actual parameters
to a dispatching call. This rule does not apply to a membership test
whose
expression
is class-wide, since any type that covers the tested type is explicitly
allowed. See
4.5.2.
This rule also doesn't apply to a selected_component
whose selector_name
is a subprogram, since the rules explicitly say that the prefix may be
class-wide (see 4.1.3).
10/2
{
8652/0011}
{
AI95-00117-01}
{
AI95-00430-01}
In the declaration of a dispatching operation of a tagged type, everywhere
a subtype of the tagged type appears as a subtype of the profile (see
6.1), it shall statically match the first subtype
of the tagged type.
If the dispatching operation
overrides an inherited subprogram, it shall be subtype conformant with
the inherited subprogram.
The
convention of an inherited or
overriding dispatching operation
is the convention of the corresponding primitive operation of the parent
or progenitor type.
The default convention of a dispatching
operation that overrides an inherited primitive operation is the convention
of the inherited operation; if the operation overrides multiple inherited
operations, then they shall all have the same convention. An
explicitly declared A dispatching
operation shall not be of convention Intrinsic.
If a dispatching operation overrides the predefined equals operator,
then it shall be of convention Ada [(either explicitly or by default
— see 6.3.1)].
10.a
Reason: These rules ensure that constraint
checks can be performed by the caller in a dispatching call, and parameter
passing conventions match up properly. A special rule on aggregates prevents
values of a tagged type from being created that are outside of its first
subtype.
11/2
11.a/2
Reason: {
AI95-00416-01}
This rule The first
part ensures that the
default_expression
always produces the "correct" tag when called with or without
dispatching, or when inherited by a descendant. If it were statically
tagged, the default would be useless for a dispatching call; if it were
dynamically tagged, the default would be useless for a nondispatching
call.
11.b/2
{
AI95-00416-01}
The second part is consistent with the first part,
since designated objects are never tag-indeterminate.
11.1/2
{
AI95-00404-01}
If a dispatching operation is defined by a subprogram_renaming_declaration
or the instantiation of a generic subprogram, any access parameter of
the renamed subprogram or the generic subprogram that corresponds to
a controlling access parameter of the dispatching operation, shall have
a subtype that excludes null.
12
A given subprogram shall not be a dispatching operation
of two or more distinct tagged types.
12.a
Reason: This restriction minimizes confusion
since multiple dispatching is not provided. The normal solution is to
replace all but one of the tagged types with their class-wide types.
12.a.1/1
Ramification: {
8652/0098}
{
AI95-00183-01}
This restriction applies even if the partial view
(see 7.3) of one or both of the types is untagged.
This follows from the definition of dispatching operation: the operation
is a dispatching operation anywhere the full views of the (tagged) types
are visible.
13
The explicit declaration of a primitive subprogram
of a tagged type shall occur before the type is frozen (see
13.14).
[For example, new dispatching operations cannot be added after objects
or values of the type exist, nor after deriving a record extension from
it, nor after a body.]
13.a/2
Reason: {
AI95-00344-01}
This rule is needed because (1) we don't want people dispatching to things
that haven't been declared yet, and (2) we want to allow
the
static part of tagged type descriptors to be static (allocated
statically, and initialized to link-time-known symbols). Suppose T2 inherits
primitive P from T1, and then overrides P. Suppose P is called
before
the declaration of the overriding P. What should it dispatch to? If the
answer is the new P, we've violated the first principle above. If the
answer is the old P, we've violated the second principle. (A call to
the new one necessarily raises Program_Error, but that's beside the point.)
13.b
Note that a call upon a dispatching operation
of type T will freeze T.
13.c
We considered applying this rule to all derived
types, for uniformity. However, that would be upward incompatible, so
we rejected the idea. As in Ada 83, for an untagged type, the above call
upon P will call the old P (which is arguably confusing).
13.d/2
Implementation Note: {
AI95-00326-01}
Because of this rule, the type descriptor can be created (presumably
containing linker symbols pointing at the not-yet-compiled bodies) at
the first freezing point of the type. It also prevents, for a
(non-incomplete)
tagged type declared in a
package_specification,
overriding in the body or by a child subprogram.
13.e/2
13.f/3
To be honest: {
AI05-0222-1}
This rule only applies to "original"
declarations and not to the completion of a primitive subprogram, even
though a completion is technically an explicit declaration, and it may
declare a primitive subprogram.
Dynamic Semantics
14
For
the execution of a call on a dispatching operation of a type
T,
the
controlling tag value determines which subprogram body is
executed. The controlling tag value is defined as follows:
15
If one or more controlling
operands are statically tagged, then the controlling tag value is
statically
determined to be the tag of
T.
16
If one or more controlling operands are dynamically
tagged, then the controlling tag value is not statically determined,
but is rather determined by the tags of the controlling operands.
If
there is more than one dynamically tagged controlling operand, a check
is made that they all have the same tag.
If this
check fails, Constraint_Error is raised unless the call is a
function_call
whose
name
denotes the declaration of an equality operator (predefined or user defined)
that returns Boolean, in which case the result of the call is defined
to indicate inequality, and no
subprogram_body
is executed. This check is performed prior to evaluating any tag-indeterminate
controlling operands.
16.a
Reason: Tag mismatch is considered an
error (except for "=" and "/=") since the corresponding
primitive subprograms in each specific type expect all controlling operands
to be of the same type. For tag mismatch with an equality operator, rather
than raising an exception, "=" returns False and "/="
returns True. No equality operator is actually invoked, since there is
no common tag value to control the dispatch. Equality is a special case
to be consistent with the existing Ada 83 principle that equality comparisons,
even between objects with different constraints, never raise Constraint_Error.
17/2
{
AI95-00196-01}
If all of the controlling operands
(if any) are
tag-indeterminate, then:
18/2
{
AI95-00239-01}
{
AI95-00416-01}
If the call has a controlling result
or controlling
access result and is itself
, or designates,
a (possibly parenthesized or qualified) controlling operand of an enclosing
call on a dispatching operation of
a descendant
of type
T, then its controlling tag value is determined
by the controlling tag value of this enclosing call;
18.a/2
Discussion: {
AI95-00239-01}
For code that a user can write explicitly, the
only contexts that can control dispatching of a function with a controlling
result of type T are those that involve controlling operands of the same
type T: if the two types differ there is an illegality and the dynamic
semantics are irrelevant.
18.b/2
In the case of an inherited
subprogram however, if a default expression is a function call, it may
be of type T while the parameter is of a type derived from T. To cover
this case, we talk about "a descendant of T" above. This is
safe, because if the type of the parameter is descended from the type
of the function result, it is guaranteed to inherit or override the function,
and this ensures that there will be an appropriate body to dispatch to.
Note that abstract functions are not an issue here because the call to
the function is a dispatching call, so it is guaranteed to always land
on a concrete body.
18.1/2
{
AI95-00196-01}
{
AI95-00416-01}
If the call has a controlling result or controlling
access result and (possibly parenthesized, qualified, or dereferenced)
is the expression of an assignment_statement
whose target is of a class-wide type, then its controlling tag value
is determined by the target;
19
Otherwise, the
controlling tag value is statically determined to be the tag of type
T.
19.a
Ramification: This includes the cases
of a tag-indeterminate procedure call, and a tag-indeterminate
function_call
that is used to initialize a class-wide formal parameter or class-wide
object.
20/3
{
AI95-00345-01}
{
AI05-0126-1}
For the execution of a call on a dispatching
operation, the
action performed is determined by
the properties of the corresponding dispatching operation body
executed is the one for the corresponding primitive subprogram
of the specific type identified by the controlling tag value
:.
If the corresponding
operation is The
body for an explicitly declared for
this type, [even if the declaration occurs in a private part], then the
action comprises an invocation of the dispatching
operation is the corresponding explicit
body for the operation.
If the corresponding operation is implicitly declared for this type: 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.
20.1/3
{
AI05-0126-1}
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;
20.2/3
{
AI95-00345-01}
{
AI05-0126-1}
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;
20.3/3
{
AI05-0197-1}
if the corresponding operation is a predefined
operator then the action comprises an invocation of that operator;
20.4/3
{
AI95-00345-01}
{
AI05-0126-1}
{
AI05-0197-1}
{
AI05-0250-1}
{
AI05-0254-1}
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 except that
additional invariant checks (see 7.3.2) and
class-wide postcondition checks (see 6.1.1)
may apply. If there is more than one such corresponding operation, the
action is that for the operation that is not a null procedure, if any;
otherwise, the action is that of an arbitrary one of the operations.
20.a/3
This paragraph
was deleted.To be honest: {
AI05-0126-1}
In the unusual case in which a dispatching subprogram
is explicitly declared (overridden) by a body (with no preceding subprogram_declaration),
the body for that dispatching subprogram is that body; that is, the “corresponding
explicit body” in the above rule is the body itself.
20.a.1/3
Ramification: {
AI05-0126-1}
“Corresponding dispatching 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 last bullet
is used and the corresponding operation of the parent type is executed
(an explicit body that happens to have the same name and profile is not
called in that case).
20.a.2/3
{
AI05-0126-1}
We have to talk about progenitors in the last bullet
in case the corresponding operation is a null procedure inherited from
an interface. In that case, the parent type may not even have the operation
in question.
20.a.3/3
{
AI05-0197-1}
For the last bullet, if there are multiple corresponding
operations for the parent and progenitors, all but one of them have to
be a null procedure. (If the progenitors declared abstract routines,
there would have to be an explicit overriding of the operation, and then
the first bullet would apply.) We call the non-null routine if one exists.
20.a.4/3
{
AI05-0126-1}
Any explicit declaration for an inherited corresponding
operation has to be an overriding routine. These rules mean that a dispatching
call executes the overriding routine (if any) for the specific type.
20.b/3
Reason: {
AI05-0005-1}
The wording of the above
rules rule
is intended to ensure that the same body is executed for a given tag,
whether that tag is determined statically or dynamically. For a type
declared in a package, it doesn't matter whether a given subprogram is
overridden in the visible part or the private part, and it doesn't matter
whether the call is inside or outside the package. For example:
20.c
package P1 is
type T1 is tagged null record;
procedure Op_A(Arg : in T1);
procedure Op_B(Arg : in T1);
end P1;
20.d
with P1; use P1;
package P2 is
type T2 is new T1 with null record;
procedure Op_A(Param : in T2);
private
procedure Op_B(Param : in T2);
end P2;
20.e/1
with P1; with P2;
procedure Main is
X : P2. T2;
Y : P1. T1'Class := X;
begin
P2.Op_A(Param => X); -- Nondispatching call to a dispatching operation.
P1.Op_A(Arg => Y); -- Dispatching call.
P2.Op_B(Arg => X); -- Nondispatching call to a dispatching operation.
P1.Op_B(Arg => Y); -- Dispatching call.
end Main;
20.f
The two calls to Op_A both execute the body
of Op_A that has to occur in the body of package P2. Similarly, the two
calls to Op_B both execute the body of Op_B that has to occur in the
body of package P2, even though Op_B is overridden in the private part
of P2. Note, however, that the formal parameter names are different for
P2.Op_A versus P2.Op_B. The overriding declaration for P2.Op_B is not
visible in Main, so the name in the call actually denotes the implicit
declaration of Op_B inherited from T1.
20.g
If a call occurs in the program text before
an overriding, which can happen only if the call is part of a default
expression, the overriding will still take effect for that call.
20.h
Implementation Note: Even when a tag
is not statically determined, a compiler might still be able to
figure it out and thereby avoid the overhead of run-time dispatching.
21
76 The body to be executed for a call on
a dispatching operation is determined by the tag; it does not matter
whether that tag is determined statically or dynamically, and it does
not matter whether the subprogram's declaration is visible at the place
of the call.
22/2
77 {
AI95-00260-02}
This subclause covers calls on
dispatching primitive
subprograms of a tagged type. Rules for tagged type membership tests
are described in
4.5.2. Controlling tag determination
for an
assignment_statement
is described in
5.2.
23
78 A dispatching call can dispatch to a
body whose declaration is not visible at the place of the call.
24
79 A call through an access-to-subprogram
value is never a dispatching call, even if the access value designates
a dispatching operation. Similarly a call whose
prefix
denotes a
subprogram_renaming_declaration
cannot be a dispatching call unless the renaming itself is the declaration
of a primitive subprogram.
Extensions to Ada 83
24.a
The concept of dispatching
operations is new.
Incompatibilities With Ada 95
24.b/2
{
AI95-00404-01}
If a dispatching operation
is defined by a subprogram_renaming_declaration,
and it has a controlling access parameter, Ada 2005 requires the subtype
of the parameter to exclude null. The same applies to instantiations.
This is required so that all calls to the subprogram operate the same
way (controlling access parameters have to exclude null so that dispatching
calls will work). Since Ada 95 didn't have the notion of access subtypes
that exclude null, and all access parameters excluded null, it had no
such rules. These rules will require the addition of an explicit not
null on nondispatching operations that are later renamed to be dispatching,
or on a generic that is used to define a dispatching operation.
Extensions to Ada 95
24.c/2
{
AI95-00416-01}
Functions that have an access
result type can be dispatching in the same way as a function that returns
a tagged object directly.
Wording Changes from Ada 95
24.d/2
{
8652/0010}
{
AI95-00127-01}
Corrigendum: Allocators and access attributes
of objects of class-wide types can be used as the controlling parameter
in a dispatching calls. This was an oversight in the definition of Ada
95. (See 3.10.2 and 4.8).
24.e/2
{
8652/0011}
{
AI95-00117-01}
{
AI95-00430-01}
Corrigendum: Corrected the conventions of
dispatching operations. This is extended in Ada 2005 to cover operations
inherited from progenitors, and to ensure that the conventions of all
inherited operations are the same.
24.f/2
{
AI95-00196-01}
Clarified the wording to ensure that functions
with no controlling operands are tag-indeterminate, and to describe that
the controlling tag can come from the target of an assignment_statement.
24.g/2
{
AI95-00239-01}
Fixed the wording to cover default expressions
inherited by derived subprograms. A literal reading of the old wording
would have implied that operations would be called with objects of the
wrong type.
24.h/2
24.i/2
{
AI95-00345-01}
Dispatching calls include operations implemented
by entries and protected operations, so we have to update the wording
to reflect that.
24.j/2
{
AI95-00335-01}
A stream attribute of a tagged type is usually
a dispatching operation, even though it is not a primitive operation.
If they weren't dispatching, T'Class'Input and T'Class'Output wouldn't
work.
Wording Changes from Ada 2005
24.k/3
{
AI05-0076-1}
Correction: Defined “function with
a controlling result”, as it is used in 3.9.3.
24.l/3
{
AI05-0126-1}
{
AI05-0197-1}
Correction: Corrected holes in the definition
of dynamic dispatching: the behavior for operations that are never declared
and/or inherited from a progenitor were not specified.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe