6.5. Method forwarding

6.5.1. Forwarding mechanism

One of the things that make dynamic binding an interesting approach to method dispatching (i.e., the decision which code to invoke to handle a given message) is the ability to forward a method invocation. A message is forwarded when the receiver object does not provide an implementation of the method denoted by the message. In this highlight, the forward mechanism of TOM will be explained.

Every method has two implicit arguments: self and cmd. The object self is the `current object'; it is the receiver of the message that lead to the method invocation. The argument cmd is the selector of that message.

When an object does not implement a method, the self and cmd arguments are used to decide how to respond to the message.

6.5.2. Speed

Everything comes with a price, especially flexibility.

I've done some speed tests (on a PII/266, Debian 1.3.x, gcc 2.7.2.1) with various ways to invoke a method, with various number of arguments, with the results shown in the table below.

Table 6-3. Speed of method invocation

how#invtime
  0123456
x10^812.5812.9312.5812.5313.6914.0013.91
p10^711.1511.7712.7413.8014.8815.6317.32
d10^711.6212.7513.7515.1115.8116.6118.52
i10^615.9617.4417.8018.1418.5118.8719.22

In Table 6-3, using the morerows attribute causes jade/html to produce incorrect tables, and jade/tex to die.

In Table 6-3, `how' describes how the method is invoked, `#inv' is the number of invocations performed in the given time, and `time' is the CPU time needed to run the test for the indicated number of arguments.

Note that for every forwardInvocation dispatch, an Invocation object and an InvocationResultis created, and approximately half the time taken by the test runs is spent in garbage collecting those objects. Also note that the mechanism underlying perform with and forwardDelegate, does not create InvocationResult objects for void methods, as was the case in the test.

The numbers come down to the following: in the time that you can do 1 forwardInvocation, you can do 10 forwardDelegate calls or invocations through perform with, and 100 direct method invocations.

I don't know if these numbers are good or bad; I don't have numbers to compare them with (maybe testing Objective-C Rhapsody on a PII/266?). It does show, that using forwardDelegate is much faster than having an Invocation object be created and forwarding that. Which is what it was supposed to do. (And it can probably be made much faster when using __builtin_apply_args in trt_forward, instead of going through perform_args.)