[External] : Re: Method and Field Literals
Remi Forax
forax at univ-mlv.fr
Fri Apr 29 20:26:21 UTC 2022
----- Original Message -----
> From: "John Rose" <john.r.rose at oracle.com>
> To: "Brian Goetz" <brian.goetz at oracle.com>
> Cc: "arjan tijms" <arjan.tijms at gmail.com>, "Ethan McCue" <ethan at mccue.dev>, "Martijn Verburg"
> <martijnverburg at gmail.com>, "discuss" <discuss at openjdk.java.net>
> Sent: Friday, April 29, 2022 10:01:06 PM
> Subject: Re: [External] : Re: Method and Field Literals
> On 24 Apr 2022, at 8:31, Brian Goetz wrote:
>
>> So, a feature where field and method literals evaluated only to Method
>> objects is a pretty weak one, and worse, fi the goal is merely to pull
>> the reflection API into the language, is likely to result in requests
>> to pull further. Though I do enjoy the extra type checking that
>> IntelliJ gives me for method and method handle lookup.)
>>
>> The reality is that Method is not a very useful type; reflection is an
>> escape hatch, which has more benefit for frameworks than for ordinary
>> user code. You might say “but we have class literals”, but this
>> is mostly a “for consistency” argument*, and one that doesn’t
>> even survive much scrutiny.
>>
>> Class literals have two aspects that method literals would not: their
>> role in inference (Foo.class has type Class<Foo>, meaning that it can
>> be used as a source of constraints in type inference), and the
>> Object::getClass method. Method and field literals would have neither
>> of these two touch points. (If it were not for the type inference
>> aspect, if we didn’t have class literals now, I might not be
>> inclined to add them — Class::forName works too.) So I would rate
>> this a pretty weak feature.
>>
>> The main reason method references are useful and these are less useful
>> is that methods have behavior, and method refs allow you to access
>> that behavior through the suitable abstraction level (e.g., Function,
>> Supplier.) Passing around Method or MethodHandle or VarHandle is not
>> particularly desirable for ordinary application code.
>>
>> There’s a version of method (and field) references that is more
>> interesting, where we can use target typing to let Foo::bar evaluate
>> to a SAM type, Method, MethodHandle, MethodDesc, or other description
>> of a method. (Note that you also have to pull in additional syntax
>> and behavior to support overload selection, since we don’t have a
>> SAM type to guide the overload selection.) That’s more interesting,
>> but a more complex feature. Fields are even more complicated, because
>> fields have TWO behaviors, and the obvious representations (Field,
>> VarHandle) are also pretty low-level and unsuitable to
>> application-level interaction. (If the language had Properties, then
>> turning a field into a Property would be a more appropriate API-level
>> encoding.)
>>
>>
>> *If the best argument you can make for a feature is “for
>> consistency”, that’s usually a sign that the feature is weak.
>>
>
> This is a very good summary for the public record of the core design
> issues for method (and field) literals. I think target typing is a
> promising tactic here but there are lots of fiddly details to work out.
> It’s definitely not one of those a “why don’t you just…”
> suggestions.
>
> I have two minor comments to add:
>
> 1. Brian mentions that target-typing to M/MH/MD fails to select
> overloads. Some of that could be worked around (w/o syntax changes) by
> encouraging users to convert first to a FI object (which contains a
> method signature) and then to the desired M/MH/MD. That would require
> fiddly rules to ensure that the right answer came out of the cascaded
> conversions, instead of an opaque FI object wrapper, so maybe an overt
> signature annotation syntax would be better on balance. (The opaque
> wrapper is harmless for MHs but not jlr.Ms or MDs.)
>
> 2. Brian mentions that fields have two behaviors. Actually they can
> have a bundle of many behaviors, including atomics, *when viewed through
> the VH lens*. And that provides a way to think about those multiple
> behaviors: Allow a field ref to be target-typed to a VH, and you get
> all the behaviors. (Similar point for jlr.F and FD.) I think it would
> be reasonable, for MHs and FIs, to simply return the read behavior and
> ignore the other behaviors. After all, read is the most important
> operation on a field (and the only one, for a final field).
>
> An aside: If you really want to have static checking of name strings,
> you can do this today by building a private-static-final constant
> containing the string, as extracted (in the static initializer) from an
> appropriately bugged serializable method reference (maybe using a helper
> function). Yeah, it’s harder than syntax sugar, but it can be done.
see https://github.com/forax/macro/blob/master/src/main/java/com/github/forax/macro/Macro.java#L496
on how to convert a serializable method reference to a SerializedLambda object
and an example showing how to write a builder for any records (with 4 or less components)
using method references.
https://github.com/forax/macro/blob/master/src/main/examples/com/github.forax/macro/example/builder3.java#L156
Rémi
More information about the discuss
mailing list