Problem with method references

Rémi Forax forax at univ-mlv.fr
Tue Jan 4 10:37:25 PST 2011


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