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