Call for Dicussion: JEP: Java Expression Trees API
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu May 9 11:15:23 UTC 2024
Hi, couple of notes here on annotations.
The general policy for annotation use is that annotations cannot be used
to alter semantics of a program. Does @CodeReflection changes semantics?
The jury is out, I believe. On the one hand, a method annotated with
@CodeReflection has bytecode like any other method. On the other hand,
such a method will return something meaningful when the impl of that
method is inspected using code reflection. Is that an acceptable
semantics change? My feeling here is that it is. Because the kind of
semantics change brought by this annotation is a reflective one - not
too different from e.g. asking if a method has an annotation (which of
course will only return true if the annotation is present - is that a
semantics change? Well no).
Now, with that out of the way, the use you describe of @CodeReflection
paired with functional interface might work, yes. But there's another
issue here, one of trust boundaries: are we ok with a library single
handedly decide for all its clients as to whether the lambdas passed
into it must be reflectable? This is a bit of a shaky territory, and one
where there's many similarities with how we approached serializable
lambdas back in Java 8. Where we ended up back then was:
* if a library just takes Function<T, R>, a lambda is not serializable.
A client must opt in (with a cast - e.g. Function & Serializable)
* if the library takes a SerializableFunction<T, R> where this extends
Serializable, no opt in is required.
This behavior was deemed acceptable for Java 8, so it does create some
kind of precedent for Babylon.
Now, the difference is that serialization of lambda expression is
generally not very encouraged, even by our own docs [1]. This is mainly
due to the fact that serializing a lambda expression would unavoidably
expose some compiler artifacts (pretty much in the same way as
serializing an inner class would). So there was a sort of incentive to
make serializable lambdas explicit and... well, not that pretty.
But with code reflection, the situation is a bit different: code
reflection is about persisting the IR of a computation in a way that
reflect the structure of source code it comes from. And this kind of
"serialization" is less dirty than the classic one. So there might be an
argument here that, perhaps, some of the constraints around
explicit-ness and opt-in might be relaxed, eventually.
All that said, in a way we're arguing about "syntax" in a way.
Eventually, there needs to be a way to pass a lambda where a reflectable
functional interface is expected. Currently, this is done with the same
approach as serializable lambdas which, while heavy-handed, it is at
least consistent with other similar choices we made in the past. We
might improve this, which will result in a slightly different syntax to
achieve the same goal, but I don't think the specific syntax we use to
denote reflectable lambdas is too important at this stage of the project?
Cheers
Maurizio
[1] -
https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html#serialization
On 09/05/2024 11:54, Konstantin Triger wrote:
> Hey Maurizio,
>
> If we are in agreement that using wildcards is not an important case,
> I'm not sure I understand why this does not slot well into the
> existing type system. Potentially I'm missing something.
> On the other hand, something like: method(@CodeReflection Function<T,
> R> f) is another option that won't suffer from compiler issues, but
> per Paul might not be clear/secure enough.
>
> I just want to say that Quotable is also far from being a perfect
> solution (personally, I think it is worse than the 2 above). Seems
> that it was chosen due to similarity to Serializable case and because
> it already exists. But "Serializable" is an old solution, that
> was introduced before annotations, not sure the same design would be
> done today.
>
> P.S. I'm raising the above as my personal thoughts. I'm not part of
> the Babylon team and will totally understand if the above will be
> completely ignored.
>
> Thanks,
> Kosta
>
>
> On Thu, May 9, 2024 at 2:46 AM Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> wrote:
>
>
> On 08/05/2024 22:56, Konstantin Triger wrote:
>> Hi Maurizio,
>>
>> Looking on this, I'm wondering how important is this case:
>> Quoted<Function<?, ?>> f = (Integer i) -> "";
>> The "practical" case is something like: <T, R> RETURN_TYPE
>> method(Quoted<Function<T, R>> f).
>> Which should compile well because of inference.
>> And if someone insists on working with wildcards, so he has an
>> option.
>
> The specific case per se is not important. But if Babylon needs
> more help from the language, I think whatever feature we add needs
> to slot it correctly into the existing type system/inference
> machinery. The Quoted<T> idea at the moment seems more a case of a
> square peg in a round hole - but that's not to say that, maybe,
> we'll come up with some clever idea to rescue that approach.
>
> Maurizio
>
>>
>> Kosta
>>
>> On Wed, May 8, 2024 at 3:19 PM Maurizio Cimadamore
>> <maurizio.cimadamore at oracle.com> wrote:
>>
>> On 06/05/2024 18:50, Paul Sandoz wrote:
>>
>>>> Just wanted to mention that there might be alternative implementations addressing this requirement.
>>>> 1. Structural quoting (a la C#) - derives from the variable type, e.g. Quoted<T>. So, the user understands that the lambda body will be accessible.
>>> There are some challenges with Java’s type system, which is why we embedded up where we are with the current approaches. Maurizio is better able than I to describe these challenges.
>>
>> Hi,
>> we have explored approaches such as |Quoted<T>| (where |T| is
>> a functional interface) early on. And found them a bad fit
>> for Java. The main issue we faced is that being a functional
>> interface, as per today’s JLS, is a predicate on class
>> declarations not types (there was some intense discussion on
>> this point during Java 8). But here we have something that
>> can be treated as a functional interface or not, precisely
>> depending on its type (e.g. the type parameter). E.g. a
>> |Quotable<T>| is a functional interface or not depending on
>> |T|. This is a pretty deep big departure from how the spec
>> currently deal with functional interfaces.
>>
>> One possibility would be for the compiler/spec to ignore the
>> |Quoted<T>|, and just focus on the inner |T|, and then add
>> the quoting back, after type-checking. But doing so leads to
>> (bad) edge cases. For instance, Java 8 supports a form of
>> inference of the target type from the explicit lambda
>> parameter types, in this case:
>>
>> |Function<?, ?> f = (Integer i) -> ""; |
>>
>> In this case, the type of the lambda expression is not just
>> |Function<?, ?>| (the target type), but
>> |Function<Integer,Object>|. That is, the compiler tries to
>> get rid of the wildcards before attempting to type-check the
>> lambda expression (this step is performed to avoid wildcards
>> popping up when checking the lambda body). But with quoting,
>> this won’t compose well - e.g.:
>>
>> |Quoted<Function<?, ?>> f = (Integer i) -> ""; |
>>
>> Will give an error:
>>
>> |error: incompatible types: Quoted<Function<Integer, Object>>
>> cannot be converted to Quoted<Function<?, ?>>
>> Quoted<Function<?, ?>> f = (Integer i) -> “”; ^ |
>>
>> That is, the functional interface type inferred by the
>> compiler (by dropping wildcards) is now incompatible with the
>> target type (because of the way in which generics
>> type-argument containment rules work). To make things work,
>> the client would need at least to do this:
>>
>> |Quoted<? extends Function<?, ?>> f = (Integer i) -> “”; |
>>
>> Overall it felt like we were pushing against the physics of
>> the language here. Serializable lambdas (with all their
>> limitations) were a strong precedent to build on top of,
>> which didn’t suffer from any of the limitations described above.
>>
>> Maurizio
>>
>>
>>
>>
>>
>> --
>> Regards,
>> Konstantin Triger
>
>
>
> --
> Regards,
> Konstantin Triger
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/babylon-dev/attachments/20240509/10d7e191/attachment-0001.htm>
More information about the babylon-dev
mailing list