Skip to main content



      Home
Home » Language IDEs » Java Development Tools (JDT) » Covariant return types with multiple interfaces
Covariant return types with multiple interfaces [message #248283] Mon, 01 October 2007 05:35 Go to next message
Eclipse UserFriend
Originally posted by: j.abraham.moconso.com

Hi,

I have two independent interfaces which return idependent types for the same
method. Then i have another interface which implements those two and
overrides the method with a covariant return type that also implements the
original two types. A simple example looks like this:

public class CovariantTest {
public static interface Type1 {
}
public static interface Type2 {
}

public static interface Interface1 {
public Type1 getType();
}
public static interface Interface2 {
public Type2 getType();
}

public static interface Type12 extends Type1, Type2 {
}
public static interface Interface12 extends Interface1, Interface2 {
public Type12 getType();
}
}

The funny thing is that this actually works in Eclipse compiler, but if i
try to compile this using the standard JDK 5 or 6 javac compiler, it
complains the implemented interfaces in Interface12 have the same method
with unrelated return types (which is actually no problem since the new
method has a covariant type compatible to both of these types).

My question is: Is this actually a "bug" in Eclipse compiler or is the bug
in javac? Or are those just two different interpretations of some stupid
specification?

Thanks,
Jaroslav
Re: Covariant return types with multiple interfaces [message #248298 is a reply to message #248283] Mon, 01 October 2007 17:06 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: wharley.bea.com

"Jaroslav Abraham" <j.abraham@moconso.com> wrote in message
news:fdqeuu$rdc$1@build.eclipse.org...
> Hi,
>
> I have two independent interfaces which return idependent types for the
> same method. Then i have another interface which implements those two and
> overrides the method with a covariant return type that also implements the
> original two types. A simple example looks like this:
>
> public class CovariantTest {
> public static interface Type1 {
> }
> public static interface Type2 {
> }
>
> public static interface Interface1 {
> public Type1 getType();
> }
> public static interface Interface2 {
> public Type2 getType();
> }
>
> public static interface Type12 extends Type1, Type2 {
> }
> public static interface Interface12 extends Interface1, Interface2 {
> public Type12 getType();
> }
> }
>
> The funny thing is that this actually works in Eclipse compiler, but if i
> try to compile this using the standard JDK 5 or 6 javac compiler, it
> complains the implemented interfaces in Interface12 have the same method
> with unrelated return types (which is actually no problem since the new
> method has a covariant type compatible to both of these types).
>
> My question is: Is this actually a "bug" in Eclipse compiler or is the bug
> in javac? Or are those just two different interpretations of some stupid
> specification?


In the code sample above there is no conflict; see
http://java.sun.com/docs/books/jls/third_edition/html/classe s.html#8.4.8 for
details on the spec.

However, you mention "implemented interfaces" that you don't show here; and
I assume that Type1 and Type2 actually have some methods in them. If Type1
and Type2 have a same-named method with different (incompatible) return
types, then there is no way to implement Type12.

Can you show a complete example of code that actually compiles in Eclipse
and fails in javac?
Re: Covariant return types with multiple interfaces [message #248308 is a reply to message #248283] Mon, 01 October 2007 19:24 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: news.jnana.de

Jaroslav Abraham wrote:

>My question is: Is this actually a "bug" in Eclipse compiler or is the bug
>in javac? Or are those just two different interpretations of some stupid
>specification?

It's a bug in the Eclipse compiler. The JLS3rd states this case clearly in
9.4.1:

»... 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. ...«

And that is exactly what happens in your example:

interface I1 { C1 foo(); }
interface I2 { C2 foo(); }

interface I3 extends I1, I2 {} <-- compile time error

Here I3 inherits several methods with override-equivalent signatures,
explanation:

I1#foo() has the signature consisting of the name »foo« and an empty argument list.

I2#foo() has the signature consisting of the name »foo« and an empty argument list.

Hence, after 8.4.2 they have the same signature (»Two methods have the same signature if they have the same name and argument types.«)

Also, after 8.4.2 the signature of I1#foo() is a subsignature of the signature of I2#foo() (and vice versa) (»The signature of a method m1 is a subsignature of the signature of a method m2 if either m2 has the same signature as m1, or ...«)

And finally also after 8.4.2 the signatures of both methods are override-equivalent. (»Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.«)

Now that we have shown that I3 indeed inherits several methods with
override-equivalent signatures, the rest of the cited rules apply,
especially this part: »However, one of the inherited methods must must be
return type substitutable for any other inherited method; otherwise, a
compile-time error occurs.«

And this is not the case in the example. The return types in question are
C1 and C2 and either C1 has to be a subtype of C2 or C2 has to be a
subtype of C1, if neither is the case, as in our example, then a compile
time error occurs.


OK, so far i have explained, why Suns javac is right and why the Eclipse
compiler can be considered buggy according to the spec.

However, your example is a little more sophisticated:

interface C1 {}
interface C2 {}
interface C3 extends C1,C2 {}

interface I1 { C1 foo(); }
interface I2 { C2 foo(); }

interface I3 extends I1, I2 {} <-- still compile time error

Now there still is a compile time error, because the rules explained above
still apply. But it is your intention to override both foo methods with a
method, that actually is return type substutable to both, and the only
thing that keeps you from doing so, is the above compile time error. (This
might allow the question if the spec is correct to forbid such
constructions, but that is another question, which I don't want to delve
into here.) Now there should be several workarounds, because all you have
to do is, that I3 inherits the required return type substitutable
override-equivalent method.

Workaround 1:

interface C1 {}
interface C2 {}
interface C3 extends C1,C2 {}

interface I1 { C1 foo(); }
interface I2 { C2 foo(); }

interface IntermediateI2 { C3 foo(); }

interface I3 extends I1, IntermediateI2 {} <-- no error !!

So this workaround actually works with javac. (At least with the current
1.6 javac I use here.)

However, this should also work

Workaround 2:

interface C1 {}
interface C2 {}
interface C3 extends C1,C2 {}

interface I1 { C1 foo(); }
interface I2 { C2 foo(); }

interface Extra { C3 foo(); }

interface I3 extends I1, I2, Extra {} <-- again compile-time error

Remember: »However, one of the inherited methods must must be return type
substitutable for any other inherited method; otherwise, a compile-time
error occurs.«

And we have one method, namely Extra#foo(), that is return type
substitutable to the others (C3 is subtype of C1 and C2), so our
declaration is correct according to the spec. but here javac still raises
an error. So javac seems to be also buggy regarding this special rule.

There is also a third Workaround using Generics:

interface C1 {}
interface C2 {}
interface C3 extends C1,C2 {}

interface I1<T extends C1> { T foo(); }
interface I2<T extends C2> { T foo(); }

interface I3a<T extends C1 & C2> extends I1<T>, I2<T> {}
or
interface I3b<T extends C3> extends I1<T>, I2<T> {}

And I think the fact, that this third Workaround exists and works, and
after type erasure is applied, results (in case of I3b) exactly the same
signatures as your original example, makes this the best argument for a
change in the spec in order to relax the rules of 9.4.1. (And in return
makes the behavior of the Eclipse compiler very much reasonable even
though it breaks with the spec.)

HTH

cu
Re: Covariant return types with multiple interfaces [message #248313 is a reply to message #248298] Mon, 01 October 2007 19:27 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: news.jnana.de

Walter Harley wrote:

>In the code sample above there is no conflict; see
> http://java.sun.com/docs/books/jls/third_edition/html/classe s.html#8.4.8
>for details on the spec.

Chapter 8 is about classes. But the error in question is raised on an
interface declaration and those are specified in chapter 9. Further
details in my other posting.

cu
Re: Covariant return types with multiple interfaces [message #248318 is a reply to message #248308] Mon, 01 October 2007 19:36 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: news.jnana.de

Ralf Ullrich wrote:

>Workaround 1:
>
> interface C1 {}
> interface C2 {}
> interface C3 extends C1,C2 {}
>
> interface I1 { C1 foo(); }
> interface I2 { C2 foo(); }
>
> interface IntermediateI2 { C3 foo(); }

Darn, this should have been

interface IntermediateI2 { C3 foo(); } extends I2 {}

>
> interface I3 extends I1, IntermediateI2 {} <-- no error !!
>
>So this workaround actually works with javac. (At least with the current
>1.6 javac I use here.)
>
>However, this should also work

Well I had made the same mistake in my tests, and after I corrected it,
the error was back. So Workaround 1 does not work with javac, but should
work according to the spec.

Sorry for thie mistakes, the only excuse I have, is, that it's late night
here in Germany.

cu
Re: Covariant return types with multiple interfaces [message #248801 is a reply to message #248298] Tue, 16 October 2007 12:19 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: j.abraham.moconso.com

The example that compiles in Eclipse is in the original post (public class
CovariantTest {...}), just copy&paste.

"Walter Harley" <wharley@bea.com> schrieb im Newsbeitrag
news:fdrnfo$fha$1@build.eclipse.org...
> "Jaroslav Abraham" <j.abraham@moconso.com> wrote in message
> news:fdqeuu$rdc$1@build.eclipse.org...
>> Hi,
>>
>> I have two independent interfaces which return idependent types for the
>> same method. Then i have another interface which implements those two and
>> overrides the method with a covariant return type that also implements
>> the original two types. A simple example looks like this:
>>
>> public class CovariantTest {
>> public static interface Type1 {
>> }
>> public static interface Type2 {
>> }
>>
>> public static interface Interface1 {
>> public Type1 getType();
>> }
>> public static interface Interface2 {
>> public Type2 getType();
>> }
>>
>> public static interface Type12 extends Type1, Type2 {
>> }
>> public static interface Interface12 extends Interface1, Interface2 {
>> public Type12 getType();
>> }
>> }
>>
>> The funny thing is that this actually works in Eclipse compiler, but if i
>> try to compile this using the standard JDK 5 or 6 javac compiler, it
>> complains the implemented interfaces in Interface12 have the same method
>> with unrelated return types (which is actually no problem since the new
>> method has a covariant type compatible to both of these types).
>>
>> My question is: Is this actually a "bug" in Eclipse compiler or is the
>> bug in javac? Or are those just two different interpretations of some
>> stupid specification?
>
>
> In the code sample above there is no conflict; see
> http://java.sun.com/docs/books/jls/third_edition/html/classe s.html#8.4.8
> for details on the spec.
>
> However, you mention "implemented interfaces" that you don't show here;
> and I assume that Type1 and Type2 actually have some methods in them. If
> Type1 and Type2 have a same-named method with different (incompatible)
> return types, then there is no way to implement Type12.
>
> Can you show a complete example of code that actually compiles in Eclipse
> and fails in javac?
>
Re: Covariant return types with multiple interfaces [message #248806 is a reply to message #248318] Tue, 16 October 2007 12:24 Go to previous message
Eclipse UserFriend
Originally posted by: j.abraham.moconso.com

Hi,

thanks a lot for your looong post, my greetings also from Germany :)

I'll try some workaround. It's a pity that javac is so strict, because
logically it makes perfectly sense.

J.

"Ralf Ullrich" <news@jnana.de> schrieb im Newsbeitrag
news:xn0fbyg0j917y0y00k@news.eclipse.org...
> Ralf Ullrich wrote:
>
>>Workaround 1:
>>
>> interface C1 {}
>> interface C2 {}
>> interface C3 extends C1,C2 {}
>>
>> interface I1 { C1 foo(); }
>> interface I2 { C2 foo(); }
>>
>> interface IntermediateI2 { C3 foo(); }
>
> Darn, this should have been
>
> interface IntermediateI2 { C3 foo(); } extends I2 {}
>
>>
>> interface I3 extends I1, IntermediateI2 {} <-- no error !!
>>
>>So this workaround actually works with javac. (At least with the current
>>1.6 javac I use here.)
>>
>>However, this should also work
>
> Well I had made the same mistake in my tests, and after I corrected it,
> the error was back. So Workaround 1 does not work with javac, but should
> work according to the spec.
>
> Sorry for thie mistakes, the only excuse I have, is, that it's late night
> here in Germany.
>
> cu
Previous Topic:So when will Eclipse be totally Java 1.6???
Next Topic:Eclipse frequently crashing with out of memory errors
Goto Forum:
  


Current Time: Wed May 07 17:18:18 EDT 2025

Powered by FUDForum. Page generated in 0.04011 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top