From: stt@spock.camb.inmet.com (Tucker Taft)
Subject: Re: Ada 9x Dispatching Question
Keywords: Ada Dispatching Polymorphism
Organization: Intermetrics Inc, Cambridge MA
Date: Fri, 21 Aug 1992 14:50:44 GMT

In article <9223120.6784@mulga.cs.mu.OZ.AU> 
fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON) writes:

>bwhite@cobra.camb.inmet.com (Bill White) writes:
>
>>The MRT has discussed this at length in the past.  Tucker believes that
>>it is important to have a syntactic marker to tell when a call is
>>dispatching.  An alternative rule would be the C++ rule, where all
>>dispatching operations dispatch always.  (Ada9X dispatching operations
>>are roughly equivalent to C++ virtual operations.)  This means that the 
>>compiler could not replace a dispatching call with a non-dispatching
>>call even if the compiler knows where the routine is going to go
>>anyway.  This is considered expensive.
>
>I don't understand why the compiler can't replace a dispatching call
>with a non-dispatching one if it really does know the exact type of
>the operand.  This is quite possible in C++. Indeed, in C++ you can
>declare a function to be both inline and virtual, so that if the
>compiler manages to avoid the dispatch, it can then insert the code
>directly and avoid any function call altogether.

The compiler can certainly do that if it knows the "exact type"
at compile time.  However, for a by-reference parameter in
C++, one never knows the "exact type" at compile-time.
On the other hand, with an object or a by-value parameter,
a C++ compiler always knows at compile-time the "exact type."
And as you illustrate, a decent optimizer can track the
value of a reference presuming it is initialized locally.

However, we are talking here exclusively about parameters.
Unless you inline the function, the C++ compiler has no idea
what is the exact type or a by-reference parameter.  

In Ada 9X, we distinguish explicitly between "class-wide" types
and "specific" types.  If a formal parameter has a specific type,
then all direct uses of that parameter later treat it as that specific type.
If a formal parameter has a class-wide type, or if one converts
an expression of a specific type to a class-wide type, one
then has a "dynamically tagged" expression, and run-time dispatch
is used to locate the correct body.

Another way to think of it is that the parameter is "viewed" as being
of a specific type, but upon conversion to a class-wide type,
it is viewed as dynamically tagged.  A similar distinction can
be made in C++.  Explicit qualification like p->c1::func can
be used to prevent dispatching when p is a reference,
whereas p->func always dispatches.  

In Ada 9X you have three choices, given a formal parameter 
p of some specific type c1.  You can call the "c1" version of
func, by simply saying "func(p)."  You can call some other specific 
ancestor's type's (like c0) version of func by saying "func(c0(p))."
Or you can "redispatch" by saying "func(c1'class(p))" which
will look at the tag of p at runtime and decide which func to call.

The Ada 9X approach is consistent with the way derived types
work in Ada 83, with the addition of the "class-wide" alternative.

If the parameter p is itself of a class-wide type, then func(p) will
always dispatch, which can be "turned off" by explicitly
converting p to some specific type, such as func(c2(p)) which
will verify that p is in the class rooted at c2, and then call
c2's func.

>Fergus Henderson             fjh@munta.cs.mu.OZ.AU      

S. Tucker Taft   stt@inmet.com
Intermetrics, Inc.
Cambridge, MA  02138