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