Function dispatch based on the types of multiple arguments, whether static or dynamic, raises two challenges: We must specify which function body is considered the correct choice for any given call, and we must provide a way for the program to branch to this code efficiently. In this section, we consider the question of how to adapt the existing dispatch rules of C++ for accessory functions, leaving the the question of how to branch to this function for Section 5.
The traditional choice of static vs. dynamic dispatch, and the new decision of which argument is to be used for dynamic dispatch, must be made at compile-time. These decisions are thus based on the types of the references used in the call (rather than the types of the objects they refer to), and the set of functions that are in scope at the point of the call. Once the compiler has selected dynamic dispatch on a particular object, the true ``run-time'' type of the object will be used in the actual call.
We ensure that we can statically determine which argument is to be used in dynamic dispatch by requiring that, in any one scope, no two functions with the same name and arity (number of arguments) are dynamically dispatched on different parameters. Essentially, we consider dispatch mechanism to be an attribute of the message (function name) rather than method (function body). Conflicts that might arise when two independent projects happen to use the same function names must be resolved via namespaces.
This restriction allows us to use the traditional C++ approach to dispatch: We select, from the set of functions that are in scope, the one with parameters types that best match the compile-time type information about the arguments used in the call. If there is no unique best match, we generate an error message. We then generate either a dynamic dispatch (based on the appropriate parameter type, if one parameter is virtual) or static dispatch (if no parameter is virtual).
Thus, if a group of functions of a given name and arity are dispatched on argument , we produce a branch to the function that would have been called if all functions with this name and arity had been written as (possibly virtual) member functions of the classes of their arguments. In other words, we generate a branch to the function that would have been called if we had violated the encapsulation of the classes.
As we will see in Section 5, our implementation allows us to produce warnings for certain surprising behavior that is a consequence of this combination of static and dynamic information.