No way to create a no-op MethodHandle that returns void?

54 views
Skip to first unread message

Charles Oliver Nutter

unread,
Jan 24, 2012, 2:01:04 AM1/24/12
to Da Vinci Machine Project, JVM Languages
I discovered a possible gap in the MethodHandles API.

Say I want to create an exception handler that does nothing but ignore
the exception. The target handle is a method that looks like this:

void foo(String)

I have my "target" handle pointing at foo.

I want to catch all Throwable and ignore them, so I would build up a
method handle chain that does the following (top-down)

1. receives arguments (Throwable, String) and returns void
2. drops both arguments
3. ???

There's no endpoint I can attach it to for a "no-op" void return.

"constant" doesn't work because it returns a value, and explicitly
forbids void return type.

"identity" doesn't work because it returns a value and receives one argument.

What I need here is something like MethodHandles.constant, but that
takes no arguments and has a void return. MethodHandles.nop anyone?

I could filterReturn, but I still would have to attach it to an
external method...there's no way to create a filter that returns void
entirely with method handles.

Am I missing something?

- Charlie

Charles Oliver Nutter

unread,
Jan 24, 2012, 2:26:25 AM1/24/12
to Da Vinci Machine Project, JVM Languages
Oh, that does seem to work...what an ugly hack. And actually, you can
just use Object.class but cast the resulting return to void, and it
works.

So basically, I do this:

handler = MethodHandles.constant(Object.class, null)
handler = MethodHandles.asType(void.class)
handler = MethodHandles.dropArguments(0, Throwable.class, String.class)

And then use that as the exception handler.

It's not exactly the no-op I wanted, since it has the cast logic in
there, but it's close enough.

FWIW, I'm using this in the tests for invokebinder, for testing the
tryFinally operation:

public void testTryFinally3() throws Throwable {
MethodHandle post = Binder
.from(void.class, String[].class)
.invokeStatic(MethodHandles.lookup(),
BinderTest.class, "finallyLogic");

MethodHandle ignoreException = Binder
.from(void.class, RuntimeException.class, String[].class)
.drop(0, 2)
.cast(Object.class)
.constant(null);

MethodHandle handle = Binder
.from(void.class, String[].class)
.tryFinally(post)
.catchException(RuntimeException.class, ignoreException)
.invokeStatic(MethodHandles.lookup(),
BinderTest.class, "setZeroToFooAndRaise");

assertEquals(MethodType.methodType(void.class,
String[].class), handle.type());
String[] stringAry = new String[1];
try {
handle.invokeExact(stringAry);
} catch (RuntimeException re) {
assertTrue("should not have reached here", false);
}
assertEquals("foofinally", stringAry[0]);
}

invokebinder is my MethodHandle DSL, so I don't have to stand on my
head while building MH chains :)

https://github.com/headius/invokebinder

- Charlie

On Tue, Jan 24, 2012 at 1:07 AM, Noctarius <m...@noctarius.com> wrote:
> Hi Charly,
>
> why not use Void and return null what behaves like using void as
> the return type.
>
> Cheers
> Chris

>> - Charlie _______________________________________________
>> mlvm-dev mailing list mlvm...@openjdk.java.net
>> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>
>
> --
>
>
> ##############################
> # A Digital's Life           #
> ##############################
> Nickname: Noctarius
> Location: Germany
>
> Meet me at:
> Ohloh: http://www.ohloh.net/accounts/noctarius
> Web: http://www.noctarius.com
> XMPP/Jabber: noct...@jabber.ccc.de
> _______________________________________________
> mlvm-dev mailing list
> mlvm...@openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

John Rose

unread,
Jan 24, 2012, 3:40:57 AM1/24/12
to Da Vinci Machine Project, JVM Languages
On Jan 23, 2012, at 11:26 PM, Charles Oliver Nutter wrote:

> Oh, that does seem to work...what an ugly hack. And actually, you can
> just use Object.class but cast the resulting return to void, and it
> works.
>
> So basically, I do this:
>
> handler = MethodHandles.constant(Object.class, null)
> handler = MethodHandles.asType(void.class)

The EG considered things like having MethodHandles.constant(void.class, null) or identity(void.class).
Even identity(methodType(void.class, Throwable.class, String.class)).
There is a certain logic to such things but it didn't feel regular enough, and users can get the same effect by asType (as you realized).

Noctarius is right in referring to Void. The MH API treats Void fairly regularly as the wrapper type for void, with a unique (unit) wrapped value of null.

> handler = MethodHandles.dropArguments(0, Throwable.class, String.class)
>
> And then use that as the exception handler.
>
> It's not exactly the no-op I wanted, since it has the cast logic in
> there, but it's close enough.
>
> FWIW, I'm using this in the tests for invokebinder, for testing the
> tryFinally operation:

That binder stuff is great. Next, we want a builder syntax in Java (for more than just List+Map constants). Plus a little type-system bridge from Foo::bar and foo->bar to MethodHandle. Then we can compose our method handles quite swimmingly.

-- John

Rémi Forax

unread,
Jan 24, 2012, 4:18:42 AM1/24/12
to Da Vinci Machine Project, John Rose, JVM Languages

Lambda should provide bridge from Foo::bar to MethodHandle :)

>
> -- John

R�mi

Charles Oliver Nutter

unread,
Jan 24, 2012, 4:20:37 AM1/24/12
to jvm-la...@googlegroups.com, Da Vinci Machine Project

A syntax in Java would be quite powerful. Hopefully something like
invokebinder can bootstrap it. I've grown quite fond of it now, and
I'm using it to replace some of the ugly bits of JRuby's indy logic.

Here's the tests I have for it. Not all MethodHandles transforms are
implemented, but most of them are there:

https://github.com/headius/invokebinder/blob/master/src/test/java/com/headius/invoke/binder/BinderTest.java

The unfortunate thing is that it would be a whole lot nicer if I had
lambda right now. Here's that same tryFinally setup from before with a
hypothetical version that uses lambda expressions.

https://gist.github.com/1668691

Damn near as syntactic as you would ever really need. :)

- Charlie

Paul Phillips

unread,
Jan 31, 2012, 1:32:52 AM1/31/12
to jvm-la...@googlegroups.com


On Tue, Jan 24, 2012 at 1:20 AM, Charles Oliver Nutter <hea...@headius.com> wrote:
The unfortunate thing is that it would be a whole lot nicer if I had
lambda right now. Here's that same tryFinally setup from before with a
hypothetical version that uses lambda expressions.

https://gist.github.com/1668691

Damn near as syntactic as you would ever really need. :)

What? You can never have enough syntax!


from[(String, String) => String] invoke target

Reply all
Reply to author
Forward
0 new messages