Ada Resource Association
News and resources for the Ada programming language
Annotated Ada Reference ManualLegal Information
Contents   Index   References   Search   Previous   Next 

3.9.2 Dispatching Operations of Tagged Types

{AI95-00260-02} {AI95-00335-01} {dispatching operation [distributed]} {dispatching call (on a dispatching operation)} {nondispatching call (on a dispatching operation)} {statically determined tag} {dynamically determined tag} {polymorphism} {run-time polymorphism} {controlling tag (for a call on a dispatching operation)} 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.] {object-oriented programming (OOP): See dispatching operations of tagged types} {OOP (object-oriented programming): See dispatching operations of tagged types} {message: See dispatching call} {method: See dispatching subprogram} {virtual function: See dispatching subprogram}
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

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

{AI95-00260-02} {AI95-00416-01} {call on a dispatching operation} {dispatching operation} 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. {controlling operand} 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; {controlling formal parameter} 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. {controlling result} If the call is to a (primitive) function with result type T, 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 access result type designating T, then the call has a controlling access result, and the context can similarly control dispatching. 
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. 
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: 
Discussion: It is illegal to have both statically tagged and dynamically tagged controlling operands in the same call -- see below. 
{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. 
Ramification: A type_conversion is never tag indeterminate, even if its operand is. A designated object is never tag indeterminate.
{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

A call on a dispatching operation shall not have both dynamically tagged and statically tagged controlling operands. 
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). 
{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. 
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. 
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). 
 {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. {statically matching (required) [partial]} If the dispatching operation overrides an inherited subprogram, it shall be subtype conformant with the inherited subprogram. {subtype conformance (required)} 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)]. 
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. 
 {AI95-00416-01} The default_expression for a controlling formal parameter of a dispatching operation shall be tag indeterminate. A controlling formal parameter that is an access parameter shall not have a default_expression.
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.
{AI95-00416-01} The second part is consistent with the first part, since designated objects are never tag-indeterminate. 
   {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.
A given subprogram shall not be a dispatching operation of two or more distinct tagged types. 
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.
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. 
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.]
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.)
Note that a call upon a dispatching operation of type T will freeze T.
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). 
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. 
Ramification: {AI95-00251-01} A consequence is that for a tagged type declaration derived_type_declaration in a declarative_part, only the last (overriding) first primitive subprogram can be declared by a subprogram_body. (Other overridings must be provided by subprogram_declarations.)

Dynamic Semantics

{execution (call on a dispatching operation) [partial]} {controlling tag value} 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: 
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.
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.
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. 
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. 
 {AI95-00345-01} 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.
To be honest: 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. 
Reason: The wording of the above 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: 
package P1 is
    type T1 is tagged null record;
    procedure Op_A(Arg : in T1);
    procedure Op_B(Arg : in T1);
end P1;
with P1; use P1;
package P2 is
    type T2 is new T1 with null record;
    procedure Op_A(Param : in T2);
    procedure Op_B(Param : in T2);
end P2;
with P1; with P2;
procedure Main is
    X : P2. T2;
    Y : P1. T1'Class := X;
    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;
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.
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.
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.
73  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.
74  {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.
75  A dispatching call can dispatch to a body whose declaration is not visible at the place of the call.
76  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

{extensions to Ada 83} The concept of dispatching operations is new. 

Incompatibilities With Ada 95

{AI95-00404-01} {incompatibilities with Ada 95} 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

{AI95-00416-01} {extensions to Ada 95} 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

{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).
{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.
{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.
{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.
{AI95-00260-02} An abstract formal subprogram is a dispatching operation, even though it is not a primitive operation. See 12.6, “Formal Subprograms”.
{AI95-00345-01} Dispatching calls include operations implemented by entries and protected operations, so we have to update the wording to reflect that.
{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. 

Contents   Index   References   Search   Previous   Next 
Ada-Europe Sponsored by Ada-Europe