Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are sub-interfaces the solution to default-method conflicts?

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?
like image 693
skiwi Avatar asked Oct 01 '22 02:10

skiwi


1 Answers

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.

like image 180
Holger Avatar answered Oct 20 '22 14:10

Holger