blob: 66d30ec971632c36b103834cdd1d701f446e2ddf [file] [log] [blame]
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--><head>
<meta charset='utf-8'/><meta http-equiv='X-UA-Compatible' content='IE=edge'/><meta name='viewport' content='width=device-width, initial-scale=1'/><title>The Apache Groovy programming language - Developer docs - GEP-14</title><link href='../img/favicon.ico' type='image/x-ico' rel='icon'/><link rel='stylesheet' type='text/css' href='../css/bootstrap.css'/><link rel='stylesheet' type='text/css' href='../css/font-awesome.min.css'/><link rel='stylesheet' type='text/css' href='../css/style.css'/><link rel='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css'/>
</head><body>
<div id='fork-me'>
<a href='https://github.com/apache/groovy'>
<img style='position: fixed; top: 20px; right: -58px; border: 0; z-index: 100; transform: rotate(45deg);' src='/img/horizontal-github-ribbon.png'/>
</a>
</div><div id='st-container' class='st-container st-effect-9'>
<nav class='st-menu st-effect-9' id='menu-12'>
<h2 class='icon icon-lab'>Socialize</h2><ul>
<li>
<a href='https://groovy-lang.org/mailing-lists.html' class='icon'><span class='fa fa-envelope'></span> Discuss on the mailing-list</a>
</li><li>
<a href='https://twitter.com/ApacheGroovy' class='icon'><span class='fa fa-twitter'></span> Groovy on Twitter</a>
</li><li>
<a href='https://groovy-lang.org/events.html' class='icon'><span class='fa fa-calendar'></span> Events and conferences</a>
</li><li>
<a href='https://github.com/apache/groovy' class='icon'><span class='fa fa-github'></span> Source code on GitHub</a>
</li><li>
<a href='https://groovy-lang.org/reporting-issues.html' class='icon'><span class='fa fa-bug'></span> Report issues in Jira</a>
</li><li>
<a href='http://stackoverflow.com/questions/tagged/groovy' class='icon'><span class='fa fa-stack-overflow'></span> Stack Overflow questions</a>
</li><li>
<a href='http://groovycommunity.com/' class='icon'><span class='fa fa-slack'></span> Slack Community</a>
</li>
</ul>
</nav><div class='st-pusher'>
<div class='st-content'>
<div class='st-content-inner'>
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]--><div><div class='navbar navbar-default navbar-static-top' role='navigation'>
<div class='container'>
<div class='navbar-header'>
<button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>
<span class='sr-only'></span><span class='icon-bar'></span><span class='icon-bar'></span><span class='icon-bar'></span>
</button><a class='navbar-brand' href='../index.html'>
<i class='fa fa-star'></i> Apache Groovy
</a>
</div><div class='navbar-collapse collapse'>
<ul class='nav navbar-nav navbar-right'>
<li class=''><a href='https://groovy-lang.org/learn.html'>Learn</a></li><li class=''><a href='https://groovy-lang.org/documentation.html'>Documentation</a></li><li class=''><a href='/download.html'>Download</a></li><li class=''><a href='https://groovy-lang.org/support.html'>Support</a></li><li class=''><a href='/'>Contribute</a></li><li class=''><a href='https://groovy-lang.org/ecosystem.html'>Ecosystem</a></li><li class=''><a href='/blog'>Blog posts</a></li><li class=''><a href='https://groovy.apache.org/events.html'></a></li><li>
<a data-effect='st-effect-9' class='st-trigger' href='#'>Socialize</a>
</li><li class=''>
<a href='../search.html'>
<i class='fa fa-search'></i>
</a>
</li>
</ul>
</div>
</div>
</div><div id='content' class='page-1'><div class='row'><div class='row-fluid'><div class='col-lg-3'><ul class='nav-sidebar'><li class='active'><a href='#doc'>GEP-14</a></li><li><a href='#_abstract' class='anchor-link'>Abstract</a></li><li><a href='#_references_and_useful_links' class='anchor-link'>References and useful links</a></li><li><a href='#_update_history' class='anchor-link'>Update history</a></li></ul></div><div class='col-lg-8 col-lg-pull-0'><a name='doc'></a><h1>GEP-14</h1><hr/><div id="preamble">
<div class="sectionbody">
<div class="sidebarblock">
<div class="content">
<div class="title">Metadata</div>
<div class="hdlist">
<table>
<tr>
<td class="hdlist1">
<strong>Number</strong>
</td>
<td class="hdlist2">
<p>GEP-14</p>
</td>
</tr>
<tr>
<td class="hdlist1">
<strong>Title</strong>
</td>
<td class="hdlist2">
<p>Record classes</p>
</td>
</tr>
<tr>
<td class="hdlist1">
<strong>Version</strong>
</td>
<td class="hdlist2">
<p>1</p>
</td>
</tr>
<tr>
<td class="hdlist1">
<strong>Type</strong>
</td>
<td class="hdlist2">
<p>Feature</p>
</td>
</tr>
<tr>
<td class="hdlist1">
<strong>Status</strong>
</td>
<td class="hdlist2">
<p>Draft</p>
</td>
</tr>
<tr>
<td class="hdlist1">
<strong>Leader</strong>
</td>
<td class="hdlist2">
<p>Paul King</p>
</td>
</tr>
<tr>
<td class="hdlist1">
<strong>Created</strong>
</td>
<td class="hdlist2">
<p>2021-10-26</p>
</td>
</tr>
<tr>
<td class="hdlist1">
<strong>Last modification</strong>&#160;
</td>
<td class="hdlist2">
<p>2021-10-26</p>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_abstract">Abstract</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Record classes, or <em>records</em> 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 <code>@Immutable</code> and <code>@Canonical</code>
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.</p>
</div>
<div class="sect2">
<h3 id="_motivation">Motivation</h3>
<div class="paragraph">
<p>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.:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">record Point3D(int x, int y, int z) { }</code></pre>
</div>
</div>
<div class="paragraph">
<p>or:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">record Person(String firstName, String lastName) { }</code></pre>
</div>
</div>
<div class="paragraph">
<p>Such classes have automatic <code>toString</code>, <code>hashCode</code> and <code>equals</code> methods
and an automatic tuple constructor. All of these factor into account the
properties (known as record components) of the class.</p>
</div>
</div>
<div class="sect2">
<h3 id="_requirements">Requirements</h3>
<div class="paragraph">
<p>The main requirement is to provide equivalent functionality to Java record classes when compiling on suitable JDK versions (16+).
By <em>equivalent functionality</em>, the following aspects are relevant:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Support reduced ceremony when writing records.</p>
</li>
<li>
<p>Store appropriate information at the bytecode level so that Groovy records are recognised by Java.
We refer to classes with such bytecode information as <em>native</em> records.</p>
</li>
<li>
<p>Maintain Java syntax compatibility where possible including the compact constructor syntax.</p>
</li>
</ul>
</div>
<div class="sect3">
<h4 id="_non_goals">Non-goals</h4>
<div class="ulist">
<ul>
<li>
<p>Provide native record support on versions of the JDK which supported records in preview mode</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_design_considerations">Design considerations</h3>
<div class="ulist">
<ul>
<li>
<p>Numerous Groovy AST transforms already provide functionality that overlaps with some features of Java records, e.g. <code>@ToString</code>
helps reduce ceremony by offering a declarative mechanism to achieve an <em>automatic</em> <code>toString</code> method.
Where it makes sense, Groovy&#8217;s record implementation should leverage such existing functionality.</p>
</li>
<li>
<p>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.</p>
</li>
<li>
<p>Groovy&#8217;s existing AST transforms offer additional customization options and additional boilerplate reduction options.
These should be available with Groovy records (when it makes sense).</p>
</li>
<li>
<p>Given that Groovy&#8217;s existing AST transforms work for JDK versions prior to JDK16, Groovy&#8217;s record functionality can
allow the creation of <em>record-like</em> classes. Unlike <em>native</em> records, these won&#8217;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.</p>
</li>
<li>
<p>Given that records are primarily designed to be data aggregates, Groovy records are <code>@CompileStatic</code> by default.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_groovy_special_features">Groovy special features</h3>
<div class="ulist">
<ul>
<li>
<p>Support Groovy&#8217;s named-parameter syntax</p>
</li>
<li>
<p>Support Groovy&#8217;s <code>getAt</code> method for positional access of components</p>
</li>
<li>
<p>Support Groovy&#8217;s default parameter concept</p>
</li>
<li>
<p>Support additional helper methods found in other languages, e.g. Kotlin data classes and Scala case classes. Candidates include <code>copyWith</code>, <code>size</code>, <code>toMap</code>, <code>toList</code>.</p>
</li>
<li>
<p>Support destructuring of records</p>
</li>
</ul>
</div>
<div class="sect3">
<h4 id="_initial_implementation">Initial implementation</h4>
<div class="ulist">
<ul>
<li>
<p>Provide a <code>@RecordType</code> annotation collector which collects
existing AST transforms suitable for providing the desired functionality.</p>
</li>
<li>
<p>Provide a <code>@RecordBase</code> AST transform which encapsulates any special
treatment not found in existing transforms.</p>
</li>
<li>
<p>Provide a <code>@RecordOptions</code> annotation which allows the constructed
record implementation to be customised.</p>
</li>
<li>
<p>Provide support for the <code>record</code> keyword in the grammar which can be used
instead of the <code>@RecordType</code> annotation.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_references_and_useful_links">References and useful links</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://openjdk.java.net/jeps/395">JEP 395: Records</a></p>
</li>
<li>
<p><a href="https://openjdk.java.net/jeps/384">JEP 384: Records (Second Preview)</a></p>
</li>
<li>
<p><a href="https://openjdk.java.net/jeps/359">JEP 359: Records (Preview)</a></p>
</li>
<li>
<p><a href="https://docs.oracle.com/en/java/javase/16/language/records.html">Record Classes</a> Java documentation</p>
</li>
<li>
<p><a href="https://kotlinlang.org/docs/data-classes.html">Kotlin data classes</a></p>
</li>
<li>
<p><a href="https://docs.scala-lang.org/tour/case-classes.html">Scala case classes</a></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_reference_implementation">Reference implementation</h3>
<div class="paragraph">
<p><a href="https://github.com/apache/groovy/pull/1375" class="bare">https://github.com/apache/groovy/pull/1375</a>
<a href="https://github.com/apache/groovy/pull/1633" class="bare">https://github.com/apache/groovy/pull/1633</a>
<a href="https://github.com/apache/groovy/pull/1645" class="bare">https://github.com/apache/groovy/pull/1645</a></p>
</div>
</div>
<div class="sect2">
<h3 id="_jira_issues">JIRA issues</h3>
<div class="ulist">
<ul>
<li>
<p><a href="https://issues.apache.org/jira/browse/GROOVY-9754">GROOVY-9754: Provide a record-like equivalent</a></p>
</li>
<li>
<p><a href="https://issues.apache.org/jira/browse/GROOVY-10240">GROOVY-10240: Support record grammar</a></p>
</li>
<li>
<p><a href="https://issues.apache.org/jira/browse/GROOVY-10298">GROOVY-10298: Refine records to not use system properties</a></p>
</li>
<li>
<p><a href="https://issues.apache.org/jira/browse/GROOVY-10338">GROOVY-10338: Enhance records with additional helper methods</a></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_update_history">Update history</h2>
<div class="sectionbody">
<div class="paragraph">
<p>1 (2021-10-26) Initial draft
2 (2021-11-06) Update to align with 4.0.0-beta-2</p>
</div>
</div>
</div></div></div></div></div><footer id='footer'>
<div class='row'>
<div class='colset-3-footer'>
<div class='col-1'>
<h1>Groovy</h1><ul>
<li><a href='https://groovy-lang.org/learn.html'>Learn</a></li><li><a href='https://groovy-lang.org/documentation.html'>Documentation</a></li><li><a href='/download.html'>Download</a></li><li><a href='https://groovy-lang.org/support.html'>Support</a></li><li><a href='/'>Contribute</a></li><li><a href='https://groovy-lang.org/ecosystem.html'>Ecosystem</a></li><li><a href='/blog'>Blog posts</a></li><li><a href='https://groovy.apache.org/events.html'></a></li>
</ul>
</div><div class='col-2'>
<h1>About</h1><ul>
<li><a href='https://github.com/apache/groovy'>Source code</a></li><li><a href='https://groovy-lang.org/security.html'>Security</a></li><li><a href='https://groovy-lang.org/learn.html#books'>Books</a></li><li><a href='https://groovy-lang.org/thanks.html'>Thanks</a></li><li><a href='http://www.apache.org/foundation/sponsorship.html'>Sponsorship</a></li><li><a href='https://groovy-lang.org/faq.html'>FAQ</a></li><li><a href='https://groovy-lang.org/search.html'>Search</a></li>
</ul>
</div><div class='col-3'>
<h1>Socialize</h1><ul>
<li><a href='https://groovy-lang.org/mailing-lists.html'>Discuss on the mailing-list</a></li><li><a href='https://twitter.com/ApacheGroovy'>Groovy on Twitter</a></li><li><a href='https://groovy-lang.org/events.html'>Events and conferences</a></li><li><a href='https://github.com/apache/groovy'>Source code on GitHub</a></li><li><a href='https://groovy-lang.org/reporting-issues.html'>Report issues in Jira</a></li><li><a href='http://stackoverflow.com/questions/tagged/groovy'>Stack Overflow questions</a></li><li><a href='http://groovycommunity.com/'>Slack Community</a></li>
</ul>
</div><div class='col-right'>
<p>
The Groovy programming language is supported by the <a href='http://www.apache.org'>Apache Software Foundation</a> and the Groovy community.
</p><div text-align='right'>
<img src='../img/asf_logo.png' title='The Apache Software Foundation' alt='The Apache Software Foundation' style='width:60%'/>
</div><p>Apache&reg; and the Apache feather logo are either registered trademarks or trademarks of The Apache Software Foundation.</p>
</div>
</div><div class='clearfix'>&copy; 2003-2023 the Apache Groovy project &mdash; Groovy is Open Source: <a href='http://www.apache.org/licenses/LICENSE-2.0.html' alt='Apache 2 License'>license</a>, <a href='https://privacy.apache.org/policies/privacy-policy-public.html'>privacy policy</a>.</div>
</div>
</footer></div>
</div>
</div>
</div>
</div><script src='../js/vendor/jquery-1.10.2.min.js' defer></script><script src='../js/vendor/classie.js' defer></script><script src='../js/vendor/bootstrap.js' defer></script><script src='../js/vendor/sidebarEffects.js' defer></script><script src='../js/vendor/modernizr-2.6.2.min.js' defer></script><script src='../js/plugins.js' defer></script><script src='https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.js'></script><script>document.addEventListener('DOMContentLoaded',prettyPrint)</script><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-257558-10', 'auto');
ga('send', 'pageview');
</script>
</body></html>