Problem with method references

Brian Goetz brian.goetz at oracle.com
Tue Jan 4 17:51:23 PST 2011


Very nice!


On Jan 4, 2011, at 5:25 PM, Rémi Forax wrote:

> 
> JSR 292 goodness: Lambda to SAM type conversion using invokedynamic:
> http://weblogs.java.net/blog/forax/archive/2011/01/04/jsr-292-goodness-lambda-sam-conversion-u
> 
> enjoy,
> Rémi
> 
> On 01/04/2011 07:37 PM, Rémi Forax wrote:
>> Also latest jdk7 build (b123) comes with a new JSR 292 feature,
>> bootstrap constant arguments.
>> With that, reference binding and asSam conversion can be done in one
>> invokedynamic call.
>> 
>>    Extractor e = this#getArgCount();
>> can be translated to
>>    invokedynamic [#asSamBsm, AClass#getArgCount(), Extractor.class] (this)
>> 
>> and
>>    Extractor e = AClass#getArgCount();
>> to
>>    invokedynamic [#asSamBsm, AClass#getArgCount(), Extractor.class] ()
>> 
>> The method reference and the resulting SAM type are arguments that
>> are sent once at linking time.
>> The last call is interresting because it can return a constant from the
>> VM point of view
>> so the extractor will be allocated once.
>> 
>> I will try to sketch a prototype this evening :)
>> 
>> Rémi
>> 
>> On 01/04/2011 07:08 PM, Brian Goetz wrote:
>>> this#getArgCount should result in a bound instance method reference, with 'this' as the receiver.  Most likely the shorthand #getArgCount will correspond to this#getArgCount.
>>> 
>>> On Jan 4, 2011, at 10:01 AM, Tomasz Kowalczewski wrote:
>>> 
>>>> Maurizio,
>>>> 
>>>> I didn't suggest any semantic changes, just described what is my gut
>>>> feeling about what 'this#getArgCount' should mean. Nevertheless thanks
>>>> for looking into it. I appreciate hard work of all you guys working on
>>>> the lambda implementation.
>>>> 
>>>> On Tue, Jan 4, 2011 at 5:02 PM, Maurizio Cimadamore
>>>> <maurizio.cimadamore at oracle.com>   wrote:
>>>>> 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
>>>>>>> 
>>>>>>> 
>>>> -- 
>>>> Tomasz Kowalczewski
>>>> 
>> 
> 
> 



More information about the lambda-dev mailing list