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
<maurizio.cimadam...@oracle.com
<mailto:maurizio.cimadam...@oracle.com>> 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 <head...@headius.com>
<mailto:head...@headius.com>
Reply-To: jvm-languages@googlegroups.com
<mailto:jvm-languages@googlegroups.com>
To: JVM Languages <jvm-languages@googlegroups.com>
<mailto:jvm-languages@googlegroups.com>
CC: Mark Reinhold <mark.reinh...@oracle.com>
<mailto:mark.reinh...@oracle.com>
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 tojvm-langua...@googlegroups.com
<mailto:jvm-languages@googlegroups.com>.
To unsubscribe from this group, send email
tojvm-languages+unsubscr...@googlegroups.com
<mailto:jvm-languages+unsubscr...@googlegroups.com>.
For more options, visit this group
athttp://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 jvm-languages@googlegroups.com
<mailto:jvm-languages@googlegroups.com>.
To unsubscribe from this group, send email to
jvm-languages+unsubscr...@googlegroups.com
<mailto:jvm-languages+unsubscr...@googlegroups.com>.
For more options, visit this group at
http://groups.google.com/group/jvm-languages?hl=en.