Lambda Specification, Part F: Overload Resolution

Navigation: Overview - Part A - Part B - Part C - Part D - Part E - Part F - Part G - Part H - Part J
Sections: 15.12.2 - 15.12.2.1 - 15.12.2.2 - 15.12.2.3 - 15.12.2.4 - 15.12.2.5 - 15.12.2.6
Version 0.6.1. Copyright © 2012 Oracle America, Inc. Legal Notice.

Summary

Method and constructor declarations can be overloaded, meaning multiple declarations with different parameter types can co-exist in a type. In order to interpret a method invocation or a class instance creation expression, the compiler performs "overload resolution," inferring the declaration intended by the user at a particular invocation site. This occurs in three steps: i) identifying potentially applicable methods, that is, methods of the appropriate shape; ii) performing type analysis to identify applicable methods for the given arguments; iii) among the applicable methods, choosing one that is most specific.

To accomodate lambda expressions, the definition of potential applicability is expanded to take into account both the arity of the candidate methods and the presence and "shape" of functional interface target types.

To check for applicability, the types of an invocation's arguments cannot, in general, be inputs to the analysis. This is because:

Instead, the input to the applicability check is a list of argument expressions, which can be checked for compatibility with potential target types, even if the ultimate types of the expressions are unknown.

The Java 7 most-specific analysis was defined as a pairwise comparison of method declarations. Here, we augment the analysis to take into account certain information from the invocation site as well. Specifically:

15.12.2 Compile-Time Step 2: Determine Method Signature [Modified]

Compare JLS 15.12.2

The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the argument expessions to locate methods that are both accessible and applicable, that is, declarations that can be correctly invoked on the given arguments.

There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is the one used at run time to perform the method dispatch.

A method is applicable if it is either applicable by one of strict invocation (15.12.2.2), applicable by loose invocation (15.12.2.3), or it is an applicable variable arity method invocation (15.12.2.4). [jls-15.12.2-120]

Although the method invocation may be a poly expression, only its argument expressions—not its target type—influence the selection of applicable methods.

...

Deciding whether a method is applicable will, in the case of generic methods (8.4.4), require an analysis of the type arguments. Type arguments may be passed explicitly or implicitly. If they are passed implicitly, bounds on the type arguments must be inferred (18) from the types of the argument expressions.

...

Discussion and motivation:
  1. To check for applicability, the types of an invocation's arguments cannot, in general, be inputs to the analysis. This is because:

    • The arguments to a method invocation may be poly expressions
    • Poly expressions cannot be typed in the absence of a target type
    • Overload resolution has to be completed before the arguments' target types will be known

    Instead, the input to the applicability check is a list of argument expressions, which can be checked for compatibility with potential target types, even if the ultimate types of the expressions are unknown.

  2. Overload resolution is independent of a target type for two reasons:

    • First, it makes the user model more accessible and less error-prone. The meaning of a method name (i.e., the declaration corresponding to the name) is too fundamental to the meaning of a program to depend on subtle contextual hints. (In contrast, other poly expressions may have different behavior depending on a target type; but the variation in behavior is always limited and essentially equivalent, while no such guarantees can be made about the behavior of an arbitrary set of methods that share a name and arity.)
    • Second, it allows other properties—such as whether or not the method is a poly expression (15.12) or how to categorize a conditional (15.25)—to depend on the meaning of the method name, even before a target type is known.

15.12.2.1 Identify Potentially Applicable Methods [Modified]

Compare JLS 15.12.2.1

...

A member method is potentially applicable to a method invocation if and only if all of the following are true: [jls-15.12.2.1-200]

...

An expression is potentially compatible with a target type according to the following rules: [jsr335-15.12.2.1-10]

If the search does not yield at least one method that is potentially applicable, then a compile-time error occurs. [jls-15.12.2.1-210]

Discussion and motivation:
  1. This definition of potential applicability expands the previous arity check to also take into account the presence and "shape" of functional interface target types.

    In some cases involving type argument inference, a lambda expression appearing as a method invocation argument cannot be properly typed until after overload resolution. These rules allow the form of the lambda expression to still be taken into account, discarding obviously incorrect target types that might otherwise cause ambiguity errors.

15.12.2.2 Phase 1: Identify Matching Arity Methods Applicable by Subtyping Strict Invocation [Modified]

Compare JLS 15.12.2.2

Let m be a potentially applicable method (15.12.2.1), let e1, ..., en be the actual argument expressions of the method invocation, and let Ai be the type of ei (1 ≤ i ≤ n) F1, ..., Fn be the types of the formal parameters of m. Then: [jls-15.12.2.2-100]

If no method applicable by strict invocation is found, the search for applicable methods continues with phase 2 (15.12.2.3). [jls-15.12.2.2-120]

Otherwise, the most specific method (15.12.2.5) is chosen among the methods that are applicable by strict invocation. [jls-15.12.2.2-130]

Discussion and motivation:
  1. The rules for handling generic method type argument inference, and associated terminology, have become too unwieldy to simply inline in the applicability rules. Instead, in this and the subsequent applicability sections, the inference problem has been factored out to 18.5.1.

15.12.2.3 Phase 2: Identify Matching Arity Methods Applicable by Invocation Conversion Loose Invocation [Modified]

Compare JLS 15.12.2.3

