New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Method reference support #18748
Method reference support #18748
Conversation
I will check and commit changes when I come back from Berlin buzzwords. 😉 Am 6. Juni 2016 15:49:33 MESZ, schrieb Robert Muir notifications@github.com:
Uwe Schindler |
…ry. Without it real lambdas won't work, as their implementations are private to script class
Hi Robert: I just fixed the methodhandles lookup object passed to LambdaMetaFactory. For real lambdas we need to pass the lookup object of the original invokedyanmic, otherwise it wont find the lambda method impl. This fixes one todo |
…led code when a conversion fails. This works anyways, because fallback is allowed to throw any Throwable
Hi Robert, |
BTW: filterArguments should be fine! One question: How do we handle method calls using functional references that are statically compiled (e.g., calls on non-Def methods that pass a functional ref) |
As i mentioned above: we dont need to be doing any lookuping or classloader passing. This is just because of shitty ASM apis. We can fix that. |
This is the easy case: https://github.com/rmuir/elasticsearch/blob/3238868cc43346c34fe4068c0d7e60eff4e4c387/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java#L67-L79 We just invoke LambdaMetaFactory right there, and push the result (which is e.g. a Comparator or whatever the functional interface is) on the stack. |
Ah, missed that one!Uwe Schindler |
Yeah, the thing done there is the same as javac, you know the type of the expected interface, so you know everything :) |
I cleaned this up, it is not so horrible anymore. I want to iterate with further stuff as a followup. |
LGTM. Thanks for getting method refs working. |
Thanks for the help here @uschindler @jdconrad . The ugly parts are fixed, we can try to extend it in followup issues with some of the deferred stuff, e.g. |
This adds support for method references (
Class::virtualMethod
,Class::staticMethod
,Class::new
).The syntax for this was added in #18578, as a stub that throws UnsupportedOperationException. This adds the logic. It is useful because these are the simplest lambda types (non-capturing, no desugaring needed), but can make the functional apis usable to users in many ways, based on functions that already exist. For example plugging in different functions for comparators, using streams apis, etc.
There are two cases: static and dynamic. In the static case we call LambdaMetaFactory from bytecode, since we know everything we need at compile time. This is similar to javac's case, just infer interface from the method's argument type.
In the dynamic case, we don't yet know enough to do anything interesting, so we just push the reference on the stack as a string, and mark the argument as a function in a bitset passed as a static bootstrap param. Once types are known at runtime, then we do the same stuff as the static case, just with java code, and replace the "placeholders" using MethodHandles.filterArguments.
Array constructor references (
foo[]::new
) are not yet supported. We should do that as a followup if we want to support them, as they are a little more complicated (require us to write bridge methods). For cases like this we will need to "expand" our recipe param to be something better than a bitset, so that pointers to our own-written functions can work too.There are also some random cleanups, and additional strictness to the whitelist: enforcing that we always whitelist covariant and generic overrides. Some of this is kinda unrelated, but happens to be here.
The PR is not yet ready. In particular it is super-messy, and there needs to be a lot of cleanup and refactoring before we should push it. For example, FunctionRef class should maybe work with MethodType rather than ASM types, and Definition should do the functional interface computation stuff (no reflection api needs to be used). The two different apis for the two ways we call this thing (Handle/MethodHandle and Type/MethodType) make things a mess at the moment. Needs help :)
@uschindler i know you are at buzzwords, but if you have some time to look, would be great to get your thoughts on some of this.