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