| <!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>  |
| </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’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’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’s existing AST transforms work for JDK versions prior to JDK16, Groovy’s record functionality can |
| allow the creation of <em>record-like</em> classes. Unlike <em>native</em> 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.</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’s named-parameter syntax</p> |
| </li> |
| <li> |
| <p>Support Groovy’s <code>getAt</code> method for positional access of components</p> |
| </li> |
| <li> |
| <p>Support Groovy’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® and the Apache feather logo are either registered trademarks or trademarks of The Apache Software Foundation.</p> |
| </div> |
| </div><div class='clearfix'>© 2003-2024 the Apache Groovy project — 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> |