Lambda and JSR 292 method handle

Rémi Forax forax at univ-mlv.fr
Fri Dec 18 06:05:53 PST 2009


Le 18/12/2009 11:55, Howard Lovatt a écrit :
> Rémi,
>
> I thought the idea from the JSR 292 group was to use JavaMethodHandle
> [1] (which extends MethodHandle). The difference is that the
> JavaMethodHandle retains the type information, needed by Java, and it
> can implement interfaces so you can use a lambda with an existing
> function. Your example:
>
> class A {
>     public static void main(String[] args) {
>       #int(int) f = #(int x) (x+x);
>       f(2);
>     }
> }
>    

Here is what I am thinking:
A JavaMethodHandle is a method handle that allow you to implement one or 
more interface.
One goal is to use it to implement function conversion, i.e when you 
want to use a lambda
as a class implementing an interface like Runnable, Callable, etc to be 
able to use legacy code.
Because a JavaMethodHandle is a method handle, you don't need an 
interface like CallableInitInt,
you already can invoke it using .invokeLambda().

This approach is too heavyweight for being used for 'classical' lambda 
because it requires
to create a new class for each lambda.

Some experts in JSR 292 expert group think that JavaMethodHandle aren't 
neccessary.
They complexify the implementation and may disable some optimizations 
done by the VM.
So this feature is still under consideration.

You can notice that function conversion (the one of the strawman 
proposal and the one of BGGA)
doesn't require that the resulting object to be a lambda.

Runnable r = #() { System.out.println("run"); }
#void() f = (#void()) r;    // works with JavaMethodHandle but not 
required by the spec

So function conversion can be implemented without JavaMethodHandle.

Cheers,
Rémi

> Would get translated to:
>
> class A {
>    private static final class Lambda$1 extends JavaMethodHandle
> implements CallableIntInt {
>      private static final Lambda$1 instance = new Lambda$1();
>      @Override public int call( int x ) { return x + x; }
>      private Lambda$1() { super "CALL"; }
>      private static final MethodHandle CALL =
> MethodHandles.lookup().findVirtual( Lambda$1.class, "call",
> MethodHandles.methodType( int.class, int.class ) );
>    }
>    public static void main(String[] args) {
>      CallableIntInt f = Lambda$1.instance;
>      f.call(2);
>    }
> }
>
> Where CallableIntInt is either a standard interface, in java.lang say,
> or a synthetic interface (depending on implementation details) and is:
>
> public interface CallableIntInt { int call( int a ); }
>
> If you use a MethodHandle directly then you can't pass it to anything
> because you have lost the type information, i.e. an invokeGeneric on a
> method handle will accept any arguments (though will throw a runtime
> exception). EG if I have a method:
>
> void m( #int(int) f ) { out.println( f( 2 ) ); }
>
> Then if you use MethodHandles directly it would be translated to:
>
> void m( MethodHandle f ) { out.println( f.<int>invokeGeneric( 2 ) ); }
>
> But then I could say:
>
> m( #void() () );
>
> And the compiler couldn't catch the mistake. Using JavaMethodHandles
> instead, would mean m is translated into:
>
> void m( CallableIntInt f ) { out.println( f.call( 2 ) ); }
>
> And hence retains type safety.
>
> The above JavaMethodHandle version doesn't seem to be that much better
> than using an inner class directly! There was also, at least
> originally, talk of anonymous classes in JSR 292 [2]; these would seem
> to be more useful, are they still part of JSR 292? (I ask because I
> think you are on the expert group.)
>
>    -- Howard.
>
> PS The above APIs are in a state of flux, I have used the versions (at
> least I tried to without having a compiler to check my code) from the
> paper you can download from [3].
>
> Ref:
> [1] http://cr.openjdk.java.net/~jrose/pres/indy-javadoc-b59/
> [2] http://blogs.sun.com/jrose/resource/DVMTest.java.txt
> [3] http://blogs.sun.com/jrose/entry/vmil_paper_on_invokedynamic
>    



More information about the lambda-dev mailing list