Deconstructor reflection Was: Re: Deconstruction patterns

Brian Goetz brian.goetz at oracle.com
Tue Mar 7 20:16:32 UTC 2023



On 3/7/2023 2:51 PM, Dan Heidinga wrote:
>
>
>     #### Reflection
>
>     Since matchers are a new kind of class member, they will need a
>     new kind of
>     reflective object, and a method that is analogous to
>     `Class::getConstructors`.
>     The reflective object should extend `Executable`, as all of the
>     existing
>     methods
>     on `Executable` make sense for patterns (using `Object` as the return
>     type.)  If
>     the pattern is reflectively invoked, it returns `null` for no
>     match, or an
>     `Object[]` which is the boxing of the values in the carrier.
>
>
> This surprised me slightly and I'm not sure I follow the reasoning on 
> why the return value would be boxed and collected into an Object[]?
>
> The design says matcher methods return Object as an opaque descriptor 
> for the actual implementation carrier object.  Yet, reflection will 
> take that carrier object, and replace it with an equivalent Object[] 
> resulting in more allocations and (potentially) boxing on the return path.
>
> I get it's a developer friendly approach but I wonder if it encourages 
> the wrong mental model about what matchers return?
>
> Would it make sense to add an extra step in that process so the 
> java.lang.reflect.Matcher instance has a `Object[] 
> resultToArray(Object)` method?  It's more ceremony (yuck) but allows 
> avoiding the array creation and maybe the boxing on the return path 
> for allocation-sensitive callers?

There's a few things here, let's try to unpack them.

I agree that the actual classfile descriptor of the synthetic method 
need not be all that related to what reflection does, though it is nice 
to minimize that difference if we can.

Reflection routinely boxes everything; if you're working reflectively, 
this is just the price of entry?  MethodHandles are a different story, 
of course, and we should be able to unreflect a Matcher to something 
that can be invoked directly.

I had been assuming that `invoke` was a method on Executable, but now 
that I look, I realize that invocation lives on the subclasses Method 
and Constructor.  So we have more latitude than I thought. Which nudges 
me a little towards

     Object[] match(Object matchTarget, Object... additionalArgs)

where match failure is reflected as null.

This also nudges me a bit towards hiding matchers from getMethods() and 
friends (as we do with constructors).

> And speaking of MethodHandles, will there be new 
> MethodHandles.Lookup.findMatcher , findDeconstructor, etc methods?  Or 
> do you see them being looked up with the existing find* methods?

I had been assuming that we would use MethodHandle::findStatic for this.

>     We will then need some additional methods to describe the
>     bindings, so the
>     subtype of `Executable` has methods like `getBindings`,
>     `getAnnotatedBindings`,
>     `getGenericBindings`, `isDeconstructor`, `isPartial`, etc. These
>     methods will
>     decode the `Matcher` attribute and its embedded attributes.
>
>
> What does `getBindings` return?  The MethodType describing the 
> bindings?  A Class[] describing the types of the bindings? Something else?
>

     Class[] getBindings();
     Type[] getGenericBindings();
     AnnotatedType[] getAnnotatedBindings();


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20230307/8e8ac24c/attachment.htm>


More information about the amber-spec-experts mailing list