= GEP-14: Record classes :icons: font .Metadata **** [horizontal,options="compact"] *Number*:: GEP-14 *Title*:: Record classes *Version*:: 1 *Type*:: Feature *Status*:: Draft *Leader*:: Paul King *Created*:: 2021-10-26 *Last modification* :: 2021-10-26 **** == Abstract Record classes, or _records_ for short, are a special kind of class useful for modelling plain data aggregates. They provide a compact syntax with less ceremony than normal classes. Groovy already has AST transforms such as `@Immutable` and `@Canonical` which already dramatically reduce ceremony but records have been introduced in Java and record classes in Groovy are designed to align with Java record classes. === Motivation For motivation of the general concept for records, see the References and useful links section below. The overall summary is that very succinct classes can be written for the special case of plain data aggregates, e.g.: [source,groovy] ---- record Point3D(int x, int y, int z) { } ---- or: [source,groovy] ---- record Person(String firstName, String lastName) { } ---- Such classes have automatic `toString`, `hashCode` and `equals` methods and an automatic tuple constructor. All of these factor into account the properties (known as record components) of the class. === Requirements The main requirement is to provide equivalent functionality to Java record classes when compiling on suitable JDK versions (16+). By _equivalent functionality_, the following aspects are relevant: * Support reduced ceremony when writing records. * Store appropriate information at the bytecode level so that Groovy records are recognised by Java. We refer to classes with such bytecode information as _native_ records. * Maintain Java syntax compatibility where possible including the compact constructor syntax. ==== Non-goals * Provide native record support on versions of the JDK which supported records in preview mode === Design considerations * Numerous Groovy AST transforms already provide functionality that overlaps with some features of Java records, e.g. `@ToString` helps reduce ceremony by offering a declarative mechanism to achieve an _automatic_ `toString` method. Where it makes sense, Groovy's record implementation should leverage such existing functionality. * Even though existing Groovy AST transforms can be pieced together to achieve mimic record functionality, it sees worth providing a pre-canned packaging of those pieces to mirror record functionality in a concise way. Records should not introduce any additional impedance for Java developers learning or using Groovy. * Groovy's existing AST transforms offer additional customization options and additional boilerplate reduction options. These should be available with Groovy records (when it makes sense). * Given that Groovy's existing AST transforms work for JDK versions prior to JDK16, Groovy's record functionality can allow the creation of _record-like_ classes. Unlike _native_ records, these won't have record information at the bytecode level but will otherwise follow the same conventions as native records. Such classes will store record information using annotations. They will be recognised by the Groovy compiler but not a Java compiler. * Given that records are primarily designed to be data aggregates, Groovy records are `@CompileStatic` by default. === Groovy special features * Support Groovy's named-parameter syntax * Support Groovy's `getAt` method for positional access of components * Support Groovy's default parameter concept * Support additional helper methods found in other languages, e.g. Kotlin data classes and Scala case classes. Candidates include `copyWith`, `size`, `toMap`, `toList`. * Support destructuring of records ==== Initial implementation * Provide a `@RecordType` annotation collector which collects existing AST transforms suitable for providing the desired functionality. * Provide a `@RecordBase` AST transform which encapsulates any special treatment not found in existing transforms. * Provide a `@RecordOptions` annotation which allows the constructed record implementation to be customised. * Provide support for the `record` keyword in the grammar which can be used instead of the `@RecordType` annotation. == References and useful links * https://openjdk.org/jeps/395[JEP 395: Records] * https://openjdk.org/jeps/384[JEP 384: Records (Second Preview)] * https://openjdk.org/jeps/359[JEP 359: Records (Preview)] * https://docs.oracle.com/en/java/javase/16/language/records.html[Record Classes] Java documentation * https://kotlinlang.org/docs/data-classes.html[Kotlin data classes] * https://docs.scala-lang.org/tour/case-classes.html[Scala case classes] === Reference implementation https://github.com/apache/groovy/pull/1375 https://github.com/apache/groovy/pull/1633 https://github.com/apache/groovy/pull/1645 === JIRA issues * https://issues.apache.org/jira/browse/GROOVY-9754[GROOVY-9754: Provide a record-like equivalent] * https://issues.apache.org/jira/browse/GROOVY-10240[GROOVY-10240: Support record grammar] * https://issues.apache.org/jira/browse/GROOVY-10298[GROOVY-10298: Refine records to not use system properties] * https://issues.apache.org/jira/browse/GROOVY-10338[GROOVY-10338: Enhance records with additional helper methods] == Update history 1 (2021-10-26) Initial draft 2 (2021-11-06) Update to align with 4.0.0-beta-2

GEP-14