On Jun 9, 2011, at 7:53 AM, Rémi Forax wrote: > On 06/09/2011 04:46 PM, Kirk wrote: >> >> +1 Charlie, it's edgy-casey >> >> At this point, I'd ask the question, do you change the behavior or change >> the spec. > > If you change the spec Attila will kill you :) > His MOP implements the spec not the javac behavior.
Since I implemented it by reading the spec, I would've been surprised if it were otherwise :-) > Changing the spec means changing all implementations based on the spec, > the Java method resolution algorithm is not used only in Java compilers. I'm actually in two mind with regard to Dynalink here. It is not strictly bound by the JLS overload resolution rules anyway, although most of the time - i.e. in absence of a non-Java language runtime that brings custom type conversion rules with it - you'll see it adhering to it strictly[1]. If it is otherwise JLS compliant, but additionally can unambiguously choose a method in some situations when javac can't, that doesn't seem to be a bad proposition to me. The question however is whether these solutions we perceive as intuitive can indeed be formally valid under some set of consistent rules, without running into a contradiction. Attila. -- [1] (Details extracted into a footnote for curious) Contrary to javac, which has to make a method choice at compile time, Dynalink has the luxury to postpone it to actual invocation time. It does however try to do most of the selection work at link time. If it determines that there's an ambiguity at link time based on JLS, _and_ that no additional conversions can ever resolve it at invocation time, it'll throw a link-time ambiguity exception, see <https://github.com/szegedi/dynalink/blob/master/src/org/dynalang/dynalink/beans/OverloadedDynamicMethod.java#L107> Sometimes, however, it can allow some ambiguity to exist through link time, to allow for extra type conversions allowed by any plugged-in non-Java language (as, remember, Dynalink ain't just a convenient POJO linker, it's a generic cross-language linker). In that case, it'll link a multi-dispatching MethodHandle that'll have to make a choice based on actual argument types on every invocation, and can still run into ambiguity. One of morals of this story is that if you can have more specific call sites signatures, that's additional information that it can use to get more efficient overloaded method invocation, as in best case, it can select one method unambiguously at link time based on call site signature and link to it more directly. > >> >> Regards, >> Kirk > > cheers, > Rémi > >> >> On Jun 9, 2011, at 4:36 PM, Charles Oliver Nutter 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 >>> <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> >>>> Reply-To: jvm-languages@googlegroups.com >>>> To: JVM Languages <jvm-languages@googlegroups.com> >>>> CC: Mark Reinhold <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 to jvm-languages@googlegroups.com. To unsubscribe from this group, send email to jvm-languages+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/jvm-languages?hl=en.