interface fulfillment using fields - a java language proposition - part 1 of 2

Friday, July 11, 2008

I'm proposing a new keyword in Java class definitions, via. It essentially provides a methodology to simply and maintainably perform automatic delegation of interface methods to member fields.

This provides:

  1. Encouragement for coding to interfaces over inheritance
  2. Object wrappers that do not need to subclass the wrapped object, yet still expose the wrapped object's methods directly (exposed as 'is-a' rather than having to manually delegate because of 'has-a')
  3. Can 'swap out' the effective superclass (like subclassing an interface, not a class)
  4. Advantages of multiple-inheritance
  5. and potentially: Interface fulfillment by combining two or more classes

Here's an example of what it might look like:
public class Car implements Driveable via this.vehicle {

Which says, I have a class, Car, which implements the interface Driveable. Car as an object definition may not fulfill all (or any) of the requirements for Driveable, but via its field 'vehicle', the contract is met.

And the code for Car might look like:
{
private Driveable vehicle;

public Car() {
this.vehicle = new DefaultCar();
}

public void doCarStuff() {...}
}

So we can see here that the requirements for the Driveable interface can be met by anything that can be assigned to the 'vehicle' field. In this case a new instance of DefaultCar. As with any class, Car can also define any other additional members as well (e.g. doCarStuff()), enriching the functionality of DefaultCar (as subclassing would). It is essentially a methodology for automatic and type-safe delegation. But we gain nothing in this example, we may as well just extend the DefaultCar class. To get the advantages we need to make some changes...
{
private Driveable vehicle;

public Car() {
this.vehicle = new DefaultCar();
}

public Car(Driveable driveableClass) {
this.vehicle = driveableClass;
}

public void doCarStuff() {...}
}

In this way Car's new functionality can enrich any implementation of Driveable. At runtime we can instantiate different instances of Car, each of which could have a unique implementation of Driveable. Swapping in different driveableClass objects could be useful for endowing different classes with the same extra features. Also for testing, Mocks or test doubles can be passed to the constructor so that only the added features are under test.

In this example Car could also override any of the Driveable methods, as with traditional class inheritance. More on overriding in Part two.


Under the hood


So how is it working? I imagine the compiler would generate bytecode representing the code below. You could write this yourself, but it would be messy and require duplication.
Firstly an example of the Driveable interface:
public interface Driveable {

void setSpeed(int speed);

boolean isMoving();
}


Then the effective resulting code (ie the developer wouldn't see it written like this):
public class Car implements Driveable via this.vehicle {
private Driveable vehicle;

public Car() {
this.vehicle = new DefaultCar();
}

public Car(Driveable driveableClass) {
this.vehicle = driveableClass;
}

public void doCarStuff() {...}

//delegation
public void setSpeed(int speed) {
this.vehicle.setSpeed(speed);
}

//delegation
public boolean isMoving() {
return this.vehicle.isMoving();
}



Multiple inheritance


While some debate the merits of multiple inheritance, this is often imitated by subclassing and using an inner class that has subclassed also. The via keyword, however, allows us to do this directly.
public class Car implements Driveable via this.vehicle,
Runnable via this.runner {


The construct would not break existing Java inheritance relationships, as a class can both extend a class as well as use interface fulfillment via fields, and a class that uses that construct can itself be subclassed.


More to follow...


More benefits and some finer points will follow in Part 2, including benefit [5] hinted at earlier...

posted 8:17 am  

0 comments:

Post a Comment