Java most specific method subtyping rules

125 views Asked by At

In §15.12.2.5 of the Java Language Specification they describe how Java chooses the most specific method to call from a list of both accessible and applicable methods.

There is one specific remark that I don't understand, namely:

(1) A type S is more specific than a type T for any expression if S <: T

The part that really bothers me is "any expression".

To give an example why, I'll be quoting the previous paragraph that says when given two methods m1 and m2 we can say m1 is more specific than m2 for an invocation with argument expressions e1, ..., ek if:

m2 is not generic, and m1 and m2 are applicable by strict or loose invocation, and where m1 has formal parameter types S1, ..., Sn and m2 has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ n, n = k).

So if the type Si (m1) is more specific than Ti (m2) with argument expression ei for all i, then m1 is more specific than m2

Now consider this:

int a(Number a) { return 1; } // m1
int a(Double a) { return 2; } // m2

Since Double <: Number it follows that for any expression Double is more specific than Number (from quote 1).

We have:

m1 : S1 => Number

m2 : T1 => Double

But then if our argument argument expression e1 is of type Number m2 is the most specific method since Double is most specific for any expression (quote 1).

However, if we pass in a Number to a() the result is 1 ie. the method taking a Double is not chosen. But quote 1 says that if Double is a subtype of Number for any expression Double will be more specific, so how come it chooses a(Number)?

What am I missing here?

Note: I know Number is not assignable to Double and it wouldn't make sense for the compiler to choose the other one, I'm just trying to see what I'm mis-interpreting from the first quote.

1

There are 1 answers

0
ᴘᴀɴᴀʏɪᴏᴛɪs On

It turns out my misunderstanding was not as part of the quote but as to what an applicable function would be under loose or strict invocation.

More specifically strict/loose invocation contexts allow a set of conversions

  • An identity conversion ie. Number to Number
  • A widening primitive conversion ie. byte to short,int,long,float or double
  • A widening reference conversion ie. Double to Number
  • A boxing conversion ie. int to Integer optionally followed by a widening reference conversion
  • An unboxing conversion ie. Integer to int optionally followed by a widening primitive conversion

In my example, I overlooked the fact that a widening reference conversion cannot be applied to Number because Number is not a subtype of Double hence int a(Double a) is not considered an applicable method.