The development of generic mechanisms for the composition of meta-objects is still in its initial stages. OpenC++ [2] does not provide direct support for composition. MOOSTRAP [16] and MetaXa [9] (formerly known as MetaJava) support sequential composition of similar meta-objects. We say that meta-objects are similar if they implement the same interface.
Apertos [23] and CodA [14] assign aspects of base-level execution, such as sending, receiving and scheduling operations, to specialized, dissimilar meta-objects. A pre-determined set of aspects can be extended, through intrusive modification of the implementation of the meta-objects responsible for them. We consider this a primitive mechanism of composition, that fails in the general case, because the modifications are very likely to clash.
Several run-time MOPs have been designed so that, when a meta-object is requested to handle a reified operation (for example, a method invocation), it is obliged, by the design of the MOP, to return a valid result for the operation (typically the value returned by the method), as shown in Figure 1. The meta-level computation that yields the result can include or not the delivery of the operation to the base-level object.
When a Client requests an operation Op from a Server object, the operation is intercepted, reified (represented as an object) and presented to a Meta-Object. It may choose to deliver a different operation Op to the Server, obtaining the result R, that is also reified. Having delivered an operation or not, it must reply with a result R, that is unreified and returned to the Client.
This design implies that the only way to combine the behavior of meta-objects is by arranging for one meta-object, say MO1, to forward operation handling requests to another, say MO2, delegating to MO2 the responsibility for computing the result of the operation. Only after MO2 returns a result will MO1 be able to observe and/or to modify it.
Given the basic interception mechanism of Figure 1, meta-objects can only be composed with a Chain of Responsibility [5, chapter 5], a sequential delegation pattern.
Given such a protocol, meta-objects are likely to be organized in a Chain of Responsibility [5, chapter 5], so that each meta-object delegates operation handling requests to its successor, as depicted in Figure 2. The last element of the chain is either the base-level object [9] or a special meta-object that delivers operations to it [16]. We argue that this design presents some serious drawbacks:
Even AspectJ [11,12], an aspect-oriented programming [8] extension of Java, lacks the possibility of introducing such an adaptor to manage conflicting weaves of aspects so that they can coexist.