Monday, February 28, 2011

Things that Java got wrong, part 2: interface method bodies

The concept of the interface in Java is undoubtedly one of the best things about the language.  It almost, but not quite, makes up for not having pure multiple inheritance.  I particularly like the fact that you can define zero or more method signatures as well as zero or more constants.

But why not allow abstract method bodies?  If that sounds like a contradiction in terms, let me try to explain.  I'm using the term abstract in the sense of non-concrete.  Let's take an example.  You define an interface called SetOperable<T> and you define the following methods:

public abstract SetOperable<T> intersect(SetOperable<T> s);

 public abstract SetOperable<T> union(SetOperable<T> s);

 public abstract Collection<T> members();

 public abstract SetOperable<T> clear();

 public abstract SetOperable<T> add(T t);
Now, whereas you want to be able to implement the set operations on any type T, you are clearly going to have to define, in a concrete type, either the intersect or the union method.  But the other method is normally derivable in terms of the first.

So, in Java, you must create an abstract class which implements the required interface and which looks something like the following:

public abstract class SetOperable_<T> implements SetOperable<T> {

 @Override
 public SetOperable<T> union(final SetOperable<T> s) {
  final Collection<T> temp = new ArrayList<T>(members());
  temp.addAll(s.members());
  final SetOperable<T> intersection = intersect(s);
  final SetOperable<T> result = intersection.clear();
  final Collection<T> duplicates = intersection.members();
  final Iterator<T> iterator = temp.iterator();
  while (iterator.hasNext()) {
   final T t = iterator.next();
   if (duplicates.contains(t)) {
    iterator.remove();
    duplicates.remove(t);
   }
  }
  for (final T t : temp)
   result.add(t);
  return result;
 }
}

Concrete classes will extend this abstract class, defining the details of intersect, members, clear, add, etc.  But it would be so much nicer to be able to define this union method in the interface itself and not have to bother with an abstract class, assuming of course that you can define the method in terms of the interface (or its super-interfaces).  Scala allows you to do just that, at least in its own way, but not Java.

I admit that it's not the end of the world, but it can be awkward if you have a concrete class that should extend some other type as well as extending the above abstract class.  You can't have it extend both.  In the given example, you might want your concrete class to extend AbstractSet, for example.

OK, back to work!