| <!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-8</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-8</a></li><li><a href='#_abstract_static_type_checking' class='anchor-link'>Abstract: Static Type Checking</a></li><li><a href='#_rationale_static_type_checking_vs_static_compilation' class='anchor-link'>Rationale: Static Type Checking vs Static compilation</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-8</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-8</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Title</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>Static type checking</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Version</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>9</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>Comment</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>Delivered in Groovy 2.0 and enhanced in later versions</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Leader</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>Cédric Champeau</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Created</strong> |
| </td> |
| <td class="hdlist2"> |
| <p>2011-10-08</p> |
| </td> |
| </tr> |
| <tr> |
| <td class="hdlist1"> |
| <strong>Last modification</strong>  |
| </td> |
| <td class="hdlist2"> |
| <p>2018-10-12</p> |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_abstract_static_type_checking">Abstract: Static Type Checking</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>This GEP introduces a new feature in the language known as static type checking. |
| It is often disturbing for developers coming from a statically typed language (say Java) |
| to discover that the Groovy compiler will not complain at compile time:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>when assignments are made on different types</p> |
| </li> |
| <li> |
| <p>when a method doesn’t exist</p> |
| </li> |
| <li> |
| <p>when a property or variable doesn’t exist</p> |
| </li> |
| <li> |
| <p>when returned object type doesn’t match the method signature</p> |
| </li> |
| <li> |
| <p>…​</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>All those are silent because the dynamic nature of the Groovy language makes such code perfectly valid. |
| However, in some situations, a developer may want Groovy to behave like a statically typed language |
| and have the compiler give hints about such "errors". To do this, Groovy must introduce static type checking.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_rationale_static_type_checking_vs_static_compilation">Rationale: Static Type Checking vs Static compilation</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>It is important to make the difference between static type checking and static compilation. |
| The goal of this GEP is to have an option to turn static type checking (STC) on. |
| If STC is activated, the compiler will be more verbose (you will also see the term "grumpy"), |
| but in the end, the generated bytecode and runtime behaviour will be exactly the same as if you |
| did not activate this mode. This is a major difference from an alternate compiler like Groovy++ |
| which will perform STC then produce a different bytecode and therefore produce different runtime semantics. |
| The scope of this GEP is only a static type checker, and therefore should only be considered as a |
| feature which allows developers to write statically checked code, so is an elegant way for example |
| to leverage the Groovy syntax to reduce verbosity of Java code while still getting strongly checked code. |
| Eventually, IDE could support the STC mode and provide information to the developer.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_implementation_details">Implementation details</h3> |
| <div class="sect3"> |
| <h4 id="_development_branch">Development branch</h4> |
| <div class="paragraph"> |
| <p>Since Groovy 2.0-beta-2, code has been merged into master branch. However, if heavy developments are |
| done on the type checker, it is advisable to work on the grumpy branch. It adds an AST transformation |
| named TypeChecked. If set, then the AST transformation will perform type inference and store type |
| information in AST nodes metadata. Eventually, if errors are found, it will add errors to the compiler |
| through a dedicated addStaticTypeError method which basically does the same as the traditional |
| addError method but prefixes the messages with a "Static type checking" message. |
| This is done to help the developer determine whether the error they are seeing is a "plain Groovy" error, |
| or an error thrown by the STC mode.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_the_statictypecheckingtestcase_class">The StaticTypeCheckingTestCase class</h4> |
| <div class="paragraph"> |
| <p>Static type checking behaviour must be tested. As there are tons of possible checks to be done, |
| a base test class provides a framework for testing this mode. |
| Unit tests for static type checking should override this class.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_decisions_made">Decisions made</h3> |
| <div class="sect3"> |
| <h4 id="_about_this_section">About this section</h4> |
| <div class="paragraph"> |
| <p>The goal of this section is to provide code samples which demonstrates in what case the STC transformation |
| will actually complain and what is the expected error message, and serves as a basis to future STC documentation. |
| This section may not be up-to-date, and one should always take a look at the STC unit tests found in the |
| <code>src/test/groovy/transform/stc</code> directory.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Feature</th> |
| <th class="tableblock halign-left valign-top">Example</th> |
| <th class="tableblock halign-left valign-top">Behavior</th> |
| <th class="tableblock halign-left valign-top">Status</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Method does not exist</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def method() { |
| ... |
| } |
| methode() // typo</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Complains about undefined method</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Property does not exist</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>class A { |
| int x |
| } |
| A obj = new A() |
| a.y = 2</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Complains about undefined property "y"</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Assignment type checking</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>int x = 2 |
| x = 'String'</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Assigning a String to an int is forbidden</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Incompatible binary expressions</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>1 + 'string'</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Checks that arguments of a binary expression are compatible (here, no 'plus' method is available</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Possible loss of precision (1/2)</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>long myLong = ... |
| int myInt = myLong</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Complains about possible loss of precision</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Possible loss of precision (2/2)</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>int myInt = 2L</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Will not complain because '2' can be represented as an int</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Arrays components</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>String[] arr = { '1', '2', '3' } |
| arr[2] = 200</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Cannot assign an int value in an array of type String[]</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Method return type check</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>String method() { 'Hello' } |
| int x = method() // return types don't match</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Ensures that assignments are compatible with method return type</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Explicit return type checking</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>int method() { |
| return 'String' // return type is not compatible |
| }</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Ensures that returned value is compatible with declared return type</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implicit return type checking</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>int method() { |
| 'String' // return type is not compatible |
| }</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Ensures that returned value is compatible with declared return type</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implicit toString()</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>String method(String name) { |
| StringBuilder sb = new StringBuilder() |
| sb 'Hi ' << name << '!' |
| }</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implicit call to toString()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Basic type inference</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def str = 'My string' |
| str.toUpperCase() // type of 'str' is inferred</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Method calls as well as property access are checked against inferred type</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Basic flow analysis</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def o |
| ... |
| if (o instanceof String) { |
| o.toUpperCase() // no explicit cast required |
| }</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Casts should not be necessary when type can be inferred from a previous instanceof check</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">DefaultGroovyMethods support</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>'123'.toInteger() // toInteger() is a Groovy extension method</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Method calls can be resolved against Groovy extension methods</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">with</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>class A { |
| int x |
| } |
| def a = new A() |
| a.with { |
| x = 1 |
| }</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Method calls can be resolved against Groovy extension methods</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Categories</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>use (MyStringCategory) { |
| 'string'.methodInStringCategory() |
| }</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Compiler should be aware that extension method is found in a category</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>N/A</strong> (support will be limited as category support is inherently dynamic)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Groovy list constructor</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>Dimension d = [100, 200]</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Type checks the arguments and the number of arguments</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Groovy map constructor</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>Bean myBean = [x: 100, y: 200]</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Type checks the properties and checks for incorrect property names</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Closure parameter types</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def closure = { int x, int y -> x + y } |
| closure(1, 2) |
| closure('1', '2') // complains</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Type checking the arguments when calling a closure</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Closure return type inference</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def closure = { int x, int y -> x + y } |
| int sum = closure(1, 2)</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Closure return type can be inferred from block</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Method return type inference</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def method(int x, int y) { x + y } |
| int sum = method(1, 2)</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Return type can be inferred from a method if the method is itself annotated with @TypeChecked (or class is annotated with @TypeChecked)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Multiple assignments</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def (x, y) = [1, 2]</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">In case of inline declaration, type check arguments</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Multiple assignments from a variable</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def (x, y) = list</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">In case of inline declaration, type check arguments</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Generics</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>List<String> list = [] |
| List<String> list = ['a', 'b', 'c'] |
| List<String> list = [1, 2, 3] // should throw error</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Type checking of generic parameters</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Spread operator</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def list = ['a', 'b', 'c'] |
| list*.toUpperCase()</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Type checking against component type</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Closure shared variables</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock"> |
| <div class="content"> |
| <pre>def x = new Date() |
| def cl = { x = 'hello' } |
| cl() |
| x.toUpperCase() // should throw an error because the toUpperCase() method doesn't belong to both Date and String classes</pre> |
| </div> |
| </div></div></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Type check assignments of closure shared variables. The type checker is required to perform a two-pass verification, |
| in order to check that method calls on a closure shared variables belong to the lowest upper bound of all assignment types.</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Implemented</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_open_discussions">Open discussions</h3> |
| <div class="sect3"> |
| <h4 id="_closure_parameter_type_inference">Closure parameter type inference</h4> |
| <div class="paragraph"> |
| <p>With the current version of the checker, idiomatic constructs like :</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="prettyprint highlight"><code>['a','b','c'].collect { it.toUpperCase() }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Are not properly recognized. You have to explicitly set the type of the "it" parameter inside the closure. |
| It is because the expected parameter types of closures are unknown at compile time. |
| There is a discussion about how to add this type information to source code so that the inference |
| engine can deal with them properly. The implementation of closure parameter type inference requires |
| a change to the method signatures. It will probably not belong to the initial release of the type checker.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_unification_types">Unification Types</h4> |
| <div class="paragraph"> |
| <p>In cases of for example <code>x instanceof A || x instanceof B</code> with A and B being unrelated we could |
| still make an artificial union kind of type, that contains everything present in A and B, |
| to allow those kinds of method calls. The alternative to this is to allow only methods from Object here, |
| which is less interesting. This typing can also be used for multicatch, ensuring that a method call is |
| only valid if it exists on each of the exceptions for the multicatch. |
| In the current implementation (2011-10-14) the multicatch is already expanded at the point @TypeChecked will check. |
| Meaning effectively this already represents a kind of union type, as the same code is in each catch block |
| and thus the method call would fail, if the method is not available on each type. |
| The proposed behaviour is therefore to align the instanceof case with multicatch.</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/20150508041021/http://docs.codehaus.org/display/GroovyJSR/GEP+8+-+Static+type+checking">GEP-8: Static type checking</a> (web archive link with comments)</p> |
| </li> |
| <li> |
| <p><a href="http://blackdragsview.blogspot.com/2011/10/flow-sensitive-typing.html">Flow Sensitive Typing?</a></p> |
| </li> |
| <li> |
| <p><a href="https://web.archive.org/web/20150508040745/http://www.jroller.com/melix/entry/groovy_static_type_checker_status">Groovy static type checker: status update</a> (web archive)</p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect2"> |
| <h3 id="_mailing_list_discussions">Mailing-list discussions</h3> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><a href="https://markmail.org/thread/reou7z35nk64cai5">groovy-user: What to do on assignment?</a> Discussion about the expected behaviour when STC detects a potential error on assignment (for example, possible loose of precision on implicit number casts)</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-5073">GROOVY-5073: GEP-8 - Static type checking</a></p> |
| </li> |
| <li> |
| <p><a href="https://issues.apache.org/jira/browse/GROOVY-3014">GROOVY-3014: add an annotation that forces the compiler to check methods for their existence at compile time</a></p> |
| </li> |
| <li> |
| <p><a href="https://issues.apache.org/jira/browse/GROOVY-5081">GROOVY-5081: Handle explicit and implicit returns</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">8 (2012-02-21)</dt> |
| <dd> |
| <p>Version as extracted from Codehaus wiki</p> |
| </dd> |
| <dt class="hdlist1">9 (2018-10-16)</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'>© 2003-2022 the Apache Groovy project — 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> |