5

First, a little background (or skip down a little if not interested). I'm irritated and confused! This should be a pretty simple use case, and indeed my code has been compiling just fine with the Eclipse JDT compiler, so until now I've been configuring Maven to make sure to do this. It's been bothering me too much though that it doesn't compile with the Oracle JDK and OpenJDK, as I thought it may actually have been a problem with my code, so I've looked into it again.

I thought perhaps that the bug was in the JDT compiler for allowing it to compile, not the Oracle JDK and OpenJDK for not allowing it, both of which I've also tested this with. The original code in question was considerably more complicated, so it was much more difficult for me to see where the problem was, and in fact I was very surprised to see the extent to which this could be reduced whilst still not compiling.

Either the Eclipse JDT compiler or the Oracle JDK and OpenJDK have a pretty major (imho) bug.

TL;DR

This is a fairly minimal representation of the code in question. (The type bound of Anything can be replaced by any interface and the compiler behaviour won't change):

public class Bug<X extends Property<?, ?> & Anything> {
}

interface Property<C, S extends C> extends PropertyConst<C> {
    @Override
    public S get();
}

interface PropertyConst<C> {
    public C get();
}

interface Anything {
}

To summarise, I think this should compile just fine, but the Oracle JDK 7 & 8 and OpenJDK 7 disagree. It does compile for me using Eclipse Juno.

When compiled with either of those compilers the code above gives something like the following error, but works just fine with the JDT compiler:

Bug.java:3: error: types PropertyConst<?> and Property<?,?> are incompatible; both define get(), but with unrelated return types
public class Bug<X extends Property<?, ?> & Anything> {
                 ^
1 error

This makes no sense. The return types are obviously related because one of the two methods referenced necessarily frickin' overrides the other. I'm pretty much 99% confident that this should work, in fact the only reason that last 1% is missing is that it's just too basic a use of generics for this to not have been spotted, and yet I found no bug report relating to it. (Admittedly I didn't look to hard because http://bugs.sun.com/ is just the worst. Can you even filter keyword search results by whether a bug report is still open? Ugh.)

The most confusing part for me is that it compiles just fine when you remove the type bounding for Anything on X, even though the extra interface has nothing to do with the error.

Can anybody put my mind at rest? Anyone know of a bug report which exists for this, or has had experience with it before and can tell me what the problem is? If I don't get any conclusive answers I'll file some bug reports.

Edit:

A couple of people have pointed out that I had a forward reference error with <S extends C, C>. Don't know why I wasn't getting this error, it even compiled in Eclipse with the JDT...

Anyway, it still doesn't compile for me with OpenJDK 7 or Oracle JDK 7 / 8, so I modified the question to remove the issue.

Edit 2:

A quick check confirms that this sort of forward reference is now legal in Java 7. As it should be!

Edit 3:

I've posted bug reports on http://bugs.sun.com/. I'll post links here if/when they're accepted.

Elias Vasylenko
  • 1,524
  • 11
  • 21
  • The problem is ? does not equal ? – Charlie Nov 21 '12 at 20:56
  • Did you run your tests on java 6 or 7? – assylias Nov 21 '12 at 20:57
  • Do you still have error, if you remove `Anything` interface ? – Damian Leszczyński - Vash Nov 21 '12 at 20:57
  • Did you also notice the "Illegal Forward Reference" error in eclipse? (see also [this question](http://stackoverflow.com/questions/4628608/java-generics-illegal-forward-reference)) Invert the arguments on Property's generic declaration – Charlie Nov 21 '12 at 21:04
  • @Charlie - the problem is it doesn't compile, but I think it should! – Elias Vasylenko Nov 21 '12 at 21:06
  • @assylias - 7, though I've even tried compiling with Oracle JDK 8, still doesn't compile there. – Elias Vasylenko Nov 21 '12 at 21:07
  • @Vash - No error If I remove Anything, though the error remains if you replace it with any other interface. I'll try to make all these points clearer in the question, thanks for the feedback everyone. – Elias Vasylenko Nov 21 '12 at 21:09
  • @Charlie I didn't, is that even still in the spec? No error for it and definitely compiles in the JDT, seems like too obvious a feature for them to accidentally leave out... If I swap them round it still doesn't work anyways, I'll change the order in the question to make sure that's clear though, thanks :) – Elias Vasylenko Nov 21 '12 at 21:10
  • Works OK for me on Windows 7, JDK 1.7.0_07, Eclipse Juno I20120608-1400 and JDT/PDE 3.8.0.v20120525 – clstrfsck Nov 21 '12 at 21:24
  • @msandiford - It works for me too using the Eclipse compiler, could you please verify that you have specifically used the Oracle JDK or the OpenJDK, and that it compiles for one of those? Thanks for the feedback :) – Elias Vasylenko Nov 21 '12 at 21:26
  • 2
    OK, read question again. Works here with JDK 1.5.0_10 (need to remove interface @Override), 1.6.0_27. Fails with 1.7.0_07 and 1.7.0_09. – clstrfsck Nov 21 '12 at 22:24
  • @msandiford - Awesome, thanks for the confirmation :). Will submit a bug report. Not gonna do it right now though, it's like 22:40 and I've not even eaten yet today... – Elias Vasylenko Nov 21 '12 at 22:41

3 Answers3

2

It's apparently a javac bug you should report. You probably have better luck asking on one of open jdk mailing lists. But it's Thanksgiving so ...

This is not a basic usage of generics though, it's quite complicated.

irreputable
  • 44,725
  • 9
  • 65
  • 93
  • Thanks for the vote of confidence! I just wanted to ask here first to save myself from embarrassment by filing a silly bug report... I'll make sure to file one at some point though. And you should see some of my other abuses of generics haha... It's criminal sometimes. I know that's probably not a good thing, but it's a personal project and I'm enjoying myself ;). If this bug is confirmed I actually might have a few others to report too, this is far from the only place the JDT disagrees with Oracle/OpenJDK. Yea I forgot about TG, I live in the UK. – Elias Vasylenko Nov 21 '12 at 21:37
  • P.S. I'll mark this answer as correct if I don't see any disagreement over the next day or so. – Elias Vasylenko Nov 21 '12 at 21:39
  • Meh, already looks pretty clear cut at this point, so marked as answered. Thanks for the help, and thanks everyone else who tested too :) – Elias Vasylenko Nov 21 '12 at 23:08
0

I've entered your sample into my Eclipse Indigo (3.7.1) and it complained immediately about declaration of Property interface.

Illegal forward reference to type parameter C

And for the line public S get();

The return type is incompatible with PropertyConst.get()

Changing declaration of Property to this

interface Property<C, S extends C > extends PropertyConst<C> {
    @Override
    public S get();
}

fixed both errors, and compiles both in JDT and Sun's 1.6 compiler

Alexander Pogrebnyak
  • 44,836
  • 10
  • 105
  • 121
0

Didn't try it out, but in

public class Bug<X extends Property<?, ?> & Anything> {

there is no restraint on both ?'s. One would need something like:

public class Bug<C, X extends Property<C, ? extends C> & Anything> {
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • You shouldn't need that afaiu, the existing bounds as specified in the Property interfaces definition should be carried forward implicitly in this case. Property, ?> doesn't mean that Property can be parametrised with literally anything, just that we don't care about how it is parametrised here. The actual parametrisation of Property here will be verified for the type which is supplied to X when Bug is parametrised... Sorry for the awkward explanation, it's not easy to word this clearly... – Elias Vasylenko Nov 21 '12 at 23:06