This discussion is archived
6 Replies Latest reply: Apr 14, 2011 6:25 AM by 803691 RSS

Reference is ambiguous with generics

848756 Newbie
Currently Being Moderated
I posted this question on Stackoverflow, thinking this is a bug and some people confirmed my thinking:
[http://stackoverflow.com/questions/5361513/reference-is-ambiguous-with-generics]

----

I'm having quite a tricky case here with generics and method overloading. Check out this example class:
public class Test {
    public <T> void setValue(Parameter<T> parameter, T value) {
    }

    public <T> void setValue(Parameter<T> parameter, Field<T> value) {
    }

    public void test() {
        // This works perfectly. <T> is bound to String
        // ambiguity between setValue(.., String) and setValue(.., Field)
        // is impossible as String and Field are incompatible
        Parameter<String> p1 = getP1();
        Field<String> f1 = getF1();
        setValue(p1, f1);

        // This causes issues. <T> is bound to Object
        // ambiguity between setValue(.., Object) and setValue(.., Field)
        // is possible as Object and Field are compatible
        Parameter<Object> p2 = getP2();
        Field<Object> f2 = getF2();
        setValue(p2, f2);
    }

    private Parameter<String> getP1() {...}
    private Parameter<Object> getP2() {...}

    private Field<String> getF1() {...}
    private Field<Object> getF2() {...}
}
The above example compiles perfectly in Eclipse (Java 1.6_24), but not with the Ant javac command (or with the JDK's javac command), where I get this sort of error message on the second invocation of setValue:

reference to setValue is ambiguous, both method setValue(org.jooq.Parameter,T) in Test and method setValue(org.jooq.Parameter,org.jooq.Field) in Test match

According to the specification and to my understanding of how the Java compiler works, the most specific method should always be chosen: [http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20448]
In any case, even if <T> is bound to Object, which makes both setValue methods acceptable candidates for invocation, the one with the Field parameter will always be more specific. And it works in Eclipse, just not in ant.

Like this, it would work both in Eclipse and in ant (with rawtypes warnings, of course)
    public <T> void setValue(Parameter<T> parameter, Object value) {
    }

    public <T> void setValue(Parameter<T> parameter, Field value) {
    }
Am I misunderstanding something here? Is there a known compiler bug related to this? Or is there a workaround/compiler setting to help me?
  • 1. Re: Reference is ambiguous with generics
    796440 Guru
    Currently Being Moderated
    user12557111 wrote:
    The above example compiles perfectly in Eclipse (Java 1.6_24), but not with the Ant javac command (or with the JDK's javac command),
    Ant doesn't have its own compiler.
    According to the specification and to my understanding of how the Java compiler works, the most specific method should always be chosen:
    Yes. But determining which method is most specific is non-trivial, and not necessarily intuitive, particularly when generics are involved. I don't know what the correct behavior is, and I'm not interested in trying to decipher the rules. If you're feeling ambitious, here they are:

    http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.2
  • 2. Re: Reference is ambiguous with generics
    848756 Newbie
    Currently Being Moderated
    Thanks for your reply. That's true, ant uses the JDK's compiler. Your link is the same as mine, I already went through the documentation of choosing the most specific method signature among all acceptable methods. I have to admit that I don't entirely understand the whole reasoning behind that, but the behaviour looks quite wrong to me in this particular case. Note that Eclipse's compiler links method invocations correctly in my example.
  • 3. Re: Reference is ambiguous with generics
    EJP Guru
    Currently Being Moderated
    The Eclipse compiler has often been slightly more correct than the JDK compiler in Generics. If you think this is a bug report it via the Bug Parade.
  • 4. Re: Reference is ambiguous with generics
    jschellSomeoneStoleMyAlias Expert
    Currently Being Moderated
    As a note.

    There is a generics forum.

    And at least at one time not to long ago someone was answering questions there that seemed to have quite a bit of knowledge of what generic really should do. My impression was that they might have been involved in creating the standard.
  • 5. Re: Reference is ambiguous with generics
    852060 Newbie
    Currently Being Moderated
    jschell wrote:
    And at least at one time not to long ago someone was answering questions there that seemed to have quite a bit of knowledge of what generic really should do. My impression was that they might have been involved in creating the standard.
    I don't want to presume that you mean me, but just in case you do: I never had any affiliation with Sun or Oracle and was not involved in creating the standard.

    W.r.t. the question, I really think it was answered very precisely by irreputable over at stackoverflow. Nonetheless I can go into a little more detail since this is a relatively simple case.
    public <T1> void setValue(Parameter<T1> parameter, T1 value); // method 1
    public <T2> void setValue(Parameter<T2> parameter, Field<T2> value); // method 2
    I think we all agree that both methods are potentially applicable (§15.12.2.1), so let's go straight into identifying matching arity methods applicable by subtyping (§15.12.2.2):

    &bull; A ~1~ = Parameter&lang;Object&rang;
    &bull; A ~2~ = Field&lang;Object&rang;

    Method 1 (generic &rArr; first bullet point)
    &bull; F ~1~ = Parameter&lang;T1&rang;
    &bull; F ~2~ = T1
    &bull; R ~1~ = T1
    &bull; B ~1~ = Object (assumed, see §4.4)
    &bull; U ~1~ = Object (§15.12.2.7)
        &bull; initial constaints: { Parameter&lang;Object&rang; &lt;&lt; Parameter&lang;T1&rang;, Field&lang;Object&rang; &lt;&lt; T1 }
            &bull; for the first constraint we end up at list item 2.2.4 and apply list item 2.3.1 recursively to Object = T1
            &bull; for the second constraint it's list item 2.2.2
        &bull; implied constraints: { T1 = Object, Field&lang;Object&rang; &lt;: T1 }, concluding U ~1~ = Object is trivial

    &rArr;
    &bull; S ~1~ = Parameter&lang;Object&rang;
    &bull; S ~2~ = Object

    Since the following conditions hold, the method is applicable by subtyping:

    &bull; A ~1~ &lt;: S ~1~, A ~2~ &lt;: S ~2~
    &bull; Object &lt;: Object

    Method 2 (generic &rArr; first bullet point)
    &bull; F ~1~ = Parameter&lang;T2&rang;
    &bull; F ~2~ = Field&lang;T2&rang;
    &bull; R ~1~ = T2
    &bull; B ~1~ = Object (assumed, see §4.4)
    &bull; U ~1~ = Object (§15.12.2.7)
        &bull; initial constaints: { Parameter&lang;Object&rang; &lt;&lt; Parameter&lang;T2&rang;, Field&lang;Object&rang; &lt;&lt; Field&lang;T2&rang; }
            &bull; same as above for the first constraint and
            &bull; the second constraint works just the same
        &bull; implied constraints: { T2 = Object }, concluding U ~1~ = Object is even more trivial

    &rArr;
    &bull; S ~1~ = Parameter&lang;Object&rang;
    &bull; S ~2~ = Field&lang;Object&rang;

    Since the following conditions hold, the method is applicable by subtyping:

    &bull; A ~1~ &lt;: S ~1~, A ~2~ &lt;: S ~2~
    &bull; Object &lt;: Object

    -----

    When a method is applicable by subtyping we get to jump directly to choosing the most specific method (§15.12.2.5):

    Is method 1 more specific than method 2? They both have fixed arity, same name and same arity, so we need to go through the first bullet list.

    &bull; T ~1~ = Parameter&lang;T1&rang;
    &bull; T ~2~ = T1
    &bull; U ~1~ = Parameter&lang;T2&rang;
    &bull; U ~2~ = Field&lang;T2&rang;
    &bull; R ~1~ = T2
    &bull; B ~1~ = Object (assumed, see §4.4)
    &bull; A ~1~ = T1
        &bull; initial constaints: { Parameter&lang;T1&rang; &lt;&lt; Parameter&lang;T2&rang;, T1 &lt;&lt; Field&lang;T2&rang; }
            &bull; first constraint still works the same
            &bull; for the second constraint we it's list item 2.2.7 (no constaint is implied)
        &bull; implied constraints: { T1 = T2 } &rArr; A ~1~ = T1
    &bull; S ~1~ = Parameter&lang;T1&rang;
    &bull; S ~2~ = Field&lang;T1&rang;

    Here is where it breaks down:
    While T ~1~ &lt;: S ~1~ holds, T ~2~ &lt;: S ~2~ ( T1 &lt;: Field&lang;T1&rang; ) does not.

    &rArr; Method 1 is not more specific than method 2.

    That method 2 is not more specific than method 1 either was already shown at stackoverflow.

    Since neither method is more specific than the other, none is maximally specific and therefore there is no most specific method, but two applicable methods. &rArr; ambiguity error

    With kind regards
    Ben
  • 6. Re: ant uses the JDK's compiler
    803691 Newbie
    Currently Being Moderated
    That's true, ant uses the JDK's compiler.
    Ant uses whichever compiler it is instructed to use.
    It is possible to use different compilers. This can be specified by either setting the global build.compiler property, 
    which will affect all <javac> tasks throughout the build, or by setting the compiler attribute, 
    specific to the current <javac> task. 
    
    Valid values for either the build.compiler property or the compiler attribute are:
    
        * classic (the standard compiler of JDK 1.1/1.2) – javac1.1 and javac1.2 can be used as aliases.
        * modern (the standard compiler of JDK 1.3/1.4/1.5) – javac1.3 and javac1.4 and javac1.5 can be used as aliases.
        * jikes (the Jikes compiler).
        * jvc (the Command-Line Compiler from Microsoft's SDK for Java / Visual J++) – microsoft can be used as an alias.
        * kjc (the kopi compiler).
        * gcj (the gcj compiler from gcc).
        * sj (Symantec java compiler) – symantec can be used as an alias.
        * extJavac (run either modern or classic in a JVM of its own).

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points