blob: 0527d905b7c5fb5ca4c2952e57cce9e351f68e18 [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-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='http://groovy-lang.org/mailing-lists.html' class='icon'><span class='fa fa-envelope'></span> Discuss on the mailing-list</a>
</li><li>
<a href='http://groovy-lang.org/groovy-weekly.html' class='icon'><span class='fa fa-envelope-o'></span> Groovy newsletter</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='http://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='http://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='http://groovy-lang.org/learn.html'>Learn</a></li><li class=''><a href='http://groovy-lang.org/documentation.html'>Documentation</a></li><li class=''><a href='/download.html'>Download</a></li><li class=''><a href='http://groovy-lang.org/support.html'>Support</a></li><li class=''><a href='/'>Contribute</a></li><li class=''><a href='http://groovy-lang.org/ecosystem.html'>Ecosystem</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><p>Author: <i/></p><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>&#160;
</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 of the types provided by Closure itself,
it can be more than a simple Java style cast.
Closure becomes a kind of sub type 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 a 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='http://groovy-lang.org/learn.html'>Learn</a></li><li><a href='http://groovy-lang.org/documentation.html'>Documentation</a></li><li><a href='/download.html'>Download</a></li><li><a href='http://groovy-lang.org/support.html'>Support</a></li><li><a href='/'>Contribute</a></li><li><a href='http://groovy-lang.org/ecosystem.html'>Ecosystem</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='http://groovy-lang.org/security.html'>Security</a></li><li><a href='http://groovy-lang.org/learn.html#books'>Books</a></li><li><a href='http://groovy-lang.org/thanks.html'>Thanks</a></li><li><a href='http://www.apache.org/foundation/sponsorship.html'>Sponsorship</a></li><li><a href='http://groovy-lang.org/faq.html'>FAQ</a></li><li><a href='http://groovy-lang.org/search.html'>Search</a></li>
</ul>
</div><div class='col-3'>
<h1>Socialize</h1><ul>
<li><a href='http://groovy-lang.org/mailing-lists.html'>Discuss on the mailing-list</a></li><li><a href='http://groovy-lang.org/groovy-weekly.html'>Groovy newsletter</a></li><li><a href='https://twitter.com/ApacheGroovy'>Groovy on Twitter</a></li><li><a href='http://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='http://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><img src='../img/asf_logo.png' title='The Apache Software Foundation' alt='The Apache Software Foundation' class='img-responsive'/>
</div>
</div><div class='clearfix'>&copy; 2003-2022 the Apache Groovy project &mdash; Groovy is Open Source, <a href='http://www.apache.org/licenses/LICENSE-2.0.html'>Apache 2 License</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>