next up previous
Next: 2.3.3.3 Section summary. Up: 2.3.3 Language support Previous: 2.3.3.1 similar

  
2.3.3.2 Built-in Delegation.

We now discuss an alternative proposal to simulating delegation in Java, as incorporated in Lava. Lava extends Java with constructs for type-safe automatic forwarding. In particular, Lava supports two variants of forwarding : consultation and delegation. The following description of these variants has been adapted from [21].

An object, called the child, may have modifiable references to other objects, called its parents. Method calls for which the receiver has no matching method are automatically forwarded to its parents. When a suitable method is found in a parent (the method holder), it is executed after binding its implicit this parameter, which refers to the object on whose behalf the method is executed. Automatic forwarding with binding of this to the original method call receiver is called delegation, while automatic forwarding with binding of this to the method holder is called consultation. Delegation is object-based inheritance whereas consultation is just an automatic form of method calling.

Lava uses the keywords delegatee and consultee to mark instance fields of a child class that hold references to parent objects. These keywords specify whether to interpret forwarded method calls via delegation or via consultation respectively. The two approaches differ when a parent method has been redefined in a child. The delegatee will invoke the redefined child method, while the consultee will invoke the original parent method. Alternatively, one can say that delegation supports overriding whereas consultation blocks it, as illustrated below.


6#6
The expected outcome is "AC". If we used consultation (delegation) for both parent fields the outcome would be "AB" ("CC").

Note also that an object of class C can be treated as an object of both class A and class B. Delegation and consultation both have the effect of extending the interface of the child class by the public and protected methods of the declared parent types. It is instructive to compare the above code with the initial multiple inheritance example and the simulation of delegation.

A class can have multiple forwardees - delegatees and consultants - that define methods under the same name. Such ambiguities have to be resolved, by explicit overriding. This construct is a simplification of Eiffel's redefine-rename-undefine mechanism, as illustrated below. The notation localName(args) overrides field<-parentName means that the respective method overrides the method with the signature parentName(args) in objects referenced by field. If the parentName is the same as localName it may be omitted, like in the following definition of clone():


7#7
In contrast with ordinary class-based languages, there are situations where conflicts can arise only at run-time. This can happen because, with delegation, the parent object may be any instance of the declared parent type or of one of its subtypes. In the latter case, it may contain additional methods, which may have the same signature as methods in the child object.

Such conflicts, that cannot be detected statically, are resolved in Lava by a ``semantic compatibility'' criterion that a method in a child may only override a method of a parent object if both override the same method in a common declared supertype of the child's class and the parent's class. Consider the following examples from [21].


8#8

Let c = new Child(). Then c.b() delegates b() to p, which calls bang() on c (recall that delegation has the effect of binding this to the object that initially received the forwarded message).

In Lava, for the left example, bang() in class Child will be invoked, thus overriding Parent's bang() -- this is sensible to do because both methods are derived as specializations of the one in DeclParent - hence it can safely be assumed that they have a compatible semantics.

For the right example, the bang() method of class Child will not be selected because there is no evidence that it has the semantics expected in the calling context. Therefore the bang() call will be forwarded to the parent object p - just like any other call that finds no applicable method in c -- and the bang() method of p will be selected. The net effect is that accidental overriding is barred, preventing cumbersome and hard to locate errors.

Furthermore, there are cases where conflicts can be detected statically but can be resolved only at run-time. These cases are related to repeated delegation (analogous to repeated inheritance) and the semantic problem pointed out for Eiffel's select statement in Section [*]. The detailed analysis of the additional complications of this problem in the presence of aggregation and delegation, and the development of a solution is contained in [22]. A deeper discussion of explicit overriding can also be found there.


next up previous
Next: 2.3.3.3 Section summary. Up: 2.3.3 Language support Previous: 2.3.3.1 similar
T. K. Prasad