Tuesday, July 3, 2007

How Java Should Have Handled Multiple Inheritence

C++ permits multiple inheritance. That is, a class can subclass more than one parent class. This can cause ambiguities when more than one parent class exposes identically named and prototyped methods or properties. Fortunately, C++ provides ways to disambiguate this situation.
Java, on the other hand, does not permit multiple inheritance. Instead, it has interfaces, which are guarantees that a given class implements a predefined set of methods and properties. While Java does not permit multiple inheritance, it does permit a class to implement multiple interfaces, and interface names can be used in variable and parameter declarations in much the same way as class names, though an interface cannot be directly instantiated like a class.

As Java postdates C++, it is an attempt to clean up the messiness that comes with multiple inheritance. However, I think it comes up short, as it requires class designers to decide in advance whether to define a class with and interface or not. While nothing prevents designers from defining all classes with interfaces, there is nothing that requires it, and even if a prudent designer did, there is nothing to force class users to use those interfaces instead of the classes directly. Java should:
  1. Require that the entire interface that a class exposes be defined by the set of interfaces it declares that it implements. If a class implements more than one interface with the same method name and prototype, then the class can designate different functions to correspond to the different interfaces. This will properly handle interfaces that attach different semantic meanings to the same method name.
  2. Require that variable and parameter types only be declared as the interface required. A class is not a valid type. A class, however, is the only way to instantiate an object that implements a particular type.
  3. Permit interfaces to require other interfaces. This does not include the required interface’s signature in the requiring interface, but it does mean that implementing the requiring interface implicitly implements the required interface. For example, if I1 is an interface with the method f1. An interface I2 may require I1. Now, any class that implements I2 must provide a method for I1’s method f1. This f1 method is specifically not part of I2. In fact, if I2 had a method f1, then the class definition would also need to provide a method for I2’s f1 (which may or may not be the same as I1’s). Note that this avoids any messiness with multiple inheritance. Let’s say we also have an interface I3 that requires I1, and an interface I4 that requires both I2 and I3. Although both I2 and I3 require I1, I1’s methods remain I1’s, so defining a method implementing I1’s method f1 satisfies the requirement from both I2 and I3.

No comments:

Post a Comment