Dispatch refers to the mechanism for selecting the code to be executed to respond to a message. This mechanism is designed to make method invocation polymorphic. It also affects how inheritance works.
When methods are compiled or interpreted, they are treated as subprograms whose first parameter is the receiving object. When a message is compiled or interpreted the receiver is supplied as the first argument. For example, for the message
anObject.aMethod();
a compiler first generates code that locates the entry address of the machine language subprogram for the method named "aMethod". The compiler then generates code that invokes that subprogram with a reference to anObject passed as the first argument. An interpreter handles the message similarly except that it executes code rather than generating code to be executed later.
Compilers also must be able to locate instance variables. For example, consider the expression
anObject.aVariable;
The most important issues are
The answers to these questions depends on the language type.
There are two kinds of mechanisms used for locating object members.
The member is located by specifying its position, either by an index into an array or by a displacement from the beginning of a struct. This is a fast location mechanism, but the compiler must know how the members are ordered in the array or struct.
The members are stored in a table that is keyed by member names. The code generated by a compiler searches the table.
Dispatch for classless OOLs is usually as suggested by the diagram below.
Classless OOLs are inherently untyped. When a compiler encounters a message it knows the variable that it is sent to but it knows nothing about the object referenced by that variable. The compiler must generate code for the message that works for any object that has an appropriately named method. Consequently classless OOLs must implement dispatch with lookup tables.
The implementation of dispatch behaves as if all members of anObject are copied from itsPrototype when anObject is created. However, the actual implementation may be different due to space-time tradeoffs. One possibility is that there are no copies made when anObject is created - member fetches are forwarded to itsPrototype, as in the Chain of Responsibility design pattern. Another possibility is that a member is copied into anObject's member table after the first forwarded fetch from itsPrototype.
In any implementation, when a new value is assigned to a member of anObject the new value is written to anObject's member table. This is necessary to ensure that the members of anObject are distinct from those of itsPrototype.
For class-based languages, all instances of a class have the same methods. This makes it possible to store method entry addresses in class structures rather than object structures. On the other hand, each object must have its own instance variables, so they must be stored in object structures. Thus dispatch for compiled class-based object-oriented languages is usually as suggested by the diagram below.
Due to differences in the amount of information available to a compiler, typed and untyped languages use different runtime structures and lookup mechanisms.
Class-based OOLs with untyped variables are like classless OOLs in that when a compiler encounters a message it knows the variable that it is sent to but it knows nothing about the object referenced by that variable. The compiler must generate code for the message that works for any object that has an appropriately named method. Consequently untyped class-based OOLs must also implement dispatch with lookup tables. Code generated by the compiler usually just uses the member name as a lookup key to find a variable or the entry address of method.
Unlike classless languages, there is an impiortant difference between instance variable lookup and instance method lookup.
There is one common case where a compiler has additional information that allows the use of positional lookup mechanisms: code in an instance method for an object accesses the object's own instance variables or methods. For example, the Smalltalk language made all instance variables private and all instance methods public. With private instance variables, the only access to an object's instance variables is by that object's methods. Thus Smalltalk copilers often implemented positional location for variables.
For typed class-based OOLs some of the dispatch can be static. Suppose that the variable that references anObject is declared with type ParentClass, where ParentClass is the superclass of ItsClass. One simple implementation for accessing methods is to set up an array in the class structure that contains the entry addresses of their machine language subprograms. The initial part of the array for ItsClass has the same addresses as the array for ParentClass except when a method has been overridden. The rest of the array for ItsClass contains new methods defined in the code for ItsClass.
With the type information the compiler can look up the index of a method in ParentClass's method table. For the message
anObject.method();
the compiler can generate code that fetches the entry address of the machine language subprogram at the same index in ItsClass, using anObject's reference to its class to access ItsClass. Then the compiler generates code that invokes the subprogram with a reference to anObject passed as the first argument.
Note: This mechanism only works for single inheritance. Multiple inheritance requires a more complex lookup mechanism.
Note: A table lookup is always required to deal with member names. In a typed class-based OOL, the compiler has enough information that it can do a lookup at compile time to get positional information that is used at run time.
In classless OOLs, objects inherit from objects. Both variables and methods are found in object structures. A table-based lookup mechanism is used at run time for both instance variables and instance methods.
In class-based OOLs, classes inherit from classes. Methods are usually located in class structures while variables are located in object structures.
Untyped class-based OOLs usually use a table-based lookup mechanism at run time for both instance variable and instance methods, but may implement a positional lookup mechanism for private access to variables.
Typed class-based OOLs can use a positional lookup mechanism at run time for both instance variables and instance methods.
The table-based dispatch mechanism is somewhat slower than the positional mechanism. However, it offers the possibility of adding or replacing members of an object dynamically. This can trivialize achieving the intent of some design patterns such as the State design pattern. It also makes possible some design techniques that are difficult, if not impossible in typed class-based OOLs. Objects can be "educated" to offer enhanced behavior as program execution proceeds.