[jvm-l] Newly introduced OpenJDK javac bug?
Charles Oliver Nutter
headius at headius.com
Thu Jun 9 12:26:48 PDT 2011
Yay cross-posting. I include the content of my post to jvm-l here for
compiler-dev to muse upon:
On Thu, Jun 9, 2011 at 1:11 PM, Attila Szegedi <szegedia at gmail.com> wrote:
> 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.
In answer to you and Neal, it seems there's a simple way to improve
the spec to provide the "intuitive" result (or at least the result
most people here seem to find intuitive: treat primitives as more
specific than Object (and potentially over boxed numeric types as
well). My (mis)interpretation of the Java spec for Mirah's compiler
works this way currently; primitives are given priority over reference
types unconditionally, since the alternative *requires* a boxing
conversion. If you have to walk through a conversion to get there,
you're walking into a less-specific signature.
Walking back through phase 3 and specificity (and I apologize for the
informality of this..I'm not a spec writer):
void foo(String, int, Object...)
void foo(String, Object...)
foo("bar", 1) or foo("bar", 1, "baz")
* phase three is selected because only varargs can apply
* the second signature is only valid for the given arguments with a
method invocation conversion of int => Integer
* Integer is a subclass of Object, so we arrive at the ambiguity from before
* ...BUT...primitive is always more specific than reference, and so
the int method is chosen
I know many folks hate the special treatment of primitives in Java,
but this sort of exception is nothing new. Yes, primitives and
reference types live in different worlds and do not share a hierarchy.
I would argue that their disjointedness explicitly makes the strict
subtype specificity check invalid; subtyping has no meaning to
primitives, so you're measuring specificity of an int parameter with
an invalid metric. It would be like measuring the specificity of
Integer versus Long based on their bit sizes and bit-level widening
conversions. Since that doesn't make sense, neither does forcing
subtype-driven specificity constraints on primitive types.
On Thu, Jun 9, 2011 at 2:07 PM, Dan Smith <daniel.smith at oracle.com> wrote:
> On Jun 9, 2011, at 10:17 AM, Ulf Zibis wrote:
>> Am 09.06.2011 17:26, schrieb Rémi Forax:
>>> On 06/09/2011 04:52 PM, Robert Fischer wrote:
>>>> 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
>>> Yes, because either in Scala or in Groovy int is a subtype of Object.
>>> There is no point to make a difference between int and Integer in a dynamic language.
>> I think, C++ would be the more appropriate language to compare here. Does anybody here know, how C++ would solve this problem?
>> what's about:
>> method("str", new Integer(1));
>> Because Integer can be unboxed to int, there should be an ambiguity too according given rules, which feels more weird to me.
>> The only cases, which are not ambiguous here, seem to be:
>> method("str", true);
>> method("str", 1.0);
>> method("str", 1L);
>> So allowing the coexistence of those 2 signatures would seem weird too.
>> IMO, not (un)boxed matches should be valued as "more specific"!
> "more specific" is a relation among method signatures, so it would not be easy to adjust its definition in this way.
> The process has two steps: 1) find applicable methods, using the argument types; 2) choose the most specific method, ignoring the argument types. Seems like the right way to express what you're after within the current framework is to have a fourth applicability phase:
> 1) Applicable by subtyping
> 2) Applicable by method invocation
> *3) Applicable by subtyping with varargs*
> 4) Applicable by method invocation with varargs
> This would also address the original concern, although I think people might debate whether it's the correct behavior for:
> void method(String s, int n, Object... os);
> void method(String s, Object... os);
> method("abc", new Integer(3));
More information about the compiler-dev