Overload resolution simplification

Ali Ebrahimi ali.ebrahimi1781 at gmail.com
Wed Aug 21 02:10:47 PDT 2013


Hi,


On Wed, Aug 21, 2013 at 10:39 AM, Howard Lovatt <howard.lovatt at gmail.com>wrote:

> Possible type inference algorithm using type checking of Lambdas (with
> examples below to show that it works well):
>
> I. Start with the outer-most method call, declaration, or assignment and
> work inwards and then left to right.
> II. For methods select a set of candidate methods based on known types,
> method name, and number of arguments and note the lambda candidate types.
> For declared types note the type. For assignments note the destination
> type.
> III. For each candidate type signature check the lambda including the
> return type against the candidate types and if the type check fails
> eliminate that candidate. This step whilst primarily eliminating candidates
> may add candidates because there may be multiple candidates for a given
> method/declaration/assignment based on multiple super-types of signatures.
> This stage, III., and the next, IV., may be usefully combined to make the
> process quicker. The process may also be carried out in parallel.
> IV. Choose from the remaining candidates the candidate method that is the
> best fit (least number of conversions - sum of conversion required for
> argument types and return type).
> V. If there are methods that are equally good fit issue an error giving the
> possible methods.
>
> The above algorithm is simple and doesn't involve complicated speculation
> about types, i.e. it works in a forward direction form signatures through
> lambda argument types to the lambda's return type. As shown below through a
> series of examples the algorithm works well and doesn't produce any
> surprises.
>
> In all cases below the unkown type of a single lambda argument, a, is A and
> for multiple arguments, a1, a2, ..., the types are A1, A2, ..., similarly
> an unknown return type is R and multiple are R1, R2, ...
>
> Maurizio's Examples (Lambda Experts Group email)
> ================================================
> class Mappers<T> {
>   IntSream map(IntFunction<T> if) {...}
>   <Z> Stream<Z> map(Function<T, Z> f) {...}
>   <U> IntStream map(Stream<U> s, IntFunction<U> if) {...}
>   <U, V> Stream<V> map(Stream<U> s, Function<U, V> f) {...}
> }
>
> Mappers<String> ms = ...;
> ms.map(a->1);                  // Ex. 1
> ms.map(a->'A');                // Ex. 2
> Stream<String> ss = ...;
> Mappers.map(ss, a->1);   // Ex. 3
> Mappers.map(ss, a->'A'); // Ex. 4
>
> Ex. 1: ms.map(a->1)
> -------------------
> 1. From the scope, function name, and number of arguments there are two
> possible functions map(IntFunction<String>) and map(Function<String, Z) and
> in both cases A = String and therefore A must be String.
> 2. Therefore (String a)->1 is either i. an IntFunction<String> (R = int) or
> ii. a Function<String, Z> (R = Object).
> 3. Type check option i., R = int, and this is OK since 1 is an int.
> 4. Type check option ii., R = Object, and this is OK since 1 could be
> autoboxed to an Integer.
> 5. Choose option i. because it doesn't require boxing.
>
> Ex. 2: ms.map(a->'A')
> ---------------------
> 1. From the scope, function name, and number of arguments there are two
> possible functions map(IntFunction<String>) and map(Function<String, Z) and
> in both cases A = String and therefore A must be String.
> 2. Therefore (String a)->'A' is either i. an IntFunction<String> (R = int)
> or ii. a Function<String, Z> (R = Object).
> 3. Type check option i., R = int, and this fails since 'A' is not
> automatically convertible to int.
>
This is not current. java can widen chars into ints from early days.


4. Type check option ii., R = Object, and that is OK since 'A' could be
> autoboxed to a Character.
> 5. Therefore ii.
>
Widening wins over Boxing and Unboxing. So answer would be i.



> Ex. 3: Mappers.map(ss, a->1)
> ----------------------------
> 1. From the scope, function name, and number of arguments there are two
> possible functions map(Stream<String>, IntFunction<String>) and
> map(Stream<String>, Function<String, Z) and in both cases U = A = String
> and therefore both U and A must be String.
> 2. Therefore (String a)->1 is either i. an IntFunction<String> (R = int) or
> ii. a Function<String, Z> (R = Object).
> 3. Type check option i, R = int, and this is OK since 1 is an int.
> 4. Type check option ii, R = Object, and this is OK since 1 could be
> autoboxed to an Integer.
> 5. Choose option i. because it doesn't require boxing.
>
> Ex. 4: Mappers.map(ss, a->'A')
> ------------------------------
> 1. From the scope, function name, and number of arguments there are two
> possible functions map(Stream<String>, IntFunction<String>) and
> map(Stream<String>, Function<String, Z) and in both cases U = A = String
> and therefore U and A must be String.
> 2. Therefore (String a)->'A' is either i. an IntFunction<String> (R = int)
> or ii. a Function<String, Z> (R = Object).
> 3. Type check option i., R = int, and this fails since 'A' is not
> automatically convertible to int.
>
So this is also not currect. See above.

4. Type check option ii., R = Object, and that is OK since 'A' could be
> autoboxed to a Character.
> 5. Therefore ii.
>
Answer: i ->  See above.

May be you can read my proposal.
http://mail.openjdk.java.net/pipermail/lambda-spec-observers/2013-August/000489.html


Ali Ebrahimi


More information about the lambda-spec-observers mailing list