5

This issue may be similar to Reference is ambiguous with generics, but I guess it is a little different.

In this case

public class MyTest {

    public static void main(String[] args) {
        MyTest test = new MyTest();
        test.add(test::method);
    }

    public void add(Interface1 i1) {
    }

    public <T extends Interface2> void add(T i2) {
    }

    private void method() {
    }

    public interface Interface1 {
        void method1();
    }
    public interface Interface2 {
        boolean isMethod2();
        void setMethod2(boolean required);
    }

}

, it is compiled with Eclipse Neon.2, but not with javac 1.8.0_121 or 1.8.0_152, giving an error:

MyTest.java:5: error: reference to add is ambiguous

   test.add(test::method);
       ^

both method add(Interface1) in MyTest and method add(T) in MyTest match

where T is a type-variable:

T extends Interface2 declared in method add(T)



However, if

public <T extends Interface2> void add(T i2) {

is changed to:

public void add(Interface2 i2) {

then it id compiled by javac.


So, is it correct for javac to say T is a type-variable, and is not sub-type of Interface2, so it complains about ambiguity, and if so, then Eclipse is wrong?

Community
  • 1
  • 1
Ahmed Ashour
  • 4,462
  • 10
  • 33
  • 49
  • 2
    eclipse has its' own compiler, and the official Java compiler is the "correct one". So yes, it's correct to say that Eclipse is wrong. – Elliott Frisch Feb 24 '17 at 11:27
  • 2
    @ElliottFrisch I'm sorry, why exactly is `javac` the correct one? – biziclop Feb 24 '17 at 11:35
  • 3
    @biziclop Because the eclipse project has no (or minimal) involvement with the specification of Java (while Oracle **owns** Java). See also, [What is the difference between javac and the Eclipse compiler?](http://stackoverflow.com/questions/3061654/what-is-the-difference-between-javac-and-the-eclipse-compiler). From the linked questions' top answer, *One notable difference is that the Eclipse compiler lets you run code that didn't actually properly compile.* – Elliott Frisch Feb 24 '17 at 11:38
  • 3
    @ElliottFrisch So? I'm sorry, I still don't see your point. If `javac` is by definition the correct one, why do they keep fixing bugs in it? :) Surely whichever compiler conforms to the JLS is the correct one. Sometimes it's the Eclipse compiler, sometimes it's `javac`. In this case I suspect `javac` is the buggy one. (And the quote about the Eclipse compiler letting you run code that didn't compile is irrelevant here, that refers to a different thing.) – biziclop Feb 24 '17 at 11:41
  • I suspect `javac` complains about ambiguity because `T extends Interface2` might in theory resolve `T` to an `Interface3` that extends `Interface2`, defines default methods for `isMethod2()` and `setMethod2()`, and then declares an abstract `void method3()`. – biziclop Feb 24 '17 at 11:47
  • 3
    @biziclop `javac` isn't entirely buggy, `T` could be a Type that implements both `Interface1` and `Interface2`, and in that case both `add(T i2)` and `add(Interface1 i1)` are valid – niceman Feb 24 '17 at 11:47
  • @niceman Yes, that is definitely a potential source of ambiguity. But in this specific case we know it doesn't happen. – biziclop Feb 24 '17 at 11:49
  • ofcourse this doesn't mean the eclipse compiler is entirely wrong because there is not `T` that implements both interfaces in anyway here, what we have here is different strategies – niceman Feb 24 '17 at 11:49
  • @niceman, even if you add `Interface3` to extends both `Interface1` and `Interface2`, and change the method signature of `i2` to `public void add(Interface3 i2) {`, it will compile with `javac`. – Ahmed Ashour Feb 24 '17 at 12:47
  • @AhmedAshour You need to make `Interface3` a functional interface with a `void methodX()`, then it will be ambiguous. – biziclop Feb 24 '17 at 12:52

0 Answers0