Covariant Return Type in Interface not compiling via Javac
Asked Answered
T

6

9

I have the following structure:

public interface BarReturn {}
public interface FooReturn {}
public interface FooBarReturn extends FooReturn, BarReturn {}

public interface Foo {  
  FooReturn fooBar( );
}

public interface Bar {
  BarReturn fooBar();
}

public interface FooBar extends Foo, Bar {
  FooBarReturn fooBar();
}

Javac fails with the following message:

FooBar.java:2: types Bar and Foo are incompatible; both define fooBar(), but with unrelated return types
public interface FooBar extends Foo, Bar {
       ^
1 error

However, Eclipse can compile it fine, and as far as I can see it should compile - FooBar's fooBar() method satisfies the contract of both Foo and Bar's fooBar() method by using covariant returns.

Is this a bug in the Eclipse compile or in javac? Or is there a way to persuade javac to compile it? For reference my javac options look like this:

javac -d /tmp/covariant/target/classes -sourcepath /tmp/covariant/src/main/java: /tmp/covariant/src/main/java/Foo.java /tmp/covariant/src/main/java/BarReturn.java /tmp/covariant/src/main/java/FooBarReturn.java /tmp/covariant/src/main/java/Bar.java /tmp/covariant/src/main/java/FooReturn.java /tmp/covariant/src/main/java/FooBar.java -g -nowarn -target 1.6 -source 1.6
Tacita answered 14/8, 2011 at 11:18 Comment(3)
Same problem with open-jdk compiler version 1.6.0_22. but it works in java7.Disobey
Just tested it and yes, so it does - great.Tacita
Possible duplicate?Spitz
P
3

You are extending both Foo and Bar in your FooBar interface. As such you are inheriting two methods with incompatible return types. Java co-variance is only allowed when it follows Liskov substitution. Aka, the overriding candidate types must pretty much be a subclass of the overridden return type.

In your example above something like this should compile:

public interface BarReturn {}
public interface FooReturn {}
public interface FooBarReturn extends FooReturn, BarReturn {}

public interface Foo {  
  FooReturn fooBar( );
}

public interface FooBar extends Foo{
  FooBarReturn fooBar();
}
Photofinishing answered 14/8, 2011 at 11:38 Comment(1)
In the OP's code, the return type of the overriding method does subtype the return types of both overridden methods. So from an academic standpoint, there's no reason why the OP's code shouldn't be valid.Empire
G
1

The JLS (§9.4.1) says :

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 I would say that javac is right. But this looks like lawyer jargon to me, so I could be wrong.

Gabionade answered 14/8, 2011 at 11:38 Comment(0)
M
1

An answer in this javaranch discussion seems to suggest that it's a javac bug. However, the referenced bug url doesn't seem to work.

Mecham answered 14/8, 2011 at 11:46 Comment(1)
It seems like JDK-7u4 fixes the bug.Sumy
T
1

As a workaround, you could do

interface Foo1 extends Foo {
  FooBarReturn fooBar();
}
interface Bar1 extends Bar {
  FooBarReturn fooBar();
}
public interface FooBar extends Foo1, Bar1 { }

Not pretty but should do the trick.

Tyrannosaur answered 14/8, 2011 at 15:37 Comment(2)
Thanks, that's a good idea - however, as it compiles with OpenJDK 7's javac and with the eclipse compiler I can work around it without introducing extra types.Tacita
This doesn't seem to work, jdk6's javac still says types Bar1 and Foo1 are incompatible; both define fooBar(), but with unrelated return types.Empire
K
1

I had the same problem and it seems to be fine by using the JDK 7 from Oracle.

Keyes answered 16/5, 2012 at 17:41 Comment(0)
T
0

This is a bug in Sun's Java 6 compiler.

Twyla answered 24/6, 2013 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.