Lambda and JSR 292 method handle

Howard Lovatt howard.lovatt at iee.org
Wed Dec 23 13:06:59 PST 2009


Rémi,

Sorry for not replying sooner (Christmas).

Presumably the problems with using generic style annotations and erasing the
actual type include:


   1. Can't have two methods of the same name only distinguished by lambda
   type, e.g. filter( #boolean(int) ) and filter( #boolean(float) )
   2. Can't have arrays of lambdas that are type safe, e.g. new #(int)()[ n
   ]; // Illegal
   3. Can't have instanceof tests (this might be possible since type
   information is carried at runtime)
   4. Can't have primitive types (this might be fixable with an extension to
   the signature attribute)
   5. Can't have static fields that are lambdas (this might be fixable with
   an extension to the signature attribute)

Are these limitations too great?

Are anonymous classes still part of 292?

Merry Christmas,

 -- Howard.

2009/12/18 Rémi Forax <forax at univ-mlv.fr>:
> Le 18/12/2009 16:06, Howard Lovatt a écrit :
>>
>> I don't get what you are saying, probably just me being slow, so
>> please bare with me. If in compilation unit A I have:
>>
>> void m( #int(int) f ) { out.println( f( 2 ); }
>>
>> and I use MethodHandle then this will get translated into:
>>
>> void m( MethodHandle f ) { out.println( f.<int>invokeGeneric( 2 ) ); }
>>
>> Then in compilation unit B I will see the signature "void m(
>> MethodHandle )", i.e. the actual types have been erased. In
>> compilation unit B I can therefore say:
>>
>> m( #void() );
>>
>> and the compiler will allow this because in compilation unit B it
>> doesn't know that m really expects a #int(int) because that
>> information was lost when the function type was converted to a
>> MethodHandle which carries only type information at runtime not
>> compiletime.
>>
>> What am I missing?
>>
>
> #int(int) is kept in the bytecode in the attribute Signature
> wich is extended to support function type.
>
> It works like with the erasure of generics:
>
> interface List<E> {
>  boolean add(E element);
> }
>
> the compiler translates the generics code to:
>
> interface List {
>  bolean add(Object element);
> }
>
> and insert a special method attribute named Signature to allow
> separate compilation of generics.
> In the example, the value of attribute Signature of
> method add(Object) is (E)Z
>
> If you want more info see 4.8.8 of class file format:
>
http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf
>
> So void m(#int(int) f) is erased to void m(MethodHandle) but like
generics,
> the attribute Signature will keep the function type, so its value will be
> something like (#I(I))V
>
>> Thanks,
>>
>>  -- Howard.
>>
>
> Cheers,
> Rémi
>
>> 2009/12/18 Rémi Forax<forax at univ-mlv.fr>:
>>
>>>
>>> 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
>>>>
>>>>
>>>
>>> ______________________________________________________________________
>>> This email has been scanned by the MessageLabs Email Security System.
>>> For more information please visit http://www.messagelabs.com/email
>>> ______________________________________________________________________
>>>
>>>
>>
>>
>>
>
>
> ______________________________________________________________________
> This email has been scanned by the MessageLabs Email Security System.
> For more information please visit http://www.messagelabs.com/email
> ______________________________________________________________________
>



-- 
 -- Howard.


More information about the lambda-dev mailing list