A peek at the roadmap for pattern matching and more

Brian Goetz brian.goetz at oracle.com
Fri Aug 14 17:42:42 UTC 2020


> Aside: My understanding of the MethodParameters attribute is that it's 
> intended more as an informational than API and unlikely to affect 
> application behaviour at runtime.

The existing MP attribute represents a somewhat unfortunate compromise.

The EE folks (remember EE?) had a compelling-enough use case for being 
able to reflect over parameter names, which was that they wanted to 
generate various remote-invocation stubs (corba, *RPC, etc) from 
classes, but felt that having to annotate each parameter 
(`foo(@MyNameIs("bob") String bob)`) would suck.  So they wanted us to 
reify the parameter names by default in the classfile, for reflection to 
serve up.

The ME folks (remember ME?) freaked out; "Whoa, more bytes in the 
classfile, you have to make that optional, and not the default!"

The EE guys came back with "OK, how about driving retention based on an 
annotation."

We said (for the zillion'th time):  You know that's not what annotations 
are for.

So the compromise was to make it a tooling option; invoke `javac` with 
`-parameters`.   Result: no one can count on them.

Now, the MP attribute itself should not need to change here; only the 
conditions under which the language promises to make these available for 
reflection and condition the compatibility rules.
> Making names significant and part of the API will affect refactoring 
> and separate compilation: developers are used to being able to freely 
> rename parameters without worrying about affects on other parts of 
> their code base or about breaking their consumers (library authors). 
>  Are there things the language can do to help with name transitions? 
>  Is treating parameter name changes in a __byname method as a breaking 
> API change something that developers will have to adapt to?

Note that we already have this problem with records; the name of a 
component in records flows into constructor descriptors, accessor names, 
etc.  It is an open question whether the developers can handle the 
responsibility :)

I have long wanted to have widely available, easy to use tooling that 
could detect incompatible changes between versions of a module, where it 
would look at the old bytecode and say "whoa, you did <incompatible 
thing> there, did you mean to?"  In the presence of such tooling, this 
would be one more set of assertions for such a mechanism.  But so far I 
haven't gotten my wish.  (Perhaps our IDE friends are cooking something 
like this up?)  I do think that detection of incompatible changes is 
something for tooling to handle, not the language.  But I agree that 
this is a concern, and more so than for records, which have the 
component names stapled to their forehead.
> Similarly libraries that implement a common specification (Java EE, 
> etc) have historically allowed each implementation to name the 
> parameters in ways that made sense for their implementation.  I can 
> see this becoming "names are API, live with it" which is a reasonable 
> answer but one that will take some time to filter thru the ecosystem 
> after the feature is released.  Any concerns that adopting this 
> feature forces a "flag day" on consumers of such libraries with all 
> implementors needing to move in lockstep?

I think the real challenge here is ensuring that, if the decision is 
made to make a member __byname, that they understand the consequences.  
("Nah, that could never change!", said every developer ever, 
incorrectly.)  Overuse of __byname could easily become a problem.  (I 
think also you're observing that this is in a sense worse than "names 
are API, live with it"; really, it's "names are *sometimes* API, live 
with that!"?)

A member going from insignificant to significant naming should be a 
compatible move, as should (eventually) adding a named parameter with a 
default to a constructor (though there's more work to do here to make 
this compatible.)  The rule about telescoping chains is there in part to 
allow us to evolve such members and leave the old entry points around.  
The flag day is when we realize "crap, that name really is so terrible 
we have to change it."

> In the "Refining overloading" section [2]
> > Each __byname constructor / deconstructor can be invoked 
> positionally, so it must follow
> > the existing rules for overloading and overload selection. A set of 
> __byname members is
> > valid if and only if for each two such members, their name sets are 
> either disjoint or one
> > is a proper subset of the other and the types corresponding to the 
> common names are the same.
> This seems like an answer to the refactoring concerns above as it 
> provides a way to leave previous API points around to not break 
> consumers.  Will the normal deprecation schemes apply to these 
> name-only overloads?  If so it covers most of the refactoring concerns 
> - though the need to leave the old API points is a bit of code smell 
> that may discourage some kinds of refactoring.  Time will tell.

Yes.  The real concern is (when we get to default parameters) that, if 
you have seventeen parameters already, that you'll have 18 tomorrow is 
virtually a guarantee.   This is tricky ground, I think I have a story 
though.
> Is the intention that the VM would check the disjoint constraints 
> during classloading?  I can see it being pushed to the VM to validate 
> or left as a language level rule with the VM's resolution taking the 
> first available match.  At first glance, both seem reasonable though 
> VM validation will incur startup costs and would need more clarity on 
> how checks for duplicate __byname constructors would mesh with the 
> "Factories" proposal, either disjoint or combined checks?  Details to 
> be worked out as the proposal progresses.

Asking the VM to check these seems a bit much, especially given that the 
names exist primarily for overload selection, which is a language 
concern.  My thinking for by-name invocation is that we do overload 
selection statically, pick a positional signature, and invoke with an 
indy that treats that positional signature as a fast path, but falls 
back to an ugly reflective linkage on fail.  This is the standard trick 
of "replicate the language semantics at runtime in indy" so the VM 
doesn't have to.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200814/faab71e8/attachment.htm>


More information about the amber-spec-experts mailing list