Annotating lambda expressions
Ron Pressler
ron at paralleluniverse.co
Sun Jul 12 17:00:00 UTC 2015
Yes, but only method definitions, not method bodies; that's a very big
difference.
On Sat, Jul 11, 2015 at 4:39 PM, Remi Forax <forax at univ-mlv.fr> wrote:
> On 07/11/2015 03:02 PM, Ron Pressler wrote:
>
>
> On Sat, Jul 11, 2015 at 3:59 PM, Ron Pressler <ron at paralleluniverse.co>
> wrote:
>
>> Thanks for the bootstrap argument tip! Will use that as a workaround.
>>
>>
> ... although it does require scanning the entire bytecode for the entire
> project (to find the indy callsites) rather than just looking for annotated
> methods...
>
>
> ??
> finding annotated methods requires to scan the entire project too ?
>
>
>
> R
>
>
> R
>
>
>
>>
>> On Sat, Jul 11, 2015 at 12:26 PM, Remi Forax < <forax at univ-mlv.fr>
>> forax at univ-mlv.fr> wrote:
>>
>>> On 07/11/2015 10:57 AM, Ron Pressler wrote:
>>>
>>> That's a very nice idea (in fact, we can do foo((@Special Runnable)
>>> ()->{...}), as well and get ASM to invoke a nice visitInsnAnnotation
>>> event), but it doesn't help, as I have no way of finding the method
>>> implementing the lambda by analyzing the bytecode.
>>>
>>>
>>> The method corresponding to the body of the lambda is one arguments of
>>> the bootstrap method of invokedynamic.
>>> see
>>> http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html
>>> (this translation scheme is not required to be used by compilers but in
>>> practice javac and ecj uses it and scalac will use it too)
>>>
>>> My suggestion says, "however the compiler chooses to represent the
>>> lambda, please apply the annotation to the implementing method, wherever it
>>> is". I think that the language spec at least implicitly forces the compiler
>>> to implement a lambda as a method *somewhere* (as opposed to, say,
>>> javac inlining the expression, as Kotlin does with inline functions).
>>>
>>>
>>> see above.
>>>
>>>
>>> The ability to attach introspectable metadata to a lambda expression
>>> that then travels with it to the implementing method -- wherever the
>>> compiler may choose to place it -- is extremely useful, and trumps, IMO,
>>> "purity" concerns re annotating expressions vs declarations, (esp. since
>>> we've already established that some expressions -- like cast and new -- are
>>> annotatable, and rightly so).
>>>
>>>
>>> cast and new are not annotatable, the type of a cast or a new are.
>>>
>>> Without this, we miss something important Java gives us, which is the
>>> ability to attach metadata to a method body. I fully understand the
>>> distinction that the annotation is applied to the *declaration* rather
>>> than the body itself, but that doesn't take away from the fact that a
>>> useful ability does not transfer to lambdas while it could be easily done.
>>>
>>> Ron
>>>
>>>
>>> Rémi
>>>
>>>
>>>
>>> On Sat, Jul 11, 2015 at 10:38 AM, Remi Forax < <forax at univ-mlv.fr>
>>> forax at univ-mlv.fr> wrote:
>>>
>>>> On 07/10/2015 11:41 PM, Ron Pressler wrote:
>>>>
>>>> I see no problem with cast annotations not being retrievable via
>>>> straightforward reflection just as I see no problem annotating the
>>>> generated method (which should always exist *somewhere*): in both
>>>> cases, those annotations are intended for use by tools that analyze the
>>>> entire project's source/bytecode (e.g. for typechecking/instrumentation)
>>>> rather than by specific reflective queries.
>>>>
>>>> What bothers me is that a capability that was trivial with inner
>>>> classes is now lost when using lambdas.
>>>>
>>>>
>>>> you can easily add a pattern recognizable by source/bytecode tools to
>>>> do what you want,
>>>> let suppose you have a static method like this:
>>>> static <T> T annotate(Class<? extends Annotation> annotation, T
>>>> lambda) { return lambda; }
>>>>
>>>> to annotate a lambda, your example can be written like this:
>>>> foo(annotate(Special.class, () -> { ...}))
>>>>
>>>> in the bytecode it will be translated to something like this:
>>>> ldc Special.class
>>>> invokedynamic ()Runnable
>>>> LambdaMetafactory + method handle ref on the lambda body
>>>> invokestatic Bar.annotate(Class, Object)Object
>>>> checkcast Runnable
>>>> invokevirtual Baz.foo(Runnable)...
>>>>
>>>> which is easy to recognize.
>>>>
>>>>
>>>> Ron Pressler
>>>> paralleluniverse.co
>>>> @puniverseco <https://twitter.com/puniverseco> on Twitter
>>>>
>>>>
>>>> Rémi
>>>>
>>>>
>>>>
>>>> On Fri, Jul 10, 2015 at 10:38 PM, Alex Buckley <
>>>> <alex.buckley at oracle.com>alex.buckley at oracle.com> wrote:
>>>>
>>>>> On 7/10/2015 2:31 AM, Maurizio Cimadamore wrote:
>>>>>
>>>>>> On 10/07/15 09:43, Ron Pressler wrote:
>>>>>>
>>>>>>> (Related to
>>>>>>>
>>>>>>> <http://mail.openjdk.java.net/pipermail/compiler-dev/2015-January/009220.html>
>>>>>>> http://mail.openjdk.java.net/pipermail/compiler-dev/2015-January/009220.html
>>>>>>> )
>>>>>>>
>>>>>>> It is useful to add an annotation to a lambda expression -- as in
>>>>>>> foo(@Special () -> { ...}) -- which will be applied to the static
>>>>>>> method implementing the lambda (not to the interface the lambda
>>>>>>> implements). This would allow instrumentation tools operating on
>>>>>>> method implementations to handle lambdas. So far, AFAICT, this is not
>>>>>>> possible (or am I wrong?).
>>>>>>>
>>>>>> This is not possible, currently - as Remi said; you have annotations
>>>>>> on
>>>>>> declarations (i.e. variable, classes, methods) - you have annotation
>>>>>> on
>>>>>> types (i.e. type of a cast, type argument, etc.) - but you don't have
>>>>>> annotations on _expressions_.
>>>>>> I take it that, under the current translation scheme, there seems to
>>>>>> be
>>>>>> a plausible description for what should happen when the lambda is
>>>>>> annotated; but what if the lambda is turned into a method reference
>>>>>> (by
>>>>>> some IDE refactoring, or human intervention) ? In that case it is not
>>>>>> guaranteed that there would still be a physical place where to put the
>>>>>> annotation (unless we tell the compiler to 'expand' all annotated
>>>>>> method
>>>>>> references).
>>>>>>
>>>>>
>>>>> Yes, the problem with annotations-on-expressions is not the language
>>>>> grammar but the storage of the annotations in the class file. With no
>>>>> standard way of translating source expressions to bytecode, there can be no
>>>>> standard API for retrieving annotations-on-expressions from bytecode. More
>>>>> broadly, there has never been a standard reflective API capable of
>>>>> inspecting method bodies.
>>>>>
>>>>> This explains why JSR 308 stayed away from annotations-on-expressions
>>>>> -- we were not in a position to let them be read back. It was already bad
>>>>> enough that some annotations-on-types are stored in the class file at the
>>>>> level of individual bytecodes (e.g. an annotation on the type of a cast) so
>>>>> are not retrievable by any standard reflective API.
>>>>>
>>>>> Alex
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150712/eaa0dbbd/attachment-0001.html>
More information about the compiler-dev
mailing list