Search |
||
method handles == closures ??Posted by forax on January 2, 2009 at 7:36 AM PST
John Rose (JSR 292 spec leader) recently push a great patch that enables support for method handles inside the VM. A java.dyn.MethodHandle is a safe object that stands for a function pointer but unlike a function pointer, calling a method handle with wrong arguments raise an exception. The aim of method handles (with invokedynamic) is to ease the support of dynamic languages by the Java VM. But method handles is also a good candidate to implement closures :) Using method handle VM support to implement closure Let's take an example, I want to iterate over a collection and call a method (here sayHello) on each element. Using BGGA syntax, it's something like that:
public static void each(Collection<?> c, {Object => void} closure) {
for(Object element:c) {
closure.invoke(element);
}
}
public static void sayHello(Object message) {
System.out.println("hello "+message);
}
public static void main(String[] args) {
{Object => void} closure=#sayHello;
List
And now using a MethodHandle:
public static void each(Collection<?> c, MethodHandle mh) {
for(Object element:c) {
mh.invoke(element);
}
}
public static void main(String[] args) {
MethodType methodType=MethodType.make(void.class, Object.class);
MethodHandle mh=MethodHandles.findStatic(MethodHandleTest.class, "sayHello", methodType);
List
To create a method handle, I first create its method type, here void(Object) then I perform a lookup using findStatic to find a static method named "sayHello" that takes an Object and returns void. And then I can call each with a list of String and my method handle (linked to sayHello). Compile and ...
And it doesn't compile :(
class Magic {
public static void invoke(MethodHandle mh, Object o) {
// ASM will provide the magic :)
// aload_0
// aload_1
// invokevirtual "invoke" "java/dyn/MethodHandle" "(Ljava/lang/Object;)V"
// return
}
}
public static void each(Collection<?> c, MethodHandle mh) {
for(Object element:c) {
Magic.invoke(mh, element);
}
}
And how to run it ?
Simple, take the hotspot source, the jdk source, take the
mlvm patch queue, apply the patches named "meth"
(no it's not for methadone), recompile
the VM, recompile the JDK.
To run: java -davinci-client -Xbootclasspath/p:method-handles.jar -XX:+MethodHandles fr.umlv.davinci.test.MethodHandleTest Some open questions: Are method handles more efficient than reflection ? I think the answer is Yes but I let you that as an exercice. BGGA spec allows co/contravariance how to do that with method handles ? Hum, good question for a future blog entry.
Happy new year,
»
Related Topics >>
Open JDK Comments
Comments are listed in date ascending order (oldest first)
Submitted by vieiro on Fri, 2009-01-02 10:40.
There's a *huge* difference between method handles (aka C function pointers) and closures.
So, of course, method handle != closure.
Saying that method handles equal closures is just confusing people.
MethodHandles are much more complex than C-function pointers
Submitted by fredrik_ohrstrom on Tue, 2009-09-01 01:36.
A MethodHandle is definitely not as simple as a C function pointer. It is a far more complex
construct than that! What Remi is saying is that the MethodHandle can (and should) be used
to implement closures, or to be more precise, hold on to closures. The MethodHandle by itself does
not give you lexical scoping and all the other goodness that you need.
Remi asked: BGGA spec allows co/contravariance how to do that with method handles ? My answer: You need generic invocation! :-) Vieiro, if you want to know more about the versatility of the MethodHandles, please read http://blogs.oracle.com/ohrstrom/2009/08/using_methodhandles_to_reconci....
Submitted by forax on Fri, 2009-01-02 11:19.
@veiro, yes but no :)
I agree with you if method handles was only C function pointers but
you can bound an object to method handle which is the definition
of a closure. By example:
class Sum {
int value;
public void sum(Object message) {
value+=(Integer)message;
}
}
...
public static void main(String[] args) {
MethodHandle sum=MethodHandles.findVirtual(Sum.class, "sum",
MethodType.make(void.class, Object.class));
Sum sumObject = new Sum();
// bound sumObject to create a new method handle
sum=MethodHandles.insertArgument(sum, sumObject);
each(Arrays.asList(1,3), sum);
System.out.println(sumObject.value);
}
This code is also included in the src.zip.
Cheers,
Rémi
Submitted by thedarksavant on Fri, 2009-01-02 12:02.
Or we could let Java be Java and when we want to use a dynamic language we use a dynamic language. I've been writing and reading Java for over 10 years now, and I have to admit that reading the code above gives me a slight headache and bit of nausea.
Here's how we do it in Groovy:
messages.each { println "hello ${it}" }
Of course Groovy already has closures. And Java-like syntax. And runs on the VM.
Chasing C# is just pushing more and more Java developers to Ruby and Groovy.
Submitted by vieiro on Fri, 2009-01-02 12:14.
@forax
D'oh! So you can bind objets to methods? Now, *that* is interesting!!
Submitted by ronaldtm on Fri, 2009-01-02 12:23.
I'm no language expert, but closures' definition didn't have that 'lexical scope variable binding' thing? This is what makes closures substantially more powerful than function pointers.
For example, without it, you couldn't do something like (Groovy syntax)
StringBuffer buffer = ...;
list.each { s -> buffer.append(s) } // references a local variable 'buffer' from the block that contains the closure
, which is a pretty common idiom in languages that support closures.
Submitted by forax on Sat, 2009-01-03 12:41.
@thedarksavant,
Currently when i want a closure in Java, i create an anonymous class and
I throw an exception when i want to escape earlier.
I think it could be a little bit more user friendly.
Java is a language, like any other ones, it evolves.
BTW, the syntax is not the point here. The point is the runtime support.
@ronaldtm, (funny alias),
yes, that why i have mentioned MethodHandles.insertArgument()
in my answer to vierio.
Rémi
Submitted by liquid on Sun, 2009-01-04 10:55.
this is seriously nice, the fact that we're both french and share almost the same first name (mais avec un y) just makes it better :)
All joking aside, this a seriously cool way to get some closure-like functionnality in java 7. Maybe if we could do add metraprogrammatically some method handles to a Class object, we could have closures, extension methods, and maybe some more type inference (generics + methods handles ?) and we'd be good to go ;)
This *is* letting java be java, you don't have to use it if you don't want to, it's IMHO a nice alternative to modifying the language and making everyone use one of the proposal's syntax/semantics they might not like. That looks like an interesting compromise, i'd love to hear more to make my mind about it.
Merci, Rémy
Submitted by forax on Sun, 2009-01-04 12:12.
@liquid,
> "add metraprogrammatically some method handles"
As far as i know, Interface injection is still a goal of JSR292,
see http://openjdk.java.net/projects/mlvm/subprojects.html#InterfaceInjection
It's a nice way to get a kind of extension methods without having one of its major drawback: extension method a la C# doesn't allow virtual call.
Rémi
Submitted by i30817 on Wed, 2009-01-14 14:30.
No alternative to real closures i guess. Their great advantage (and great disadvantage) is that they capture the method signature perfectly, unfortunately including exceptions. That guy in the closures mailing list proposing to linearize exception handling has a nice idea since that would mean no throws exception E garbage in closures accepting methods, but that requires that closures do not escape the method boundaries, so no closure variables, which IMO only makes sense.
I think that closures are a FP concept, and so, should not be able to be saved in variables. If that does not mean that we can't refer to a method as a closure. MyObject#method() or whatever makes perfect sense.
Submitted by i30817 on Wed, 2009-01-14 14:37.
http://mail.openjdk.java.net/pipermail/closures-dev/2008-December/000233...
Seriously is it only me thinking this is a great idea?
|
||
|
|