Problem with method references

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Jan 4 08:02:32 PST 2011


On 04/01/11 14:46, Tomasz Kowalczewski wrote:
> Thanks for your explanation Maurizio, this is very interesting.
>
> The Extractor interface is included in my original email (however, you
> were right about how it looks). I understand that this#getArgCount
> will be translated to a SAM with method that forwards the call to
> 'this' (so no explicit argument of type LambdaInConstructorExample is
> required). But in the constructor I am not using 'this#getArgCount', I
> am using LambdaInConstructorExample#getArgCount. That why, at least
> for me, this situation is very unintuitive.
> When working from a non-static context, is there a possibility to SAM
> convert getArgCount to the Extractor interface?
I understand your point - however, I think that, if we changed the 
semantics of this#getArgCount as you describe, another unintuitive 
example would pop-up:

interface Extractor {
int getX();
}

class Test {
    int getArgCount() { ... }

    Exctractor e = this#getArgCount;
}

Unless we let the compiler perform the automatic expansion only if the 
parenthesis are omitted from the method references - which would lead to 
this#getArgCount() being semantically different w.r.t. this#getArgCount

Maurizio

> On Tue, Jan 4, 2011 at 3:19 PM, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com>  wrote:
>> On 03/01/11 10:10, Tomasz Kowalczewski wrote:
>>> package org.tkowalcz.lambda.extractor;
>>>
>>> public class LambdaInConstructorExample {
>>>
>>>    public static void main( final String[] args ) {
>>>      // Compiles fine
>>>      Extractor x = LambdaInConstructorExample#getArgCount;
>>>    }
>>>
>>>    public LambdaInConstructorExample() {
>>>      // Error
>>>      Extractor x = LambdaInConstructorExample#getArgCount;
>>>    }
>>>
>>>    public int getArgCount() {
>>>      return 1;
>>>    }
>>> }
>> There is no bug here. The first method reference compiles because a
>> non-static method is being referenced from a static context - in such cases,
>> the following expansion is automagically applied by the compiler:
>>
>> If f is an instance method of Z whose signature is A,B->C, then #obj.f is of
>> type A,B->C and #Z.f is of type Z,A,B->C.
>>
>> Which means that, in the first case, the compiler is looking for a signature
>> of the kind (LambdaInConstructorExample)->int.
>>
>> Since the second method reference occurs in a non-static context, no
>> automatic expansion is applied, which means the compiler will look for a
>> signature of the kind ()->int.
>>
>> Now, depending on how you declare the target method in the SAM type
>> Extractor, you will not be able to get both method references to compile, as
>> the compiler will be looking for different signatures. I guess that, looking
>> at your output, your SAM type declaration looks like the following:
>>
>> interface Extractor {
>> int getX(LambdaInConstructorExample arg);
>> }
>>
>> Maurizio
>>
>>



More information about the lambda-dev mailing list