ADDING DELEGATION TO JAVA

v1.6 Fri Mar 27 18:26:44 MET 1998

Adding delegation support for Java is a recurrent discussion on the technical mailing-lists. While it is hard to predict if it will eventually make it into the language, many proposals have already been advanced. Here is my contribution to this debate.
 

CONSTRAINTS

What follows has been greatly inspired by the process used by the ISO C++ Committee to decide the inclusion (or not) of a new feature in the language. In a few words, an extension should
  I suggest you refer to #[1] for more information on this subject.
 

RATIONALE

Sometimes, I find myself simulating multiple inheritance of implementation by mixing simple inheritance and delegation. Consider the classic example of displaying a grapher. I have an "abstract" representation of a node (class Node) and I want to display it. For this, I have a class Graphic. My class will naturally be called NodeGraphic and will, at least in C++, inherit both from Node and from Graphic. And it does make sense : a NodeGraphic is both a Node and a Graphic.

In Java, it's a bit trickier :

As you can see, you end up writing a lot of dumb code, which is error prone (illustrated below) and on top of this, you can't pass a NodeGraphic to a function expecting a Graphic (you will have to resort to interfaces to achieve this, but it won't help if the author of the package Graphic belongs to didn't envision this).

Worse : if one day Graphic is improved, say with a function setBackground(), a simple recompilation won't be enough : you will have to add by hand the setBackground() function to your class. And this goes for all new functions, and deprecated ones. This is beginning to rhyme with nightmare, but it's part of the compromise Java makes with simplicity.
 

MY PROPOSAL

I would like to have the following syntax : Please note that here, the "I" prefix means "interface" (not to be confused with CORBA's usual notation where you suffix  the implementation with _i).

With this syntax, you are free to use whatever implementation of the interface IGraphic suits you best (in the constructor of NodeGraphic for example). Your class will never know about any concrete implementation of the interface it delegates to.

Of course, you can delegate to more than one attribute :

ALTERNATIVE SYNTAX

Some people are concerned about the visibility of the delegation. They'd like the fact that the implementation of an interface is actually delegated to be invisible from the declaration. Therefore, the following alternative syntax might be used :

RESOLVING AMBIGUITIES

Static ambiguities

This syntax can cause ambiguities. For example, suppose that both these interfaces have a public method clash(), the following code will create an error : You are then expected to disambiguate this code yourself : My experience (C++) tends to prove that such ambiguities are either rare, or systematic, and in this case, you should arrange for the class that causes numerous conflicts to use some different naming scheme.

If ever the class NodeGraphic has its own clash() function, it is the one chosen. Delegated functions come second in the resolution of overridden methods. A typical implementation in such a case would be in class NodeGraphic :

Dynamic ambiguities

There is a particular case that cannot be caught at compile time and will be ambiguous at runtime. Since delegated members can be modified dynamically, one member could first be assigned to a "simple" interface, and later on, replaced with an "enriched" interface (inheriting from the first interface). If this enriched interface contains a function that clashes with another implemented interface, the call becomes impossible to determine :
  To prevent this, I suggest that only those interfaces mentioned in the declarative part of the class should be considered when trying to perform a call. Therefore, in the error case, Derived.g() won't be considered because IDerived is not mentioned in the implements clause : it's IBase. Since IBase does not contain a g() (an error would have been triggered), there is no ambiguity.

Another way to solve this problem would be to throw a runtime exception, much like what happens when you try to store an object of a wrong type in an array (why this is not caught at runtime, I don't know). Instead of an ArrayStoreException, you would have some DelegationAmbiguityException.
 

VISIBILITY OF THE DELEGATED ATTRIBUTE

The attribute used as delegate can have any visibility (public, protected or private, although public should be discouraged by standard OO practice). All the functions of the implemented interface will automatically be accessible as if they had been declared public.
 

PROS AND CONS

With this declaration, you are now free to assign _graphic to whatever implementation of IGraphic suits you best.

This solution has very attractive properties :

The only drawback I see is that it forces a new interface to be introduced for a class to be delegated this way, but this might be seen as a good point (personally, I think the more interfaces, the better).  One might also use interfaces to define subsets of classes that are delegated in their class.

--
Cedric Beust
 
 
 

THANKS

...to Olivier Dedieu, Lionel Mallet, Thierry Kormann and Jean-Michel Leon for their constructive criticism.
 

REFERENCES

[1] The design and evolution of C++, Bjarne Stroustrup
ISBN 0-201-54330-3, Addison Wesley