= 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