5

Consider the following code, which is an extraction of a real use case where LinkedList<E> implements both List<E> and Deque<E>.

One can observe that both interfaces have a size() and an isEmpty() method, where the isEmpty() method could be made default in terms of size().

So, let's do that (with dummy interfaces), since Java 8 does not do it yet:

interface List<E> {
    public int size();

    default public boolean isEmpty() {
        return (size() == 0);
    }

    //more list operations
}

interface Deque<E> {
    public int size();

    default public boolean isEmpty() {
        return (size() == 0);
    }

    //more deque operations
}

class LinkedList<E> implements List<E>, Deque<E> {
    private int size;

    @Override
    public int size() {
        return size;
    }
}

Oops! We get a compile-time error on LinkedList, as it does not know which isEmpty() implementation to use, so we add this:

@Override
public boolean isEmpty() {
    return List.super.isEmpty();
}

Now we have lost practically all benefits of default methods for this use case, as it still takes us as much code to write the isEmpty() method as it did before.

But can it be solved? Yes!

Consider the following implementation:

interface Sizable {
    public int size();

    default public boolean isEmpty() {
        return (size() == 0);
    }
}

interface List<E> extends Sizable {
    //list operations
}

interface Deque<E> extends Sizable {
    //deque operations
}

class LinkedList<E> implements List<E>, Deque<E> {
    private int size;

    @Override
    public int size() {
        return size;
    }
}

So the question:

  • Is this how we, and also the JDK, are supposed to handle it in future implementations?
skiwi
  • 66,971
  • 31
  • 131
  • 216
  • 2
    Just to let you know, in your example, `Collection` interface has `size` and `isEmpty` methods, and both `List` and `Deque` extend from `Collection`... But yes, looks like that's they way it has to be now. – Luiggi Mendoza Apr 07 '14 at 19:27
  • 6
    The point of default methods is not to let you write fewer methods, with fewer lines of code (although 1 line of code doesn't look bad to me). The point of default methods is to be able to introduce new methods in interfaces without breaking existing implementations. – JB Nizet Apr 07 '14 at 19:30
  • 1
    @JBNizet Should default methods, as secondary goal, not be used to ensure that implementors of an interface have less work to do? – skiwi Apr 07 '14 at 19:34
  • When creating a new interface with a default method _foobar_, is there any way to know in advance, that somebody will later inherit from your interface and also from some other interface of a completely unrelated library, that accidentally contains a default method with the same name and signature? – nosid Apr 07 '14 at 19:34
  • @nosid In this case both interfaces are 'yours' though... If there's really two totally unrelated things, then you're correct that it's not possible. – skiwi Apr 07 '14 at 19:36
  • 3
    @skiwi: they can be used with this goal, obviously. But if the implementor chooses to override two different interfaces having a common default method, then the implementor will have to override the method and choose the version he wants (or reimplement it). That's just one line of code needed. I wouldn't call that a problem. – JB Nizet Apr 07 '14 at 19:43
  • 3
    +1. I tend to see this as a solution in search of a problem – Louis Wasserman Apr 07 '14 at 20:05

1 Answers1

4

I strongly discourage from adding super-interfaces for unrelated interfaces just for defining default methods. Normally, you don’t have that problem as either, the interfaces are related like in your example so that a natural super-interface like Collection exists or could be defined for more than just providing default methods. Or they are really unrelated and a class implementing both is either unlikely or will have to define which semantics to inherit, anyway.

In case of the Collection API having no default method for isEmpty is intentional as size can be an expensive operation for some Collections. If your Collection shares behavior with typical Collections you may inherit from AbstractCollection.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Is that no the point of the ability to override default methods? If the `isEmpty` *can* be calculated easier, then you should provide such implementation in your concrete class. I believe we have the same issue with for example a custom implementaiton of a `LinkedList`, where even though we have default functionality for some methods, we wish to override it for better behaviour. Or am I missing something? – skiwi Apr 08 '14 at 09:07
  • You explicitly choose to inherit a particular implementation when subclassing, e.g. `AbstractList` or `AbstractSequentialList`. An `interface` should not foist an implementation to its implementors. Of course, a certain implementation might be so common that a decision to add a `default` seems naturally, like with `Iterator.remove`. But unlike `Collection`s, `Iterator`s are usually implemented without the aid of an `abstract` base class. There are a lot of `Collection` methods for which a default can be provided, but `AbstractCollection` does that already. – Holger Apr 08 '14 at 09:24