I've been using precisely the pattern that Charlie lays out in some of my
code, as well, so I'm going to have to code around it now. I didn't realize
that it was technically ambiguous — it's really surprising to my intuition,
which (I'm now realizing as I think about it) tries to match arguments left
to right, and only drops to varargs if it can't find a match. That intuition
is obviously wrong compared to the spec, but does that mean we have a bug in
the spec? What's the justification for this behavior?

For the record, both Scala and Groovy resolve methods more in line with
intuition:
Groovy > https://gist.github.com/1016878
Scala > https://gist.github.com/1016880

~~ Robert.

On Thu, Jun 9, 2011 at 10:36 AM, Charles Oliver Nutter
<[email protected]>wrote:

> I accept this analysis as written. I do however have a few
> questions/comments.
>
> * This seems like it only affects cases where you have primitives butting
> up against a varargs Object..., correct? Only in those cases do you have a
> method invocation conversion from a type that does not subclass Object.
> Edge-casey.
>
> * It is unexpected, albeit correct according to specification. A few
> reasons:
>
> ** The int => Object conversion is via Integer, which *is* a subtype
> relationship. I know the spec does not provide for reevaluating specificity
> after a method invocation conversion...but perhaps it should.
>
> ** int *is* more specific than Object from a programmer/development
> perspective. Another way of looking at specificity would be "fewer
> combinations of argument types apply". That's clearly the case here.
>
> I suspect I won't be the only one to run into this new behavior. As it
> stands, the methods in question in JRuby no longer need the varargs forms,
> so I'm removing them.
>
> - Charlie
>
> On Thu, Jun 9, 2011 at 9:24 AM, Maurizio Cimadamore <
> [email protected]> wrote:
>
>>  Remi, your analysis is correct.
>>
>> Consider the method call:
>>
>> method("str", 1);
>>
>> Now, you have two potentially applicable methods, namely
>>
>> - method(String str, int num, Object... data)
>> - method(String str, Object... data)
>>
>> Since both are varargs method, both methods can only be applicable by
>> variable arity method conversion (see JLS 15.12.2.4). Both methods are
>> applicable (note that the second method is applicable since there exist a
>> method invocation conversion to go from int to Object).
>>
>> Since both are applicable we have now to choose the most specific (see
>> 15.12.2.5) - the rules says that:
>>
>> "In addition, one variable arity member method named m is more specific
>> than another variable arity member method of the same name if either:
>>
>> *) One member method has n parameters and the other has k parameters,
>> where n >= k. The types of the parameters of the first member method are T1,
>> . . . , Tn-1 , Tn[], the types of the parameters of the other method are U1,
>> . . . , Uk-1, Uk[]. [...] otherwise let Si = Ui, 1 < i <=k. Then:
>>
>>    - for all j from 1 to k-1, Tj <: Sj, and,
>>    - for all j from k to n, Tj <: Sk, and,
>>
>> *) One member method has k parameters and the other has n parameters,
>> where n>=k. The types of the parameters of the first method are U1, . . . ,
>> Uk-1, Uk[], the types of the parameters of the other method are T1, . . .,
>> Tn-1, Tn[]. [...] otherwise let Si = Ti, 1 <i <= n. Then:
>>
>>    - for all j from 1 to k-1 , Uj <: Sj, and,
>>    - for all j from k to n , Uk <: Sj, and,"
>>
>> *** Part 1
>>
>> So, is M1 = method(String str, int num, Object... data) more specific than
>> M2 = method(String str, Object... data) ? Since arity of M1 is bigger than
>> arity of M2, the first bullet apply. More specifically, n is 3, k is 2, T =
>> { String, int, Object }, while S = U = { String, Object }. We have to prove
>> that:
>>
>>    - for all j from 1 to 1 (as k is 2), Tj <: Sj, and,
>>    - for all j from 2 to 3, Tj <: S2, and,
>>
>> Which means:
>>
>> j = 1 --> T1 <: S1 ? Yes, because String <: String
>> j = 1 --> T2 <: S2 ? No, because int is not a subtype of Object
>>
>> Which means method(String str, int num, Object... data) is not more
>> specific than method(String str, Object... data). Let's try the other way
>> around.
>>
>> *** Part 2
>>
>> So, is M1 = method(String str, Object... data) more specific than M2 =
>> method(String str, int i, Object... data) ? Since arity of M1 is smaller
>> than arity of M2, the second bullet apply. More specifically, n is 2, k is
>> 3, U = { String, Object }, S = T = { String, int, Object }. We have to prove
>> that:
>>
>>    - for all j from 1 to 2 (as k is 3), Uj <: Sj, and,
>>    - for all j from 3 to 3, Uj <: S3, and,
>>
>> Which means:
>>
>> j = 1 --> U1 <: S1 ? Yes, because String <: String
>> j = 1 --> U2 <: S2 ? No, because int is not a subtype of Object
>>
>> Which means method(String str, Object... data) is not more specific than
>> method(String str, int i, Object... data). The conclusion is that neither
>> method is more specific than the other, so the compile-time error is
>> legitimate.
>>
>> Maurizio
>>
>>
>>
>>
>> On 09/06/11 14:51, Rémi Forax wrote:
>>
>> add compiler dev-list to the loop.
>>
>> My analysis is that this is a fix for a previously existing bug,
>> so the behavior of javac is now correct.
>>
>> With method("str", 1), no method are applicable without considering boxing
>> and varargs,
>> so we ends up with phase 3. Here, both boxing and varargs are enabled so
>> the two method are applicable and not one is most specific.
>> So the call is ambiguous.
>>
>> Rémi
>>
>> -------- Original Message --------  Subject: [jvm-l] Newly introduced
>> OpenJDK javac bug?  Date: Thu, 9 Jun 2011 08:26:04 -0500  From: Charles
>> Oliver Nutter <[email protected]> <[email protected]>  Reply-To:
>> [email protected]  To: JVM Languages
>> <[email protected]> <[email protected]>  CC: Mark
>> Reinhold <[email protected]> <[email protected]>
>>
>> Recent OpenJDK 7 builds seem to have introduced a bug into javac.
>> Correct me if I'm wrong.
>> https://gist.github.com/1016436
>>
>> public class Foo {
>>     public static void main(String[] args) {
>>      method("str");
>>      method("str", 1);
>>      method("str", 1, "data");
>>     }
>>
>>     public static void method(String str, int num, Object... data) {
>>      // do nothing
>>     }
>>
>>     public static void method(String str, Object... data) {
>>      // do nothing
>>     }
>> }
>>
>> It seems that the order in which it attempts to apply varargs and
>> boxing has changed. On OpenJDK/Hotspot 1.6.x and OpenJDK 7 builds
>> prior to 143, this compiles fine and calls the first signature for all
>> calls. My interpretation of the Java specification is that this is
>> correct behavior; the more exact signature that requires no boxing is
>> chosen rather than the second signature which does require boxing.
>>
>> However on later builds, we get the following errors for this case:
>>
>> Foo.java:4: error: reference to method is ambiguous, both method
>> method(String,int,Object...) in Foo and method
>> method(String,Object...) in Foo match
>>      method("str", 1);
>>      ^
>> Foo.java:5: error: reference to method is ambiguous, both method
>> method(String,int,Object...) in Foo and method
>> method(String,Object...) in Foo match
>>      method("str", 1, "data");
>>
>> Both invocations fall through to phase 3 of method selection, variable
>> arity. But in this case, I believe the first signature (with int)
>> should resolve as "more specific" than the second, and should be
>> chosen for both invocations. I admit it's a grey area, however, and I
>> can't find a specific clause in the Java spec to back me up.
>>
>> I'm not sure who to talk to about this, or whether I'm right in
>> thinking this is a new bug in javac. Thoughts?
>>
>> - Charlie
>>
>> --
>> You received this message because you are subscribed to the Google Groups 
>> "JVM Languages" group.
>> To post to this group, send email to [email protected].
>> To unsubscribe from this group, send email to 
>> [email protected].
>> For more options, visit this group at 
>> http://groups.google.com/group/jvm-languages?hl=en.
>>
>>
>>
>>
>  --
> You received this message because you are subscribed to the Google Groups
> "JVM Languages" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/jvm-languages?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups "JVM 
Languages" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/jvm-languages?hl=en.

Reply via email to