Invalid method reference with generics
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Sat Jun 29 05:00:22 PDT 2013
This code:
interface ApplicationListener<E extends ApplicationEvent> {
void onApplicationEvent(E e);
}
class ApplicationEvent { }
class Event1 extends ApplicationEvent { }
class Test {
public static <E extends ApplicationEvent> void
register(ApplicationListener<E> listener) { }
public void onEvent1(Event1 event1) { }
public void initialize() {
register(this::onEvent1);
}
}
Works fine against the latest lambda compiler (after yesterday push).
Thanks
Maurizio
On 28/06/13 18:27, Nick Williams wrote:
> On Jun 27, 2013, at 2:35 AM, Maurizio Cimadamore wrote:
>
>> On 26/06/13 18:43, Nick Williams wrote:
>>> However, I CAN do this (it compiles and runs just fine):
>>>
>>> register(new ApplicationListener<Event1>() {
>>> public void onApplicationEvent(Event1 event) { }
>>> });
>>>
>>> So, by extension, I SHOULD be able to do this, but can't:
>>>
>>> void onApplicationEvent(Event1 event) { }
>>> register(this::onApplicationEvent);
>>>
>>> We have inconsistent behavior here. In your example, both the method reference and the anonymous inner class are illegal. In my use case, the compiler allows the anonymous inner class but prohibits the method reference. That inconsistency is a real problem. There is_no_ semantic difference between what I'm doing with the anonymous inner class and what I'm doing with the method reference. Zero. The method signatures are identical (I event named them the same here to drive home the point), but one works and the other doesn't.
>>>
>>> Nick
>>>
>> Yes and no - the inner class you are creating is a subtype of:
>>
>> ApplicationListener<Event1>
>>
>> while the type inferred by the compler as a target is:
>>
>> ApplicationListener<ApplicationEvent> (wildcard removed as per spec)
>>
>> This is why you get the 'weird' behavior. To express what you mean, you need to do the following:
>>
>> public static <Z extends ApplicationEvent> void register(ApplicationListener<Z> listener) { }
>>
>> The compiler will infer Z == Event1 and all will be fine. Well, it will fail with an inference error for now, but we have plans to fix that in the future.
>>
>> Maurizio
> So, just so that I know I understand you correctly, you're saying that if I want to do it like this (which is something I tried previously and it did not work):
>
> public static <E extends ApplicationEvent> void register(ApplicationListener<E> listener) { }
> public void onEvent1(Event1 event1) { }
> public void initialize() {
> register(this::onEvent1);
> }
>
> I SHOULD be able to do this and I WILL be able to do this at some point before Java 8 is complete, but right now it's just not working.
>
> Do I understand that correctly?
>
> Nick
>
More information about the lambda-dev
mailing list