Mapper factory, overloaded handlers and eraser - no warning from the compiler

Brian Goetz brian.goetz at oracle.com
Sat Dec 15 17:09:59 PST 2012


First let's take method references out of the equation.  Your code 
basically says:

private static final Function<Object, String> STRING
     = (Object o) -> String.valueOf(o);

Which is fine, but: you've *already selected an overload* of valueOf.

>          char[] data = new char[] {'h', 'e', 'l', 'l', 'o'};
>          Function<char[], String> vo = Functions.string();
>          System.out.println( vo.apply(data));

Now, what you're doing is the exact same thing as:

   char[] c = ...
   System.out.println(String.valueOf((Object) c));

Which will also print out [C at blarf.

> But:
>          Function<char[], String> vo = String::valueOf;
>          System.out.println( vo.apply(data));
>
> Produces 'hello'

Right.  Because you're calling a different method, one that happens to 
have a similar name.

Method references are not references to a method name; they are 
references to a *specific method*, which may involve overload selection 
at the time the method ref is constructed.

Bottom line is: the string() code is simply broken.

> ----------------------
> More important:
> ----------------------
>
> static <T> Function<T, String> string() {
>          return String::valueOf;
>   }
>
> The compiler DOES NOT warn you that due to the eraser(?)  valueOf(Object)
> is always called !!

So, you somehow have come to a mental model that says a method reference 
somehow refers to a family of methods with the same name, and that 
overload selection is done at invocation time rather than capture time. 
  I could see how one could think that, but that's simply not how method 
references work.

The compiler *will* warn you if it cannot fine a unique valueOf method 
that is compatible with the signature T -> String.

I don't think any sort of warning is warranted or appropriate here. 
Think about it this way.  A method reference is really just shorthand 
for a lambda:

   Function<T, String> lambda = (T t) -> String.valueOf(t);

Which under the hood just becomes a method:

   <T> String lambda$1(T t) {
     return String.valueOf(t);
   }

Now, when viewed in this form, do you really think a warning is in order 
that the compiler is selecting a specific overload based on the static 
bound of T, rather than its dynamic type?



More information about the lambda-dev mailing list