SAM identity or at least equals/hashCode

Brian Goetz brian.goetz at oracle.com
Tue Jun 21 07:27:58 PDT 2011


The compiler desugars the lambda to a method that has two parameters. 
SAM converting that method to one that has no parameters can be 
accomplished in a number of ways -- generating bytecode for the method 
that does the currying, MethodHandle.insertArguments, etc.

On 6/21/2011 10:20 AM, Ali Ebrahimi wrote:
> Hi,
> how do you handle it if you have more than one captured (bound) state?
>
> public Adder adderGenerator(int x, int y) { return #{ ->  x + y} };
>
> Ali Ebrahimi
> On Tue, Jun 21, 2011 at 5:36 PM, Peter Levart<peter.levart at marand.si>wrote:
>
>> On 06/21/11, Brian Goetz wrote:
>>>>> If you want to refer to the object instance that is the result of
>>>>> SAM conversion, call that the SAM instance or the SAM object --
>>>>> which is an object.  (You can't assume much about its identity --
>>>>> the compiler will likely make sure that all instances of
>>>>> "stateless" lambdas are really the same object, a la the
>>>>> "Flyweight" pattern.)
>>>>
>>>> Only stateless? Why?
>>>
>>> Lambdas can capture final local variables.  Consider:
>>>
>>> public IntFactory constGenerator(int x) { return #{ ->  x } };
>>>
>>
>> This is exactly the use case I'm talking about. One would want that
>>
>> constGenerator(12).equals(constGenerator(12)) would evaluate to true and
>> constGenerator(12).equals(constGenerator(13)) would evaluate to false
>>
>> event though the instances of two SAM objects returned from two invocations
>> of method:
>>
>> constGenerator(12)
>>
>> are not the same instance, they could be equal.
>>
>>> Clients will call the resulting IntFactory with
>>>     foo.make()
>>> and expect an int to come back.  The SAM-converted lambda is an object,
>>> it has to have a nilary make() method, that method has captured state x,
>>> so where do we store the captured state?
>>>
>>
>> I belive you (could) generate a static method with one formal parameter:
>>
>> private static int lambda$1(Integer p1) { return p1; }
>>
>> ...then obtain a MethodHandle for it, say: lambda$1Mh
>> ...then capture the final x: lambda$1BoundMh = lambda$1Mh.bindTo(x);
>>
>> now the SAM-converted lambda object has a reference to lambda$1BoundMh. It
>> uses it to delegate the invocation of it's nilary make() method to. So why
>> could it not use it to delegate equals/hashCode methods too? The
>> prerequisite is of course that MethodHandle(s) define meaningfull
>> equals/hashCode methods that take into account the captured (bound) state
>> and any final target method identity too. That's what I had in mind.
>>
>> For the above example, lambda$1BoundMh would implement equals/hashCode in
>> terms of delegating to bound Object (Integer in our case) and to the wrapped
>> MH lambda$1Mh. The final lambda$1Mh would implement equals/hashCode in terms
>> of target lambda$1 method signature.
>>
>> Now, I don't know much about MHs and how they are implemented and optimized
>> in the VM, so perhaps such scheme would defeat those optimizations. Or is it
>> still possible?
>>
>> Regards, Peter
>>
>>
>>
>>
>


More information about the lambda-dev mailing list