GEP-14
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.:
record Point3D(int x, int y, int z) { }
or:
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 automatictoString
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
Reference implementation
Update history
1 (2021-10-26) Initial draft 2 (2021-11-06) Update to align with 4.0.0-beta-2