| <!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-12</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-12</a></li><li><a href='#_abstract_sam_coercion' class='anchor-link'>Abstract: SAM coercion</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-12</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-12</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Title</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>SAM coercion</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Version</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>4</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>Final</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Leader</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>Jochen "blackdrag" Theodorou</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Created</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>2013-05-30</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Last modification</strong>  |
| </td> |
| <td class="hdlist2"> |
| <p>2018-10-29</p> |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_abstract_sam_coercion">Abstract: SAM coercion</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>SAM stands for Single Abstract Method. |
| A SAM type is an abstract class or interface with a single abstract method. |
| SAM coercion involves transforming a |
| <code>groovy.lang.Closure</code> instance into an object suitable for our SAM type. |
| The coercion can happen as part of an assignment or as the result of a method call. |
| Since this transformation might be outside the types provided by Closure itself, |
| it can be more than a simple Java style cast. |
| Closure becomes a kind of subtype to all SAM types. |
| Groovy has other such transformations without explicit cast or asType usage, |
| which are number object transformations as well as the conversion of GString to String.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_motivation">Motivation</h3> |
| <div class="paragraph"> |
| <p>Even before Java8 we had discussions about supporting different interfaces with Closure like Runnable and Callable. |
| These two being easy cases, any framework can define a myriad of interfaces and abstract classes. |
| This then requires to "groovify" the library by writing a helper layer capable of transforming Closure |
| objects into something the library then understand. While it is unlikely of this approach to make Groovy |
| Builder surplus, it can still help with a more simple integration.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_meaning_of_single_abstract_method">Meaning of "Single Abstract Method"</h4> |
| <div class="paragraph"> |
| <p>For a SAM type to be a SAM type according to this GEP an abstract class or interface with a single |
| abstract method is required. Any static methods, as well as non-abstract methods are not counted. |
| The abstract method may be defined in the SAM class itself, but it can also be a parent. |
| The required visibility modifier for the method is public though.</p> |
| </div> |
| <div class="paragraph"> |
| <p>SAM examples:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Simple Interface:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface SAM { |
| def foo() |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Interface with defender method (aka virtual extension method):</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface SAM { |
| def foo() |
| def bar() default { 1 } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Interface inheriting from another interface:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface ParentOfSAM {} |
| interface SAM extends ParentOfSAM { |
| def foo() |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Interface inheriting from another interface, but not defining a method on its own:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface ParentOfSAM { |
| def foo() |
| } |
| interface SAM extends ParentOfSAM {}</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>simple abstract class</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>abstract class SAM { |
| abstract foo() |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>abstract class with an abstract and a non-abstract method:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>abstract class SAM { |
| abstract foo() |
| def bar() { 1 } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>abstract class extending other class:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>abstract class ParentOfSAM1 { |
| abstract foo() |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>abstract class SAM1 extends ParentOfSAM1 {}</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>class ParentOfSAM { |
| def bar() { 1 } |
| } |
| abstract class SAM2 extends { |
| abstract foo() |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>abstract class implementing interface:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface SomeInterface{ |
| def foo() |
| } |
| abstract class SAM1 implements SomeInterface {} |
| abstract class SAM2 implements Runnable{} |
| interface AnotherInterface {} |
| abstract class SAM3 implements AnotherInterface { |
| abstract foo() |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Non-SAM examples:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>empty interface:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface SomeMarker {}</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>interface with two methods:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface TwoMethods { |
| def foo() |
| def bar() |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>abstract class with two abstract methods:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>abstract class TwoMethods { |
| abstract foo() |
| abstract bar() |
| }</code></pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>empty abstract class:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>abstract class Empty {}</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_influence_on_method_selection">Influence on method selection</h4> |
| <div class="paragraph"> |
| <p>The normal method selection algorithm tries to find the most specific method to the given argument |
| runtime types and the most general for null. Since a SAM type and a target method parameter type |
| are not in an inheritance relation "most specific" needs a redefinition in parts. |
| It will be assumed the SAM type is like a direct child of the given target type, |
| but if the SAM type is one implemented by Closure (Runnable and Callable), |
| then no SAM coercion will be needed. This case is preferred in method selection. |
| In case of an overloaded method, where each can be used as target for the SAM coercion, |
| method selection will thus fail, regardless their internal relation. |
| In Groovy the actual method signature of the SAM type and the coercion target are not important. |
| Also it is not important if the target type is an abstract class or an interface.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example of two SAM targets with failing runtime method selection:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface SAM1 { def foo(String s)} |
| interface SAM2 { def bar(Integer i)} |
| def method(x, SAM1 s1){s1.foo(x)} |
| def method(x, SAM2 s2){s2.bar(x)} |
| method (1) {it} // fails because SAM1 and SAM2 are seen as equal |
| method ("1") {it} // fails because SAM1 and SAM2 are seen as equal</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Example of SAM type being ignore as a non-coercion case is available:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>interface SAM {def foo(String s)} |
| def method(SAM s) {1} |
| def method(Runnable r) {2} |
| assert method {it} == 2</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_influence_on_static_typing_system">Influence on static typing system</h4> |
| <div class="paragraph"> |
| <p>The Scope for the static type system is split into a basic part for Groovy 2.2 and an extended one |
| for a later version (2.3 or 3.0)</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_groovy_2_2_static_checks">Groovy 2.2 static checks</h4> |
| <div class="paragraph"> |
| <p>The type checking in Groovy 2.2 will be limited to mimic the behavior of normal Groovy. |
| No method signature checks are performed, as well as there will be no additional test or method |
| selection based on the type provided by the open block.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_groovy_2_2_static_checks_2">Groovy 2.2+ static checks</h4> |
| <div class="paragraph"> |
| <p>In later versions of Groovy the static type checker has to be improved to refine method selection by the given type |
| signature through the open block or lambda. A SAM type is then a fitting type for the coercion only if the provided |
| types and the target types in the SAM are matching by number and type itself. A more detailed description can be |
| found here: <a href="http://cr.openjdk.java.net/~dlsmith/jsr335-0.6.1/F.html" class="bare">http://cr.openjdk.java.net/~dlsmith/jsr335-0.6.1/F.html</a></p> |
| </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://web.archive.org/web/20150508054422/http://docs.codehaus.org/display/GroovyJSR/GEP+12+-+SAM+coercion">GEP-12: SAM coercion</a> (web archive link)</p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect2"> |
| <h3 id="_reference_implementation">Reference implementation</h3> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><a href="https://github.com/groovy/groovy-core/commits/SAM" class="bare">https://github.com/groovy/groovy-core/commits/SAM</a> (feature branch on GitHub)</p> |
| </li> |
| </ul> |
| </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-6188">GROOVY-6188: Java8 lambda style coercion for Closure</a></p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_update_history">Update history</h2> |
| <div class="sectionbody"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">3 (2013-07-01)</dt> |
| <dd> |
| <p>Version as extracted from Codehaus wiki</p> |
| </dd> |
| <dt class="hdlist1">4 (2018-10-29)</dt> |
| <dd> |
| <p>Numerous minor tweaks</p> |
| </dd> |
| </dl> |
| </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-2023 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> |