JDK-6352388 : Uncomparable return type handling in multiple interface inheritance
  • Type: Enhancement
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2005-11-18
  • Updated: 2010-04-02
  • Resolved: 2006-10-31
Related Reports
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
The problem arises when an interface extends two or more interfaces defining a method with the same signature except for the return type, which are uncomparable:

interface A {
     A get();
}

interface B {
     B get();
}

interface C extends A, B {}

where X and Y are uncomparable. It is obvious that this will result in a compile time error.

Now consider these additional definitions:

interface D extends A, B {
    D get();
}

class E implements A, B {
    E get() { ... }
}

In these cases D as well as E inherits two methods with same signature except for uncomparable return types.
As a matter of fact both declarations resolve the problem by defining a new method with covariant return type with respect to both inherited methods.

So compiling D and E should not result in a compile time error!

At current state E compiles and D does not. Looking in the language specification the relevant passages might be:


For classes:

8.4.8.4 Inheriting Methods with Override-Equivalent Signatures

It is possible for a class to inherit multiple methods with override-equivalent (8.4.2) signatures. It is a compile time error
 if a class C inherits a concrete method whose signatures is a subsignature of another concrete method inherited
by C.
...
If the method that is not abstract is static, a compile-time error occurs. Otherwise, the method that is not abstract is considered to override, and therefore to implement, all the other methods on behalf of the class that inherits it. If the signature of the non-abstract method is not a subsignature of each of the other inherited methods an unchecked warning must be issued (unless suppressed (9.6.1.5)). A compile-time error also occurs if the return type of the non-abstract method is not return type substitutable (8.4.5) for each of the other inherited methods. If the return type of the non-abstract method is not a subtype of the return type of any of the other inherited methods, an unchecked warning must be issued. Moreover, a compile-time error occurs if the inherited method that is not abstract has a throws clause that conflicts (8.4.6) with that of any other of the inherited methods.


For interfaces:

9.4.1 Inheritance and Overriding
...
It is possible for an interface to inherit several methods with override-equivalent signatures (8.4.2). Such a situation does not in itself cause a compile-time error. The interface is considered to inherit all the methods. However, one of the inherited methods must must be return type substitutable for any other inherited method; otherwise, a compile-time error occurs (The throws clauses do not cause errors in this case.)
...


So the real question is: Why is it allowed in classes to resolve the conflict by a new covariant method declaration and why is it not allowed in interfaces to resolve the conflict in the exact same way?
Why does the conflict in interfaces has to be resolved by inherited signatures only?

"...one of the inherited methods must must be return type substitutable for any other inherited method..."

JUSTIFICATION :
The enhancement is necessary to declare methods which always return the type of the current interface/class.
(Note that this is only a special case of the usage of this, but it is the most obvious one...)

It would allow situations like this:

interface A {
    A get();
}

interface B {
    B get();
}

interface C extends A, B {
    C get();
}

interface D {
    D get();
}

class E implements C, D {
    E get();
}

and so on.
At present state one has to use less specialized static return types:

interface A {
    Object get();
}

interface B {
    Object get();
}

interface C extends A, B {
    C get();
}

interface D {
    D get();
}

class E implements C, D {
    E get();
}


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect interfaces to react the same way classes do, when it comes to resolving uncomparable inherited return types of signature equivalent methods.
ACTUAL -
At present state interfaces do not allow resolving uncomparable return types of inherited signature equivalent methods by defining a new signature with covariant return type.
Classes do allow this procedure.

---------- BEGIN SOURCE ----------
interface A {
    A get();
}

interface B {
    B get();
}

// does not compile
interface C extends A, B {
    C get();
}

// does compile
class D implements A, B {
    public D get() {
        return null;
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
There is no workaround to this.
The problem can only be avoided by avoiding multiple inheritance in interface declarations.
(Note that this is in not possible in general project specific domains!)

Comments
EVALUATION Which makes this a dupe of compiler bug 6294779.
31-10-2006

EVALUATION interface D extends A, B { D get(); } should compile, as D::get overrides A::get and B::get by JLS9.4.1. This is a compiler error.
31-10-2006