A perspective on interfaces

How to solve problems with Java's interfaces

About three years ago, I was telling somebody about an article I had read that described a project to extend (GNU) C++. The article mentioned a new concept: signatures. When I had to explain the project in detail, I began to stutter because I realized I hadn't fully understood the article.

When Java introduced interfaces and I started to understand how they worked, it dawned on me that they were similar to the signatures I'd read about in that article. They have exactly the same purpose: To create type safety without the tight coupling of inheritance. Once I fully understood the purpose of Java's interfaces, I began to really love them.

Having used interfaces for two years now, I still love them, but my view of them has matured. In fact, I have identified several problems with interfaces:

  1. Significant increase in package sizes
  2. No version migration path
  3. Name scoping
  4. No default implementation

Increase in package sizes

The first problem is the explosion in the number of classes and interfaces. I just downloaded the JDK 1.2 beta 2 and immediately looked at the package overview. The first thing that becomes obvious is the huge number of packages and classes. The simplicity promised by JDK 1.0.2 appears to be awfully far off in the distance. I guess that's progress for ya. ;)

Looking a bit further into interfaces, I found that Swing, the new lightweight user interface framework, is causing the biggest expansion in Java 1.2 (along with the abstract windowing toolkit [AWT]). One of the reasons for this, strangely enough, is the interface. The interface has caused the number of classes and interfaces to double, at least. The designers of Java 1.2 seem to have a particular rule: to use interfaces whenever possible. While this provides a lot of flexibility, it also increases the conceptual complexity of the design. To do something useful, however, an implementation is needed, and this results in a class that has a name very similar to that of the interface. Personally, I do not like this explosion because of the significant increase in complexity that comes along with it.

Future extensibility

The second problem I see is future extensibility. Once an interface is distributed, there can never be a change in its definition. A change would immediately break all existing code. For example, let's say we have the following interface:

public interface I {
    public void f();
}

Now, in the next release we want to extend it with a new method:

public interface I {
    public void f();
    public void g();
}

When a class that implements the original interface is compiled with the updated interface, then the code breaks. The old class does not implement the new, now required function g().

Name scoping

Another problem is the scoping of the method names in an interface definition. A class that implements an interface with function f() can not implement another interface with function f(). But what do you do if interfaces overlap in their function names? You could take the precaution of using rather large and descriptive names, but this often makes the interfaces less readable.

For example, recently I had a Service interface for which start() and stop() were the logical names to use. I changed the names to startService() and stopService() to allow services that inherit from the class Thread to implement this interface. The Thread class has two methods named: start() and stop(). These methods control the state of the thread. Any interface that will use the method names start and stop can never be implemented by a subclass of the Thread class. Java has no scoping operator like C++ (the ::) to tell the compiler exactly what should be done in the case of overlapping method names from different interfaces or the superclass.

Lack of default implementation

The final problem is the lack of default implementation. When a class extends another class, this other class can provide default implementations for all the methods. Sometimes a subclass can be created simply by extending a superclass and using the entire implementation of the superclass. Some interfaces are quite extensive, and implementing all methods can be a lot of work. This is especially irritating when only one or two methods are useful to implement in a certain situation. The interface concept forces the user of the interface to implement every method in the definition. For example, the Swing ButtonModel interface has 21 (!) methods defined. Quite often, an implementation wants to implement only a part of this interface, and it should be possible to do this.

Solving the problems

How can these problems be solved? Any operation in this area should be implemented with care. Fortunately, Sun is extremely careful in making any language changes to prevent the kind of disaster that hit the C++ standardization process. Doing the mental exercise to formulate a solution to the sketched problems, however, can't do any harm.

So, what's one solution to many of the problems discussed above? Just add to the language a new keyword: "like," which you then use in place of "extends" and "interface":

public class C like A {
}

You should interpret the code above as follows: C should implement the same interface as A. If C does not implement a required method, however, the implementation is copied from A. The keyword "like" basically means: Treat a class as an interface definition and copy the code of that class when no implementation is supplied (if not abstract).

Using this keyword will solve the problem of duplication of classes and interfaces, as well as the issues of default implementation and extension discussed above. It seems feasible to implement this change in the current language version without requiring changes in the current virtual machines.

Conclusion

These are just first thoughts on the matter of interfaces. In my opinion, continued effort should be made to provide solutions to these problems -- of course, always with the caveat that changing the Java language should be done with extreme caution.

Even with the problems listed above, believe me when I say I am still in love with interfaces!

Peter Kriens is an experienced software consultant mainly working in the telecommunications area. Currently, he works for Ericsson Telecom in Mlndal on network management and in Stockholm for Ericsson Software Research. He is one of the organizers of the OOPSLA DesignFest and a long time user of object-oriented technologies. He has been working with Java intensely for the last 18 months.