Let m be a potentially applicable method (15.12.2.1), let e1, ..., en be the actual argument expressions of the method invocation, and let Ai be the type of ei (1 ≤ i ≤ n) F1, ..., Fn be the types of the formal parameters of m. Then: [jls-15.12.2.3-100]

If no method applicable by loose invocation is found, the search for applicable methods continues with phase 3 (15.12.2.4). [jls-15.12.2.3-120]

Otherwise, the most specific method (15.12.2.5) is chosen among the methods that are applicable by loose invocation. [jls-15.12.2.3-130]

15.12.2.4 Phase 3: Identify Methods Applicable by Variable Arity Methods Invocation [Modified]

Compare JLS 15.12.2.4

Where a variable-arity method has formal parameter types F1, ..., Fn-1, Fn[], define the ith variable-arity parameter type of the method as follows: [jsr335-15.12.2.4-5]

Let m be a potentially applicable method (15.12.2.1) with variable arity, let e1, ..., ek be the actual argument expressions of the method invocation and let Ai be the type of ei (1 ≤ i ≤ k) T1, ..., Tk be first k variable-arity parameter types of m. Then: [jls-15.12.2.4-100]

If no method applicable by variable-arity method invocation is found, a compile-time error occurs. [jls-15.12.2.4-120]

Otherwise, the most specific method (15.12.2.5) is chosen among the methods applicable by variable-arity methods invocation. [jls-15.12.2.4-130]

Discussion and motivation:
  1. The previous "applicable variable arity method" terminology incorrectly suggested that, if a variable-arity method is applicable in any phase, it is applicable in and only in Phase 3. This overlooks the fact that variable arity methods can act as fixed-arity methods in Phases 1 and 2. What is relevant is the kinds of adaptations actually used to determine applicability, not the kinds of adaptations allowed by the method declaration.
  2. The ith variable arity parameter type is a notational shorthand that simplifies the problem of describing all possible ways in which arguments might be matched up with parameter types. This is especially useful in the next section.

15.12.2.5 Choosing the Most Specific Method [Modified]

Compare JLS 15.12.2.5

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error. In cases such as a lambda expression argument (15.27) or a variable-arity invocation (15.12.2.4), some flexibility is allowed to adapt one signature to the other.

If the methods are applicable by strict or loose invocation, then one fixed-arity member method named m m1 is more specific than another member method of the same name and arity, m2, for an invocation with argument expressions exp1, ..., expn, if one of the following is true: [jls-15.12.2.5-200]

If the methods are applicable by variable arity invocation, then one variable arity member method named m m1 is more specific than another variable arity member method of the same name m2, for an invocation with argument expressions exp1, ..., expk if one of the following is true: [jls-15.12.2.5-300]

The above conditions are the only circumstances under which one method may be more specific than another. [jls-15.12.2.5-400]

A type T is more specific than a type S for an expression exp according to the following rules: [jsr335-15.12.2.5-10]

A method m1 is strictly more specific than another method m2 if and only if m1 is more specific than m2 and m2 is not more specific than m1. [jls-15.12.2.5-500]

...

Discussion and motivation:
  1. The Java 7 most-specific analysis was defined as a pairwise comparison of method declarations. Here, we augment the analysis to take into account certain information from the invocation site as well. Specifically:

    • If an argument is a lambda expression that cannot yet be typed due to unfinished inference (thus, the method is considered provisionally applicable), we conservatively make no attempt to compare the two methods; typically, an ambiguity error would be the result.
    • If an argument is a lambda expression, method reference, or constructor reference, and if both target types are functional interfaces with matching descriptor parameter types, then the descriptor return types may be compared. For example, a descriptor returning String is considered better than a descriptor returning Object or void.
    • If an argument produces a primitive value, a primitive type is considered better than a reference type; the opposite is true for arguments producing reference values.
  2. While these enhancements are designed with lambda expressions and method references in mind, there are a few side effects that impact code that makes no use of these features:

    • Methods that require boxing or unboxing but that don't require as much of it as an alternative may be preferred.
    • The final parameter of variable-arity methods, if the invocation expression provides zero arguments for that parameter, is no longer used for comparison.

    If these changes raise sufficiently serious backwards-compatibility concerns, adjustments can be made to minimize them.

  3. As above, the inference problem associated with the most-specific analysis has been factored out into its own section, 18.5.4.

15.12.2.6 Method Invocation Type Result and Throws Types [Modified]

Compare JLS 15.12.2.6

The invocation type of a most-specific accessible and applicable method is a method type (8.2) expressing the target types of the invocation arguments, the result type of the invocation, and the exception types of the invocation. It is determined as follows: [jsr335-15.12.2.6-10]

The type of the method invocation expression is obtained by applying capture conversion (5.1.10) to the return type of the invocation type of the chosen method. [jls-15.12.2.6-100-C.1]

The exception types that a method invocation expression can throw are specified in 11.2.1. [jls-15.12.2.6-300]

Discussion and motivation:
  1. We introduce invocation type here to group together the return type, exception types, and parameter types. Because poly expressions can appear as method arguments, we need to be more explicit than before about what the target type of a method argument is. This new abstraction also clarifies the interaction with inference (18.5.2), and simplifies the text for this section, which was needlessly concerned with the details of substitution and erasure on lists of types.