Problem with method references
Rémi Forax
forax at univ-mlv.fr
Tue Jan 4 17:25:49 PST 2011
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