This email has no concrete proposal describe within, but rather is intended to start a discussion relating to the finer-grain aspects of the Record Attribute and the primitives built atop.
Records offers a new protocol that can be leveraged at runtime by frameworks and libraries; A record class has a known state, accessors of that state, and a canonical constructor to initialize the state. Taken together these properties offer a new protocol for libraries to interact with records. We already see this with serialization libraries, e.g. Java Serialization, Jackson, Kryo, etc. The language, as it should, provides very strong guarantees about what it means to be a record class; is final, j.l.Record is the direct superclass, a final field and accessor for each component, a canonical constructor, etc. The JVM, however, does not provide such strong guarantees, which is not surprising. There is, and it is desirable to have, flexibility between the language and the JVM. The last piece of the puzzle, which builds atop the runtime, is the reflective support in the Java Core Libraries, namely j.l.Class and friends. For frameworks and libraries to take advantage of the "records protocol", then they need to be able to introspect and determine the various properties of a record class. To date, the Class::isRecord and Class::getRecordComponents primitives have proved sufficient for this. Lastly, and highly desirable, is that we've been able to expand the notion of "trusted final fields" to the fields of record classes [1]. The impact of this on the Java Core Libraries is that the fields (backing that of the record components) are not writable through the various Core Reflection, MethodHandle and VarHandles, APIs. There is a clear and tight coupling between the Java Reflection APIs and that of the JVM - they don't necessarily need to operate or even behave in the exact same way, but the relationship should be clear and well-specified. When it is not, we often find undesirable and uncomfortable behavior in dark corners - "Here be Dragons"! A recent change, 8255342 [2], laxifies the JVM checking of the Record Attribute - the JVM will happily consider a non-final, abstract class, that is not a direct subclass of j.l.Record to be a record class. The JVM implementation stores the record-ness property which feeds into the consideration of trust-final-non-static-fields, which can then feed into potential behavior (and optimizations?) in the JVM. In the Java Reflection APIs, the "writability" of the field of the record class is determine by the JVM's notion of whether or not class C is a record, and not C.isRecord - which may disagree with the JVM. But the specification of writability in the Core Reflection APIs builds upon Class::isRecord (what else could it do!). Not to mention object field lookup in Unsafe. We have a JIRA issue [3] tracking the potential knock-on affect on the Java Core Reflection APIs resulting from the changes for 8255342. We could just "fix" that bug and move on, but I think there is something more fundamental at stake here, and it may be best to re-consider some prior decisions relating to the interpretation of the Record Attribute itself. I don't have all the answers, but it seems that at an early stage the Record Attribute was merely some meta-data carried in the class file, hence its position in the second of the predefined attribute categorizes, "not critical to correct interpretation of the class file by the Java Virtual Machine, but are either critical to correct interpretation of the class file by the class libraries of the Java SE Platform". Is that still the case? Does the JVM consider the record-ness of a class for other parts of it operation now (trusting final fields)? It seems highly desirable that both the JVM and the Java Reflection Libraries agree on what it means to be a record at runtime. And where they do not, then that should be explicitly understood and the implications assessed. Comments welcome. -Chris. [1] https://bugs.openjdk.java.net/browse/JDK-8247444 [2] https://bugs.openjdk.java.net/browse/JDK-8255342 [3] https://bugs.openjdk.java.net/browse/JDK-8255560