FYI, proposed javax.lang.model changes for records

Joe Darcy joe.darcy at oracle.com
Tue Oct 8 00:52:34 UTC 2019


Hello,

On 10/7/2019 3:51 PM, Maurizio Cimadamore wrote:
> Hi Vicente,
> looking at the ElementKind construct, it is very nice to see that we 
> have now a nice 1-1 mapping between:
>
> - Record/Record_Component
> - Enum/Enum_Constant
>
> That said, from an API perspective, while both enums and records are 
> TypeElement (so we're consistent there), there's nothing in the API to 
> model enum constants directly, while now we do have a way to model 
> record components.
>
> I think this asymmetry should be rectified, eventually, but I do not 
> think this is a fault of the record API - I believe in reality what 
> I'd wish is for enums to be more exposed in the element API, rather 
> than being presented as a special kind of field (which is, I think, 
> what happens now). Moreover, there's no way to ask a TypeElement 
> representing an 'enum' questions like: give me all your constants.

Giving some context on the API design here, back in the original apt 
modeling API, there was a more specific correspondence between the 
interface hierarchy and the language concepts. For example, there were 
interfaces for all of

* TypeDeclaration
* ClassDeclaration extends TypeDeclaration
* EnumDeclaration extends ClassDeclaration (adding getEnumConstants method)
* InterfaceDeclaration extends TypeDeclaration
* AnnotationTypeDeclaration extends InterfaceDeclaration

Based on experience with the apt API, wanting to make the replacement 
API easier to evolve and easier to be implemented by multiple compilers, 
we made the javax.lang.model API less specific. For example, all five 
interfaces above map to javax.lang.model.TypeElement. The flip side is 
if methods are conceptually hoisted up the interface hierarchy, because 
several layers of interfaces are combined, more special cases in methods 
will need to be defined in terms of vacuous results. For example, if 
javax.lang.model.TypeElement::getSuperClass is called on an interface 
type, a sentinel "no type" value is returned. Another consequence is 
that methods analogous to "getEnumConstants" aren't necessarily were 
you'd look for them. To keep the main modeling interfaces streamlined, 
secondary functionality was moved over to the 
javax.lang.model.util.Elements helper interface. There isn't a single 
method in the current javax.lang.model API for returning the enum 
constants; filtering on the enclosed objects whose element kind is 
ENUM_CONSTANT is how I'd recommend coding the functionality in user code 
and how javac's printing processor isolates the constants. It would also 
be possible to add a method to return the constants to 
javax.lang.model.util.Elements.

(If default methods were available when JSR 269 was being designed, it 
is likely we would have made different API trade-offs and included more 
convenience methods in the main interfaces.)

Vicente and I had various off-list discussions about how record 
components should be represented in javax.lang.model. [1] One possible 
model is what is proposed here, record components as a new direct 
subinterface of Element.

I don't think it is absolutely necessary to give record components their 
own modeling interface, but I think it is reasonable to do so given 
their additional "conceptual size" compared to enum constants. For 
example, a record component gets mapped into potentially a constructor 
parameter, a private field, and an accessor method and can host 
annotations that get copied down accordingly. That is "bigger" than the 
enum constant mapping of to a static final field. [2] I wouldn't object 
to a convenience method for getting the enum constants of a type , but I 
think retrofitting a EnumConstantElement interface would be problematic 
with respect to behavioral compatibility of existing visitors.

One of the main technical differences between javax.lang.model and the 
older api apt API besides the leaner modeling approach is 
javax.lang.model tackles the "expression problem" for coping with 
evolving the language while the apt API was only intended for the Java 
SE 5.0 iteration of the language. [3]

HTH,

-Joe

[1] The modeling choices include:

1) New top-level RecordComponentElement as a direct subinterface of 
javax.lang.model.Element with matching kind.

2) New sub-interface of VariableElement; record components distinguished 
by a new kind.

3) No new interface for record components, reuse VariableElements with a 
RECORD_COMPONENT kind.

It is clearer how to make solutions 1) and 3) work for the visitors, 
with 1) being the most straightforward if largest footprint on the API.

[2] A limitation of the current modeling of enum constants came to my 
attention in the context of some recent work on an annotation processor 
to check the declarations of serializable types. If an enum constant is 
declared using the specialized enum constant syntax which implicitly 
defines an anonymous class, there is no way through the existing API to 
access the members of that class. To address this, the API could allow 
enum constants to have a non-empty list of enclosed elements. However, 
since this is, to my knowledge, the first time this limitation has come 
up in about 15 years of using the API, I don't think it is a very urgent 
problem.

[3] See https://en.wikipedia.org/wiki/Expression_problem for history and 
discussion. The visitUnknown visitor methods and UnknownFooExceptions 
are the mechanisms to allow well-written annotation processors to be run



More information about the compiler-dev mailing list