1. Groovy Language Specification

1.1. Syntax

This chapter covers the syntax of the Groovy programming language. The grammar of the language derives from the Java grammar, but enhances it with specific constructs for Groovy, and allows certain simplifications.

1.1.1. Comments

Single line comment

Single line comments start with // and can be found at any position in the line. The characters following //, till the end of the line, are considered part of the comment.

// a standalone single line comment
println "hello" // a comment till the end of the line
Multiline comment

A multiline comment starts with /* and can be found at any position in the line. The characters following /* will be considered part of the comment, including new line characters, up to the first */ closing the comment. Multiline comments can thus be put at the end of a statement, or even inside a statement.

/* a standalone multiline comment
   spanning two lines */
println "hello" /* a multiline comment starting
                   at the end of a statement */
println 1 /* one */ + 2 /* two */
GroovyDoc comment

Similarly to multiline comments, GroovyDoc comments are multiline, but start with /** and end with */. Lines following the first GroovyDoc comment line can optionally start with a star *. Those comments are associated with:

  • type definitions (classes, interfaces, enums, annotations),

  • fields and properties definitions

  • methods definitions

Although the compiler will not complain about GroovyDoc comments not being associated with the above language elements, you should prepend those constructs with the comment right before it.

/**
 * A Class description
 */
class Person {
    /** the name of the person */
    String name

    /**
     * Creates a greeting method for a certain person.
     *
     * @param otherPerson the person to greet
     * @return ag reeting message
     */
    String greet(String otherPerson) {
       "Hello ${otherPerson}"
    }
}

GroovyDoc follows the same conventions as Java’s own JavaDoc. So you’ll be able to use the same tags as with JavaDoc.

Shebang line

Beside the single line comment, there is a special line comment, often called the shebang line understood by UNIX systems which allows scripts to be run directly from the command-line, provided you have installed the Groovy distribution and the groovy command is available on the PATH.

#!/usr/bin/env groovy
println "Hello from the shebang line"
The # character must be the first character of the file. Any indentation would yield a compilation error.

1.1.2. Keywords

The following list represents all the keywords of the Groovy language:

Table 1. Keywords

as

assert

break

case

catch

class

const

continue

def

default

do

else

enum

extends

false

finally

for

goto

if

implements

import

in

instanceof

interface

new

null

package

return

super

switch

this

throw

throws

true

try

while

1.1.3. Identifiers

Normal identifiers

Identifiers start with a letter, a dollar or an underscore. They cannot start with a number.

A letter can be in the following ranges:

  • a to z (lowercase ascii letter)

  • A to Z (uppercase ascii letter)

  • \u00C0 to \u00D6

  • \u00D8 to \u00F6

  • \u00F8 to \u00FF

  • \u0100 to \uFFFE

Then following characters can contain letters and numbers.

Here are a few examples of valid identifiers (here, variable names):

def name
def item3
def with_underscore
def $dollarStart

But the following ones are invalid identifiers:

def 3tier
def a+b
def a#b

All keywords are also valid identifiers when following a dot:

foo.as
foo.assert
foo.break
foo.case
foo.catch
Quoted identifiers

Quoted identifiers appear after the dot of a dotted expression. For instance, the name part of the person.name expression can be quoted with person."name" or person.'name’. This is particularly interesting when certain identifiers contain illegal characters that are forbidden by the Java Language Specification, but which are allowed by Groovy when quoted. For example, characters like a dash, a space, an exclamation mark, etc.

def map = [:]

map."an identifier with a space and double quotes" = "ALLOWED"
map.'with-dash-signs-and-single-quotes' = "ALLOWED"

assert map."an identifier with a space and double quotes" == "ALLOWED"
assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"

As we shall see in the following section on strings, Groovy provides different string literals. All kind of strings are actually allowed after the dot:

map.'single quote'
map."double quote"
map.'''triple single quote'''
map."""triple double quote"""
map./slashy string/
map.$/dollar slashy string/$

There’s a difference between plain character strings and Groovy’s GStrings (interpolated strings), as in that the latter case, the interpolated values are inserted in the final string for evaluating the whole identifier:

def firstname = "Homer"
map."Simson-${firstname}" = "Homer Simson"

assert map.'Simson-Homer' == "Homer Simson"

1.1.4. Strings

Text literals are represented in the form of chain of characters called strings. Groovy lets you instantiate java.lang.String objects, as well as GStrings (groovy.lang.GString) which are also called interpolated strings in other programming languages.

Single quoted string

Single quoted strings are a series of characters surounded by single quotes:

def firstname = "Homer"
map."Simson-${firstname}" = "Homer Simson"

assert map.'Simson-Homer' == "Homer Simson"
Single quoted strings are plain java.lang.String and don’t support interpolation.
String concatenation

All the Groovy strings can be concatenated with the + operator:

assert 'ab' == 'a' + 'b'
Triple single quoted string

Triple single quoted strings are a series of characters surrounded by single quotes:

'a single quoted string'
Triple single quoted strings are plain java.lang.String and don’t support interpolation.

Triple single quoted strings are multiline. You can span the content of the string across line boundaries without the need to split the string in several pieces, without contatenation or newline escape characters:

def aMultilineString = '''line one
line two
line three'''

If your code is indented, for example in the body of the method of a class, your string will contain the whitespace of the indentation. The Groovy Development Kit contains methods for stripping out the indentation with the String#stripIndent() method, and with the String#stripMargin() method that takes a delimiter character to identify the text to remove from the beginning of a string.

When creating a string as follows:

def startingAndEndingWithANewline = '''
line one
line two
line three
'''

You will notice that the resulting string contains a newline character as first character. It is possible to strip that character by escaping the newline with a backslash:

def strippedFirstNewline = '''\
line one
line two
line three
'''

assert !strippedFirstNewline.startsWith('\n')
Escaping special characters

You can escape single quotes with the the backslash character to avoid terminating the string literal:

'an escaped single quote: \' needs a backslash'

And you can escape the escape character itself with a double backslash:

'an escaped escape character: \\ needs a double backslash'

Some special characters also use the backslash as escape character:

Escape sequence Character

\t

tabulation

\b

backspace

\n

newline

\r

carriage return

\f

formfeed

\\

backslash

\'

single quote (for single quoted and triple single quoted strings)

\"

double quote (for double quoted and triple double quoted strings)

Unicode escape sequence

For characters that are not present on your keyboard, you can use unicode escape sequances: a backslash, followed by u, then 4 hexadecimal digits.

For example, the Euro currency symbol can be represented with:

'The Euro currency symbol: \u20AC'
Double quoted string

Double quoted strings are a series of characters surrounded by double quotes:

"a double quoted string"
Double quoted strings are plain java.lang.String if there’s no interpolated expression, but are groovy.lang.GString instances if interpolation is present.
To escape a double quote, you can use the backslash character: "A double quote: \"".
String interpolation

Any Groovy expression can be interpolated in all string literals, apart from single and triple single quoted strings. Interpolation is the act of replacing a placeholder in the string with its value upon evaluation of the string. The placeholder expressions are surrounded by ${} or prefixed with $ for dotted expressions. The expression value inside the placeholder is evaluated to its string representation when the GString is passed to a method taking a String as argument by calling toString() on that expression.

Here, we have a string with a placeholder referencing a local variable:

def name = 'Guillaume' // a plain string
def greeting = "Hello ${name}"

assert greeting.toString() == 'Hello Guillaume'

But any Groovy expression is valid, as we can see in this example with an arithmetic expression:

def sum = "The sum of 2 and 3 equals ${2 + 3}"
assert sum.toString() == 'The sum of 2 and 3 equals 5'
Not only expressions are actually allowed in between the ${} placeholder. Statements are also allowed, but a statement’s value is just null. So if several statements are inserted in that placeholder, the last one should somehow return a meaningful value to be inserted. For instance, "The sum of 1 and 2 is equal to ${def a = 1; def b = 2; a + b}" is supported and works as expected but a good practice is usually to stick to simple expressions inside GString placeholders.

In addition to ${} placeholders, we can also use a lone $ sign prefixing a dotted expression:

def person = [name: 'Guillaume', age: 36]
assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'

But only dotted expressions of the form a.b, a.b.c, etc, are valid, but expressions that would contain parentheses like method calls, curly braces for closures, or arithmetic operators would be invalid. Given the following variable definition of a number:

def number = 3.14

The following statement will throw a groovy.lang.MissingPropertyException because Groovy believes you’re trying to access the toString property of that number, which doesn’t exist:

shouldFail(MissingPropertyException) {
    println "$number.toString()"
}
You can think of "$number.toString()" as being interpreted by the parser as "${number.toString}()".

If you need to escape the $ or ${} placeholders in a GString so they appear as is without interpolation, you just need to use a \ backslash character to escape the dollar sign:

assert '${name}' == "\${name}"
Special case of interpolating closure expressions

So far, we’ve seen we could interpolate arbitrary expressions inside the ${} placeholder, but there is a special case and notation for closure expressions. When the placeholder contains an arrow, ${→}, the expression is actually a closure expression — you can think of it as a closure with a dollar prepended in front of it:

def sParameterLessClosure = "1 + 2 == ${-> 3}" (1)
assert sParameterLessClosure == '1 + 2 == 3'

def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" (2)
assert sOneParamClosure == '1 + 2 == 3'
1 The closure is a parameterless closure which doesn’t take arguments.
2 Here, the closure takes a single java.io.StringWriter argument, to which you can append content with the << leftShift operator. In either case, both placeholders are embedded closures.

In appearance, it looks like a more verbose way of defining expressions to be interpolated, but closure have an interesting advantage over mere expressions: lazy evaluation.

Let’s consider the following sample:

def number = 1 (1)
def eagerGString = "value == ${number}"
def lazyGString = "value == ${ -> number }"

assert eagerGString == "value == 1" (2)
assert lazyGString ==  "value == 1" (3)

number = 2 (4)
assert eagerGString == "value == 1" (5)
assert lazyGString ==  "value == 2" (6)
1 We define a number variable containing 1 that we then interpolate within two GStrings, as an expression in eagerGString and as a closure in lazyGString.
2 We expect the resulting string to contain the same string value of 1 for eagerGString.
3 Similarily for lazyGString
4 Then we change the value of the variable to a new number
5 With a plain interpolated expression, the value was actually bound at the time of creation of the GString.
6 But with a closure expression, the closure is called upon each coercion of the GString into String, resulting in an updated string containing the new number value.
An embedded closure expression taking more than one parameter will generate an exception at runtime. Only closures with zero or one paramaters are allowed.
Inteoperability with Java

When a method (whether implemented in Java or Groovy) expects a java.lang.String, but we pass a groovy.lang.GString instance, the toString() method of the GString is automatically and transparently called.

String takeString(String message) {         (4)
    assert message instanceof String        (5)
    return message
}

def message = "The message is ${'hello'}"   (1)
assert message instanceof GString           (2)

def result = takeString(message)            (3)
assert result instanceof String
assert result == 'The message is hello'
1 We create a GString variable
2 We double check it’s an instance of the GString
3 We then pass that GString to a method taking a String as parameter
4 The signature of the takeString() method explicitly says its sole parameter is a String
5 We also verify that the parameter is indeed a String and not a GString.
GString and String hashCodes

Although interpolated strings can be used in lieu of plain Java strings, they differ with strings in a particular way: their hashCodes are different. Plain Java strings are immutable, whereas the resulting String representation of a GString can vary, depending on its interpolated values. Even for the same resulting string, GStrings and Strings don’t have the same hashCode.

assert "one: ${1}".hashCode() != "one: 1".hashCode()

GString and Strings having different hashCode values, using GString as Map keys should be avoided, especially if we try to retrieve an associated value with a String instead of a GString.

def key = "a"
def m = ["${key}": "letter ${key}"]     (1)

assert m["a"] == null                   (2)
1 The map is created with an initial pair whose key is a GString
2 When we try to fetch the value with a String key, we will not find it, as Strings and GString have different hashCode values
Triple double quoted string

Triple double quoted strings behave like double quoted strings, with the addition that they are multiline, like the triple single quoted strings.

def name = 'Groovy'
def template = """
    Dear Mr ${name},

    You're the winner of the lottery!

    Yours sincerly,

    Dave
"""

assert template.toString().contains('Groovy')
Neither double quotes nor single quotes need be escaped in triple double quoted strings.
Slashy string

Beyond the usual quoted strings, Groovy offers slashy strings, which use / as delimiters. Slashy strings are particularly useful for defining regular expressions and patterns, as there is no need to escape backslashes.

Example of a slashy string:

def fooPattern = /.*foo.*/
assert fooPattern == '.*foo.*'

Only forward slashes need to be escaped with a backslash:

def escapeSlash = /The character \/ is a forward slash/
assert escapeSlash == 'The character / is a forward slash'

Slashy strings are multiline:

def multilineSlashy = /one
    two
    three/

assert multilineSlashy.contains('\n')

Slashy strings can also be interpolated (ie. a GString):

def color = 'blue'
def interpolatedSlashy = /a ${color} car/

assert interpolatedSlashy == 'a blue car'

There are a few gotchas to be aware of.

An empty slashy string cannot be represented with a double forward slash, as it’s understood by the Groovy parser as a line comment. That’s why the following assert would actually not compile as it would look like a non-terminated statement:

assert '' == //
Dollar slashy string

Dollar slashy strings are multiline GStrings delimited with an opening $/ and and a closing /$. The escaping character is the dollar sign, and it can escape another dollar, or a forward slash. But both dollar and forward slashes don’t need to be escaped, except to escape the dollar of a string subsequence that would start like a GString placeholder sequence, or if you need to escape a sequence that would start like a closing dollar slashy string delimiter.

Here’s an example:

def name = "Guillaume"
def date = "April, 1st"

def dollarSlashy = $/
    Hello $name,
    today we're ${date}.

    $ dollar sign
    $$ escaped dollar sign
    \ backslash
    / forward slash
    $/ escaped forward slash
    $/$ escaped dollar slashy string delimiter
/$

assert [
    'Guillaume',
    'April, 1st',
    '$ dollar sign',
    '$ escaped dollar sign',
    '\\ backslash',
    '/ forward slash',
        '$/ escaped forward slash',
        '/$ escaped dollar slashy string delimiter'

        ].each { dollarSlashy.contains(it) }
String summary table

String name

String syntax

Interpolated

Multiline

Escape character

Single quoted

'…'

\

Triple single quoted

'''…'''

\

Double quoted

"…"

\

Triple double quoted

"""…"""

\

Slashy

/…/

\

Dollar slashy

$/…/$

$

Characters

Unlike Java, Groovy doesn’t have an explicit character literal. However, you can be explicit about making a Groovy string an actual character, by three different means:

char c1 = 'A' (1)
assert c1 instanceof Character

def c2 = 'B' as char (2)
assert c2 instanceof Character

def c3 = (char)'C' (3)
assert c3 instanceof Character
1 by being explicit when declaring a variable holding the character by specifying the char type
2 by using type coercion with the as operator
3 by using a cast to char operation
The first option 1 is interesting when the character is held in a variable, while the other two (2 and 3) are more interesting when a char value must be passed as argument of a method call.

1.1.5. Numbers

Groovy supports different kinds of integral literals and decimal literals, backed by the usual Number types of Java.

Integral literals

The integral literal types are the same as in Java:

  • byte

  • char

  • short

  • int

  • long

  • java.lang.BigInteger

You can create integral numbers of those types with the following declarations:

// primitive types
byte  b = 1
char  c = 2
short s = 3
int   i = 4
long  l = 5

// infinite precision
BigInteger bi =  6

If you use optional typing by using the def keyword, the type of the integral number will vary: it’ll adapt to the capacity of the type that can hold that number.

For positive numbers:

def a = 1
assert a instanceof Integer

// Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer

// Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof Long

// Long.MAX_VALUE
def d = 9223372036854775807
assert d instanceof Long

// Long.MAX_VALUE + 1
def e = 9223372036854775808
assert e instanceof BigInteger

As well as for negative numbers:

def na = -1
assert na instanceof Integer

// Integer.MIN_VALUE
def nb = -2147483648
assert nb instanceof Integer

// Integer.MIN_VALUE - 1
def nc = -2147483649
assert nc instanceof Long

// Long.MIN_VALUE
def nd = -9223372036854775808
assert nd instanceof Long

// Long.MIN_VALUE - 1
def ne = -9223372036854775809
assert ne instanceof BigInteger
Alternative non-base 10 representations
Binary literal

In Java 6 and before, as well as in Groovy, numbers could be represented in decimal, octal and hexadecimal bases, and with Java 7 and Groovy 2, you can use a binary notation with the 0b prefix:

int xInt = 0b10101111
assert xInt == 175

short xShort = 0b11001001
assert xShort == 201 as short

byte xByte = 0b11
assert xByte == 3 as byte

long xLong = 0b101101101101
assert xLong == 2925l

BigInteger xBigInteger = 0b111100100001
assert xBigInteger == 3873g

int xNegativeInt = -0b10101111
assert xNegativeInt == -175
Octal literal

Octal numbers are specified in the typical format of 0 followed by octal digits.

int xInt = 077
assert xInt == 63

short xShort = 011
assert xShort == 9 as short

byte xByte = 032
assert xByte == 26 as byte

long xLong = 0246
assert xLong == 166l

BigInteger xBigInteger = 01111
assert xBigInteger == 585g

int xNegativeInt = -077
assert xNegativeInt == -63
Hexadecimal literal

Hexadecimal numbers are specified in the typical format of 0x followed by hex digits.

int xInt = 0x77
assert xInt == 119

short xShort = 0xaa
assert xShort == 170 as short

byte xByte = 0x3a
assert xByte == 58 as byte

long xLong = 0xffff
assert xLong == 65535l

BigInteger xBigInteger = 0xaaaa
assert xBigInteger == 43690g

Double xDouble = new Double('0x1.0p0')
assert xDouble == 1.0d

int xNegativeInt = -0x77
assert xNegativeInt == -119
Decimal literals

The decimal literal types are the same as in Java:

  • float

  • double

  • java.lang.BigDecimal

You can create decimal numbers of those types with the following declarations:

// primitive types
float  f = 1.234
double d = 2.345

// infinite precision
BigDecimal bd =  3.456

Decimals can use exponents, with the e or E exponent letter, followed by an optional sign, and a integral number representing the exponent:

assert 1e3  ==  1_000.0
assert 2E4  == 20_000.0
assert 3e+1 ==     30.0
assert 4E-2 ==      0.04
assert 5e-1 ==      0.5

Conveniently for exact decimal number calculations, Groovy choses java.lang.BigDecimal as its decimal number type. In addition, both float and double are supported, but require an explicit type declaration, type coercion or suffix. Even if BigDecimal is the default for decimal numbers, such literals are accepted in methods or closures taking float or double as parameter types.

Decimal numbers can’t be represented using a binary, octal or hexadecimal representation.
Underscore in literals

When writing long literal numbers, it’s harder on the eye to figure out how some numbers are grouped together, for example with groups of thousands, of words, etc. By allowing you to place underscore in number literals, it’s easier to spot those groups:

long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010
Number type suffixes

We can force a number (including binary, octals and hexadecimals) to have a specific type by giving a suffix (see table bellow), either uppercase or lowercase.

Type Suffix

BigInteger

G or g

Long

L or l

Integer

I or i

BigDecimal

G or g

Double

D or d

Float

F or f

Examples:

assert 42I == new Integer('42')
assert 42i == new Integer('42') // lowercase i more readable
assert 123L == new Long("123") // uppercase L more readable
assert 2147483648 == new Long('2147483648') // Long type used, value too large for an Integer
assert 456G == new BigInteger('456')
assert 456g == new BigInteger('456')
assert 123.45 == new BigDecimal('123.45') // default BigDecimal type used
assert 1.200065D == new Double('1.200065')
assert 1.234F == new Float('1.234')
assert 1.23E23D == new Double('1.23E23')
assert 0b1111L.class == Long // binary
assert 0xFFi.class == Integer // hexadecimal
assert 034G.class == BigInteger // octal
Math operations

Although operators are covered later on, it’s important to discuss the behavior of math operations and what their resulting types are.

Division and power binary operations aside (covered below),

  • binary operations between byte, char, short and int result in int

  • binary operations involving long with byte, char, short and int result in long

  • binary operations involving BigInteger and any other integral type result in BigInteger

  • binary operations between float, double and BigDecimal result in double

  • binary operations between two BigDecimal result in BigDecimal

The following table summarizes those rules:

byte char short int long BigInteger float double BigDecimal

byte

int

int

int

int

long

BigInteger

double

double

double

char

int

int

int

long

BigInteger

double

double

double

short

int

int

long

BigInteger

double

double

double

int

int

long

BigInteger

double

double

double

long

long

BigInteger

double

double

double

BigInteger

BigInteger

double

double

double

float

double

double

double

double

double

double

BigDecimal

BigDecimal

Thanks Groovy’s operator overloading, the usual arithmetic operators work as well with BigInteger and BigDecimal, unlike in Java where you have to use explict methods for operating on those numbers.
The case of the division operator

The division operators / (and /= for division and assignment) produce a double result if either operand is a float or double, and a BigDecimal result otherwise (when both operands are any combination of an integral type short, char, byte, int, long, BigInteger or BigDecimal).

BigDecimal division is performed with the divide() method if the division is exact (ie. yielding a result that can be represented within the bounds of the same precision and scale), or using a MathContext with a precision of the maximum of the two operands’ precision plus an extra precision of 10, and a scale of the maximum of 10 and the maximum of the operands’ scale.

For integer division like in Java, you should use the intdiv() method, as Groovy doesn’t provide a dedicated integer division operator symbol.
The case of the power operator

The power operation is represented by the ** operator, with two parameters: the base and the exponent. The result of the power operation depends on its operands, and the result of the operation (in particular if the result can be represented as an integral value).

The following rules are used by Groovy’s power operation to determine the resulting type:

  • If the exponent is a decimal value

    • if the result can be represented as an Integer, then return an Integer

    • else if the result can be represented as a Long, then return a Long

    • otherwise return a Double

  • If the exponent is an integral value

    • if the exponent is strictly negative, then return an Integer, Long or Double if the result value fits in that type

    • if the exponent is positive or zero

      • if the base is a BigDecimal, then return a BigDecimal result value

      • if the base is a BigInteger, then return a BigInteger result value

      • if the base is an Integer, then return an Integer if the result value fits in it, otherwise a BigInteger

      • if the base is a Long, then return a Long if the result value fits in it, otherwise a BigInteger

We can illustrate those rules with a few examples:

// base and exponent are ints and the result can be represented by an Integer
assert    2    **   3    instanceof Integer    //  8
assert   10    **   9    instanceof Integer    //  1_000_000_000

// the base is a long, so fit the result in a Long
// (although it could have fit in an Integer)
assert    5L   **   2    instanceof Long       //  25

// the result can't be represented as an Integer or Long, so return a BigInteger
assert  100    **  10    instanceof BigInteger //  10e20
assert 1234    ** 123    instanceof BigInteger //  170515806212727042875...

// the base is a BigDecimal and the exponent a negative int
// but the result can be represented as an Integer
assert    0.5  **  -2    instanceof Integer    //  4

// the base is an int, and the exponent a negative float
// but again, the result can be represented as an Integer
assert    1    **  -0.3f instanceof Integer    //  1

// the base is an int, and the exponent a negative int
// but the result will be calculated as a Double
// (both base and exponent are actually converted to doubles)
assert   10    **  -1    instanceof Double     //  0.1

// the base is a BigDecimal, and the exponent is an int, so return a BigDecimal
assert    1.2  **  10    instanceof BigDecimal //  6.1917364224

// the base is a float or double, and the exponent is an int
// but the result can only be represented as a Double value
assert    3.4f **   5    instanceof Double     //  454.35430372146965
assert    5.6d **   2    instanceof Double     //  31.359999999999996

// the exponent is a decimal value
// and the result can only be represented as a Double value
assert    7.8  **   1.9  instanceof Double     //  49.542708423868476
assert    2    **   0.1f instanceof Double     //  1.0717734636432956

1.1.6. Booleans

Boolean is a special data type that is used to represent truth values: true and false. Use this data type for simple flags that track true/false conditions.

Boolean values can be stored in variables, assigned into fields, just like any other data type:

def myBooleanVariable = true
boolean untypedBooleanVar = false
booleanField = true

true and false are the only two primitive boolean values. But more complex boolean expressions can be represented using logical operators.

In addition, Groovy has special rules (often referred to as Groovy Truth) for coercing non-boolean objects to a boolean value.

1.1.7. Lists

Groovy uses a comma-separated list of values, surrounded by square brackets, to denote lists. Groovy lists are plain JDK java.util.List, as Groovy doesn’t define its own collection classes. The concrete list implementation used when defining list literals are java.util.ArrayList by default, unless you decide to specify otherwise, as we shall see later on.

def numbers = [1, 2, 3]         (1)

assert numbers instanceof List  (2)
assert numbers.size() == 3      (3)
1 We define a list numbers delimited by commas and surrounded by square brackets, and we assign that list into a variable
2 The list is an instance of Java’s java.util+List interface
3 The size of the list can be queried with the size() method, and shows our list contains 3 elements

In the above example, we used a homogeneous list, but you can also create lists containing values of heterogeneous types:

def heterogeneous = [1, "a", true]  (1)
1 Our list here contains a number, a string and a boolean value

We mentioned that by default, list literals are actually instances of java.util.ArrayList, but it is possible to use a different backing type for our lists, thanks to using type coercion with the as operator, or with explicit type declaration for your variables:

def arrayList = [1, 2, 3]
assert arrayList instanceof java.util.ArrayList

def linkedList = [2, 3, 4] as LinkedList    (1)
assert linkedList instanceof java.util.LinkedList

LinkedList otherLinked = [3, 4, 5]          (2)
assert otherLinked instanceof java.util.LinkedList
1 We use coercion with the as operator to explicitly request a java.util.LinkedList implementation
2 We can say that the variable holding the list literal is of type java.util.LinkedList

You can access elements of the list with the [] subscript operator (both for reading and setting values) with positive indices or negative indices to access elements from the end of the list, as well as with ranges, and use the << leftShift operator to append elements to a list:

def letters = ['a', 'b', 'c', 'd']

assert letters[0] == 'a'     (1)
assert letters[1] == 'b'

assert letters[-1] == 'd'    (2)
assert letters[-2] == 'c'

letters[2] = 'C'             (3)
assert letters[2] == 'C'

letters << 'e'               (4)
assert letters[ 4] == 'e'
assert letters[-1] == 'e'

assert letters[1, 3] == ['b', 'd']         (5)
assert letters[2..4] == ['C', 'd', 'e']    (6)
1 Access the first element of the list (zeroth-based counting)
2 Access the last element of the list with a negative index: -1 is the first element from the end of the list
3 Use an assignment to set a new value for the third element of the list
4 Use the << leftShift operator to append an element at the end of the list
5 Access two elements at once, returning a new list containing those two elements
6 Use a range to access a range of values from the list, from a start to an end element position

As lists can be heterogeneous in nature, lists can also contain other lists to create multi-dimensional lists:

def multi = [[0, 1], [2, 3]]     (1)
assert multi[1][0] == 2          (2)
1 Define a list of list of numbers
2 Access the second element of the top-most list, and the first element of the inner list

1.1.8. Arrays

Groovy reuses the list notation for arrays, but to make such literals arrays, you need to explicitely define the type of the array through coercion or type declaration.

String[] arrStr = ['Ananas', 'Banana', 'Kiwi']  (1)

assert arrStr instanceof String[]    (2)
assert !(arrStr instanceof List)     (3)

def numArr = [1, 2, 3] as int[]      (4)

assert numArr instanceof int[]       (5)
assert numArr.size() == 3
1 Define an array of strings using explicit variable type declaration
2 Assert that we created an array of strings
3 Create an array of ints with the as operator
4 Assert that we created an array of primitive ints

You can also create multi-dimensional arrays:

def matrix3 = new Integer[3][3]         (1)
assert matrix3.size() == 3

Integer[][] matrix2                     (2)
matrix2 = [[1, 2], [3, 4]]
assert matrix2 instanceof Integer[][]
1 You can define the bounds of a new array
2 Or declare an array without specifying its bounds

Access to elements of an array follows the same notation as for lists:

String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul']
assert names[0] == 'Cédric'     (1)

names[2] = 'Blackdrag'          (2)
assert names[2] == 'Blackdrag'
1 Retrieve the first element of the array
2 Set the value of the third element of the array to a new value
Java’s array initializer notation is not supported by Groovy, as the curly braces can be misinterpreted with the notation of Groovy closures.

1.1.9. Maps

Sometimes called dictionaries or associative arrays in other languages, Groovy features maps. Maps associate keys to values, separating keys and values with colons, and each key/value pairs with commas, and the whole keys and values surrounded by square brackets.

def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']   (1)

assert colors['red'] == '#FF0000'    (2)
assert colors.green  == '#00FF00'    (3)

colors['pink'] = '#FF00FF'           (4)
colors.yellow  = '#FFFF00'           (5)

assert colors.pink == '#FF00FF'
assert colors['yellow'] == '#FFFF00'

assert colors instanceof java.util.LinkedHashMap
1 We define a map of string color names, associated with their hexadecimal-coded html colors
2 We use the subscript notation to check the content associated with the red key
3 We can also use the property notation to assert the color green’s hexadecimal representation
4 Similarily, we can use the subscript notation to add a new key/value pair
5 Or the property notation, to add the yellow color
When using names for the keys, we actually define string keys in the map.
Groovy creates maps that are actually instances of java.util.LinkedHashMap.

If you try to access a key which is not present in the map:

assert colors.unknown == null

You will retrieve a null result.

In the examples above, we used string keys, but you can also use values of other types as keys:

def numbers = [1: 'one', 2: 'two']

assert numbers[1] == 'one'

Here, we used numbers as keys, as numbers can unambiguously be recognized as numbers, so Groovy will not create a string key like in our previous examples. But consider the case you want to pass a variable in lieu of the key, to have the value of that variable become the key:

def key = 'name'
def person = [key: 'Guillaume']      (1)

assert !person.containsKey('name')   (2)
assert person.containsKey('key')     (3)
1 The key associated with the 'Guillaume’ name will actually be the "key" string, not the value associated with the key variable
2 The map doesn’t contain the 'name’ key
3 Instead, the map contains a 'key’ key
You can also pass quoted strings as well as keys: ["name": "Guillaume"]. This is mandatory if your key string isn’t a valid identifier, for example if you wanted to create a string key containing a hash like in: ["street-name": "Main street"].

When you need to pass variable values as keys in your map definitions, you must surround the variable or expression with parentheses:

person = [(key): 'Guillaume']        (1)

assert person.containsKey('name')    (2)
assert !person.containsKey('key')    (3)
1 This time, we surround the key variable with parentheses, to instruct the parser we are passing a variable rather than defining a string key
2 The map does contain the name key
3 But the map doesn’t contain the key key as before

1.2. Operators

This chapter covers the operators of the Groovy programming language.

1.2.1. Arithmetic operators

Groovy supports the usual familiar arithmetic operators you find in mathematics and in other programming languages like Java. All the Java arithmetic operators are supported. Let’s go through them in the following examples.

Normal arithmetic operators

The following binary arithmetic operators are available in Groovy:

Operator Purpose Remarks

+

addition

-

substraction

*

multiplication

/

division

Use intdiv() for integer division, and see the section about the integer division for more information on the return type of the division.

%

modulo

**

power

See the section about the power operation for more information on the return type of the operation.

Here are a few examples of usage of those operators:

assert  1  + 2 == 3
assert  4  - 3 == 1
assert  3  * 5 == 15
assert  3  / 2 == 1.5
assert 10  % 3 == 1
assert  2 ** 3 == 8
Unary operators

The + and - operators are also available as unary operators:

assert +3 == 3
assert -4 == 0 - 4

assert -(-1) == 1  (1)
1 Note the usage of parentheses to surround an expression to apply the unary minus to that surrounded expression.

In terms of unary arithmetics operators, the ++ (increment) and -- (decrement) operators are available, both in prefix and postfix notation:

def a = 2
def b = a++ * 3             (1)

assert a == 3 && b == 6

def c = 3
def d = c-- * 2             (2)

assert c == 2 && d == 6

def e = 1
def f = ++e + 3             (3)

assert e == 2 && f == 5

def g = 4
def h = --g + 1             (4)

assert g == 3 && h == 4
1 The postfix increment will increment a after the expression has been evaluated and assigned into b
2 The postfix decrement will decrement c after the expression has been evaluated and assigned into d
3 The prefix increment will increment e before the expression is evaluated and assigned into f
4 The prefix decrement will decrement g before the expression is evaluated and assigned into h
Assignment arithmetic operators

From the binary arithmetic operators we have seen above, certain of them are also available in an assignment form:

  • +=

  • -=

  • *=

  • /=

  • %=

Let’s see them in action:

def a = 4
a += 3

assert a == 7

def b = 5
b -= 3

assert b == 2

def c = 5
c *= 3

assert c == 15

def d = 10
d /= 2

assert d == 5

def e = 10
e %= 3

assert e == 1

1.2.2. Relational operators

Relational operators allow comparisons between objects, to know if two objects are the same or different, or if one is greater or lower than or equal to the other.

The following operators are available:

Operator Purpose

==

equal

!=

different

<

less than

<=

less than or equal

>

greater than

>=

greater than or equal

These operators into action in simple number comparisons:

assert 1 + 2 == 3
assert 3 != 4

assert -2 < 3
assert 2 <= 2
assert 3 <= 4

assert 5 > 1
assert 5 >= -2

1.2.3. Logical operators

Groovy offers three logical operators for boolean expressions:

  • &&: logical "and"

  • ||: logical "or"

  • !: logical "not"

Let’s illustrate them with the following examples:

assert !false           (1)
assert true && true     (2)
assert true || false    (3)
1 "not" false is true
2 true "and" true is true
3 true "or" false is true
Precedence

The logical "not" has a higher priority than the logical "and".

assert !false && true    (1)
1 Here, the assertion is true, because "not" has a higher precedence than "and", otherwise, the assertion would have failed

The logical "and" has a higher priority than the logical "or".

assert false || true && true    (1)
1 Here, the assertion is true, because "and" has a higher precedence than "or", otherwise, the assertion would have failed
Short-circuiting for ||

The logical "or" operator is supporting short-circuiting: if the left operand is true, it won’t evaluate the right operand. The right operand will be evaluated only if the left operand is false.

called = false

boolean somethingTrueOrFalse(boolean b) {  (1)
    called = true
    return b
}

assert true || somethingTrueOrFalse(false)
assert !called                              (2)

assert false || somethingTrueOrFalse(true)
assert called                               (3)
1 We create a function that returns its boolean argument, but it sets the called flag
2 In the first case, we confirm that the function is not called, as || short-circuits the evaluation of the right operand.
3 In the second case, the right operand is called, as indicated by the fact our flag is now true

1.2.4. Bitwise operators

Groovy offers 4 bitwise operators:

  • &: bitwise "and"

  • |: bitwise "or"

  • ^: bitwise "xor" (exclusive "or")

  • ~: bitwise negation

Bitwise operators can be applied on a byte or an int and return an int:

int a = 0b00101010
assert a==42
int b = 0b00001000
assert b==8
assert (a & a) == a                     (1)
assert (a & b) == b                     (2)
assert (a | a) == a                     (3)
assert (a | b) == a                     (4)

int mask = 0b11111111                   (5)
assert ((a ^ a) & mask) == 0b00000000   (6)
assert ((a ^ b) & mask) == 0b00100010   (7)
assert ((~a) & mask)    == 0b11010101   (8)
1 bitwise and
2 bitwise and returns common bits
3 bitwise or
4 bitwise or returns all 1 bits
5 setting a mask to check only the last 8 bits
6 bitwise exclusive or on self returns 0
7 bitwise exclusive or
8 bitwise negation

It’s worth noting that the internal representation of primitive types follow the Java Language Specification. In particular, primitive types are signed, meaning that for a bitwise negation, it is always good to use a mask to retrieve only the necessary bits.

In Groovy, bitwise operators have the particularity of being overloadable, meaning that you can define the behavior of those operators for any kind of object.

1.2.5. Conditional operators

Not operator

The "not" operator is represented with an exclamation mark (!) and inverts the result of the underlying boolean expression. In particular, it is possible to combine the not operator with the Groovy truth:

assert (!true)    == false                      (1)
assert (!'foo')   == false                      (2)
assert (!'')      == true                       (3)
1 the negation of true is false
2 foo is a non empty string, evaluating to true, so negation returns false
3 '' is an empty string, evaluating to false, so negation returns true
Ternary operator

The ternary operator is a shortcut expression that is equivalent to an if/else branch assigning some value to a variable.

Instead of:

if (string!=null && string.length()>0) {
    result = 'Found'
} else {
    result = 'Not found'
}

You can write:

result = (string!=null && string.length()>0)?'Found':'Not found'

The ternary operator is also compatible with the Groovy truth, so you can make it even simpler:

result = string?'Found':'Not found'
Elvis operator

The "Elvis operator" is a shortening of the ternary operator. One instance of where this is handy is for returning a sensible default value if an expression resolves to false or null. A simple example might look like this:

displayName = user.name ? user.name : 'Anonymous'   (1)
displayName = user.name ?: 'Anonymous'              (2)
1 with the ternary operator, you have to repeat the value you want to assign
2 with the Elvis operator, the value which is tested is used if it is not false or null

Usage of the Elvis operator reduces the verbosity of your code and reduces the risks of errors in case of refactorings, by removing the need to duplicate the expression which is tested in both the condition and the positive return value.

1.2.6. Object operators

Safe navigation operator

The Safe Navigation operator is used to avoid a NullPointerException. Typically when you have a reference to an object you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator will simply return null instead of throwing an exception, like so:

def person = Person.find { it.id == 123 }           (1)
def name = person?.name                             (2)
assert name == null                                 (3)
1 find will return a null instance
2 use of the null-safe operator prevents from a NullPointerException
3 result is null
Direct field access operator

Normally in Groovy, when you write code like this:

class User {
    public final String name                               (1)
    User(String name) { this.name = name}
    String getName() { "Name: $name" }                     (2)
}
def user = new User('Bob')
assert user.name == 'Name: Bob'                            (3)
1 public field name
2 a getter for name that returns a custom string
3 calls the getter

The user.name call triggers a call to the property of the same name, that is to say, here, to the getter for name. If you want to retrieve the field instead of calling the getter, you can use the direct field access operator:

assert user.@name == 'Bob'                                 (1)
1 use of .@ forces usage of the field instead of the getter
Method reference operator

The method reference operator (.&) call be used to store a reference to a method in a variable, in order to call it later:

def str = 'example of method reference'            (1)
def fun = str.&toUpperCase                         (2)
def upper = fun()                                  (3)
assert upper == str.toUpperCase()                  (4)
1 the str variable contains a String
2 we store a reference to the toUpperCase method on the str instance inside a variable named fun
3 fun can be called like a regular method
4 we can check that the result is the same as if we had called it directly on str

There are multiple advantages in using method references. First of all, the type of such a method reference is a groovy.lang.Closure, so it can be used in any place a closure would be used. In particular, it is suitable to convert an existing method for the needs of the strategy pattern:

def transform(List elements, Closure action) {                                      (1)
    def result = []
    elements.each {
        result << action(it)
    }
    result
}
String describe(Person p) {                                                         (2)
    "$p.name is $p.age"
}
def action = this.&describe                                                         (3)
def list = [new Person(name:'Bob', age:42), new Person(name:'Julia',age:35)]        (4)
assert transform(list, action) == ['Bob is 42', 'Julia is 35']                      (5)
1 the transform method takes each element of the list and calls the action closure on them, returning a new list
2 we define a function that takes a Person a returns a String
3 we create a method reference on that function
4 we create the list of elements we want to collect the descriptors
5 the method reference can be used where a Closure was expected

Method references are bound by the receiver and a method name. Arguments are resolved at runtime, meaning that if you have multiple methods with the same name, the syntax is not different, only resolution of the appropriate method to be called will be done at runtime:

def doSomething(String str) { str.toUpperCase() }                                   (1)
def doSomething(Integer x) { 2*x }                                                  (2)
def reference = this.&doSomething                                                   (3)
assert reference('foo') == 'FOO'                                                    (4)
assert reference(123)   == 246                                                      (5)
1 define an overloaded doSomething method accepting a String as an argument
2 define an overloaded doSomething method accepting an Integer as an argument
3 create a single method reference on doSomething, without specifying argument types
4 using the method reference with a String calls the String version of doSomething
5 using the method reference with an Integer calls the Integer version of doSomething

1.2.7. Regular expression operators

Pattern operator

The pattern operator (~) provides a simple way to create a java.util.regex.Pattern instance:

def p = ~/foo/
assert p instanceof Pattern

while in general, you find the pattern operator with an expression in a slashy-string, it can be used with any kind of String in Groovy:

p = ~'foo'                                                                              (1)
p = ~'foo'                                                                              (2)
p = ~$/dollar/slashy $ string/$                                                         (3)
p = ~"${pattern}"                                                                       (4)
1 using single quote strings
2 using double quotes strings
3 the dollar-slashy string lets you use slashes and the dollar sign without having to escape them
4 you can also use a GString!
Find operator

Alternatively to building a pattern, you can directly use the find operator =~ to build a java.util.regex.Matcher instance:

def text = "some text to match"
def m = text =~ /match/                                                                 (1)
assert m instanceof Matcher                                                             (2)
if (!m) {                                                                               (3)
    throw new RuntimeException("Oops, text not found!")
}
1 ~= creates a matcher against the text variable, using the pattern on the right hand side
2 the return type of ~= is a Matcher
3 equivalent to calling if (!m.find())

Since a Matcher coerces to a boolean by calling its find method, the =~ operator is consistent with the simple use of Perl’s =~ operator, when it appears as a predicate (in if, while, etc.).

Match operator

The match operator (==~) is a slight variation of the find operator, that does not return a Matcher but a boolean and requires a strict match of the input string:

m = text ==~ /match/                                                                    (1)
assert m instanceof Boolean                                                             (2)
if (m) {                                                                                (3)
    throw new RuntimeException("Should not reach that point!")
}
1 ~== matches the subject with the regular expression, but match must be strict
2 the return type of ~== is therefore a boolean
3 equivalent to calling if (text ==~ /match/)

1.2.8. Other operators (WIP)

Spread operator

The Spread Operator (*.) is used to invoke an action on all items of an aggregate object. It is equivalent to calling the action on each item and collecting the result into a list:

class Car {
    String make
    String model
}
def cars = [
       new Car(make:'Peugeot', model:'508'),
       new Car(make:'Renault', model:'Clio')]                                    (1)
def makes = cars*.make                                                           (2)
assert makes == ['Peugeot', 'Renault']                                           (3)
1 build a list of Car items. The list is an aggregate of objects.
2 call the spread operator on the list, accessing the make property of each item
3 returns a list of strings corresponding to the collection of make items

The spread operator is null-safe, meaning that if an element of the collection is null, it will return null instead of throwing a NullPointerException:

cars = [
   new Car(make:'Peugeot', model:'508'),
   null,                                                                         (1)
   new Car(make:'Renault', model:'Clio')]
assert cars*.make == ['Peugeot', null, 'Renault']                                (2)
assert null*.make == null                                                        (3)
1 build a list for which of of the elements is null
2 using the spread operator will not throw a NullPointerException
3 the receiver might also be null, in which case the return value is null

The spread operator can be used on any class which implements the Iterable interface:

class Component {
    Long id
    String name
}
class CompositeObject implements Iterable<Component> {
    def components = [
        new Component(id:1, name: 'Foo'),
        new Component(id:2, name:'Bar')]

    @Override
    Iterator<Component> iterator() {
        components.iterator()
    }
}
def composite = new CompositeObject()
assert composite*.id == [1,2]
assert composite*.name == ['Foo','Bar']
Spreading method arguments

There may be situations when the arguments of a method call can be found in a list that you need to adapt to the method arguments. In such situations, you can use the spread operator to call the method. For example, imagine you have the following method signature:

int function(int x, int y, int z) {
    x*y+z
}

then if you have the following list:

def args = [4,5,6]

you can call the method without having to define intermediate variables:

assert function(*args) == 26

It is even possible to mix normal arguments with spread ones:

args = [4]
assert function(*args,5,6) == 26
Spread list elements

When used inside a list literal, the spread operator acts as if the spread element contents were inlined into the list:

def items = [4,5]                      (1)
def list = [1,2,3,*items,6]            (2)
assert list == [1,2,3,4,5,6]           (3)
1 items is a list
2 we want to insert the contents of the items list directly into list without having to call addAll
3 the contents of items has been inlined into list
Spread map elements

The spread map operator works in a similar manner as the spread list operator, but for maps. It allows you to inline the contents of a map into another map literal, like in the following example:

def m1 = [c: 3, d: 4]                 (1)
def map = [a:1, b:2, *:m1]            (2)
assert map == [a:1, b:2, c:3, d:4]    (3)
1 m1 is the map that we want to inline
2 we use the *:m1 notation to spread the contents of m1 into map
3 map contains all the elements of m1

The position of the spread map operator is relevant, like illustrated in the following example:

def m1 = [c: 3, d: 4]                 (1)
def map = [a:1, b:2, *:m1, d: 8]      (2)
assert map == [a:1, b:2, c:3, d:8]    (3)
1 m1 is the map that we want to inline
2 we use the *:m1 notation to spread the contents of m1 into map, but redefine the key d after spreading
3 map contains all the expected keys, but d was redefined
Range operator

Groovy supports the concept of ranges and provides a notation (..) to create ranges of objects:

def range = 0..5                                    (1)
assert (0..5).collect() == [0, 1, 2, 3, 4, 5]       (2)
assert (0..<5).collect() == [0, 1, 2, 3, 4]         (3)
assert (0..5) instanceof List                       (4)
assert (0..5).size() == 6                           (5)
1 a simple range of integers, stored into a local variable
2 an IntRange, with inclusive bounds
3 an IntRange, with exclusive upper bound
4 a groovy.lang.Range implements the List interface
5 meaning that you can call the size method on it

Ranges implementation is lightweight, meaning that only the lower and upper bounds are stored. You can create a range from any Comparable object. For example, you can create a range of characters this way:

assert ('a'..'d').collect() == ['a','b','c','d']
Spaceship operator

The spaceship operator (<=>) delegates to the compareTo method:

assert (1 <=> 1) == 0
assert (1 <=> 2) == -1
assert (2 <=> 1) == 1
assert ('a' <=> 'z') == -1
Subscript operator

The subscript operator is a short hand notation for getAt or putAt, depending on whether you find it on the left hand side or the right hand side of an assignment:

def list = [0,1,2,3,4]
assert list[2] == 2                         (1)
list[2] = 4                                 (2)
assert list[0..2] == [0,1,4]                (3)
list[0..2] = [6,6,6]                        (4)
assert list == [6,6,6,3,4]                  (5)
1 [2] can be used instead of getAt(2)
2 if on left hand side of an assignment, will call putAt
3 getAt also supports ranges
4 so does putAt
5 the list is mutated

The subscript operator, in combination with a custom implementation of getAt/putAt is a convenient way for destructuring objects:

class User {
    Long id
    String name
    def getAt(int i) {                                                  (1)
        switch (i) {
            case 0: return id
            case 1: return name
        }
        throw new IllegalArgumentException("No such element $i")
    }
    void putAt(int i, def value) {                                      (2)
        switch (i) {
            case 0: id = value; return
            case 1: name = value; return
        }
        throw new IllegalArgumentException("No such element $i")
    }
}
def user = new User(id: 1, name: 'Alex')                                (3)
assert user[0] == 1                                                     (4)
assert user[1] == 'Alex'                                                (5)
user[1] = 'Bob'                                                         (6)
assert user.name == 'Bob'                                               (7)
1 the User class defines a custom getAt implementation
2 the User class defines a custom putAt implementation
3 create a sample user
4 using the subscript operator with index 0 allows retrieving the user id
5 using the subscript operator with index 1 allows retrieving the user name
6 we can use the subscript operator to write to a property thanks to the delegation to putAt
7 and check that it’s really the property name which was changed
Membership operator

The membership operator (in) is equivalent to calling the isCase method. In the context of a List, it is equivalent to calling contains, like in the following example:

def list = ['Grace','Rob','Emmy']
assert ('Emmy' in list)                     (1)
1 equivalent to calling list.contains('Emmy') or list.isCase('Emmy')
Identity operator

In Groovy, using == to test equality is different from using the same operator in Java. In Groovy, it is calling equals. If you want to compare reference equality, you should use is like in the following example:

def list1 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']        (1)
def list2 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']        (2)
assert list1 == list2                                       (3)
assert !list1.is(list2)                                     (4)
1 Create a list of strings
2 Create another list of strings containing the same elements
3 using ==, we test object equality
4 but using is, we can check that references are distinct
Coercion operator

The coercion operator (as) is a variant of casting. Coercion converts object from one type to another without them being compatible for assignement. Let’s take an example:

Integer x = 123
String s = (String) x                                   (1)
1 Integer is not assignable to a String, so it will produce a ClassCastException at runtime

This can be fixed by using coercion instead:

Integer x = 123
String s = x as String                                  (1)
1 Integer is not assignable to a String, but use of as will coerce it to a String

When an object is coerced into another, unless the target type is the same as the source type, coercion will return a new object. The rules of coercion differ depending on the source and target types, and coercion may fail if no conversion rules are found. Custom conversion rules may be implemented thanks to the asType method:

class Identifiable {
    String name
}
class User {
    Long id
    String name
    def asType(Class target) {                                              (1)
        if (target==Identifiable) {
            return new Identifiable(name: name)
        }
        throw new ClassCastException("User cannot be coerced into $target")
    }
}
def u = new User(name: 'Xavier')                                            (2)
def p = u as Identifiable                                                   (3)
assert p instanceof Identifiable                                            (4)
assert !(p instanceof User)                                                 (5)
1 the User class defines a custom conversion rule from User to Identifiable
2 we create an instance of User
3 we coerce the User instance into an Identifiable
4 the target is an instance of Identifiable
5 the target is not an instance of User anymore
Diamond operator

The diamond operator (<>) is a syntactic sugar only operator added to support compatibility with the operator of the same name in Java 7. It is used to indicate that generic types should be inferred from the declaration:

List<String> strings = new LinkedList<>()

In dynamic Groovy, this is totally unused. In statically type checked Groovy, it is also optional since the Groovy type checker performs type inference whether this operator is present or not.

Call operator

The call operator () is used to call a method named call implicitly. For any object which defines a call method, you can omit the .call part and use the call operator instead:

class MyCallable {
    int call(int x) {           (1)
        2*x
    }
}

def mc = new MyCallable()
assert mc.call(2) == 4          (2)
assert mc(2) == 4               (3)
1 MyCallable defines a method named call. Note that it doesn’t need to implement java.util.concurrent.Callable
2 we can call the method using the classic method call syntax
3 or we can omit .call thanks to the call operator

1.2.9. Operator precedence (TBD)

1.2.10. Operator overloading

Groovy allows you to overload the various operators so that they can be used with your own classes. Consider this simple class:

class Bucket {
    int size

    Bucket(int size) { this.size = size }

    Bucket plus(Bucket other) {                     (1)
        return new Bucket(this.size + other.size)
    }
}
1 Bucket implements a special method called plus()

Just by implementing the plus() method, the Bucket class can now be used with the + operator like so:

def b1 = new Bucket(4)
def b2 = new Bucket(11)
assert (b1 + b2).size == 15                         (1)
1 The two Bucket objects can be added together with the + operator

All (non-comparator) Groovy operators have a corresponding method that you can implement in your own classes. The only requirements are that your method is public, has the correct name, and has the correct number of arguments. The argument types depend on what types you want to support on the right hand side of the operator. For example, you could support the statement

assert (b1 + 11).size == 15

by implementing the plus() method with this signature:

Bucket plus(int capacity) {
    return new Bucket(this.size + capacity)
}

Here is a complete list of the operators and their corresponding methods:

Operator Method Operator Method

+

a.plus(b)

a[b]

a.getAt(b)

-

a.minus(b)

a[b] = c

a.putAt(b, c)

*

a.multiply(b)

<<

a.leftShift(b)

/

a.div(b)

>>

a.rightShift(b)

%

a.mod(b)

++

a.next()

**

a.power(b)

--

a.previous()

|

a.or(b)

+a

a.positive()

&

a.and(b)

-a

a.negative()

^

a.xor(b)

~a

a.bitwiseNegative()

1.3. Program structure (Anto Aravinth)

This chapter covers the program structure of the Groovy programming language.

1.3.1. Package name (TBD)

1.3.2. Imports (TBD)

Default imports (TBD)
Simple import (TBD)
Star import (TBD)
Static import (TBD)
Static star import (TBD)
Import aliasing (TBD)

1.3.3. Scripts versus classes

Package name plays exactly the same role as they used to play in Java. They allows us to separate the code base without any conflicts. Groovy classes must specify their package before the class definition, else the default package is assumed.

Defining a package is very similar to java, as you can see

//Defines a package named com.yoursite
package com.yoursite

To refer the class Foo in the com.yoursite.com package then you need to use com.yoursite.com.Foo in your code else you can use import statement as we can see now.

1.3.4. Imports

In order to refer any class you need a reference for it. Groovy follows Java’s notion of allowing import statement to resolve the class references. Groovy provides several builder classes, one such class is MarkupBuilder. MarkupBuilder is inside the package groovy.xml, in order to use this class, you need to import it as shown:

//imports the class MarkupBuilder
import groovy.xml.MarkupBuilder

//uses the imported class to create an object
def xml = new MarkupBuilder( )

assert xml != null
Default imports

Default imports are the imports that Groovy language provides by default. For example look at the following code:

new Date()

The same code in Java needs an import statement to Date class like this: import java.util.Date. Groovy by default imports these classes for you. There are six packages that groovy imports for you, they are:

import java.lang.*
import java.util.*
import java.io.*
import java.net.*
import groovy.lang.*
import groovy.util.*
import java.math.BigInteger
import java.math.BigDecimal
Simple import

Simple import is an import, where you fully define the class name along with the package. For example the import statement import groovy.xml.MarkupBuilder in the code below is the simple import, which directly refer the class inside the package.

//imports the class MarkupBuilder
import groovy.xml.MarkupBuilder

//uses the imported class to create an object
def xml = new MarkupBuilder( )

assert xml != null
Star import

Groovy (like Java) provides a special way to import all classes from a package using *, they are called as Star import. MarkupBuilder is class which is in package groovy.xml, another class called StreamingMarkupBuilder is in the same package. Consider the case, where you need to use two classes, then you can do:

import groovy.xml.MarkupBuilder
import groovy.xml.StreamingMarkupBuilder

def markupBuilder = new MarkupBuilder( )

assert markupBuilder != null

assert new StreamingMarkupBuilder() != null

Thats a perfectly valid code. But with * import, we can do the same like this:

import groovy.xml.*

def markupBuilder = new MarkupBuilder( )

assert markupBuilder != null

assert new StreamingMarkupBuilder() != null

where, does imports all the class under package groovy.xml. Using import can clutters your local namespace. But with groovy type aliasing, this can be solved easily.

Static import

Groovy’s static import capability allows you to reference imported classes as if they were static methods in your own class. This is similar to Java’s static import capability but works with Java 1.4 and above and is a little more dynamic than Java in that it allows you to define methods with the same name as an imported method as long as you have different types. If you have the same types, the imported class takes precedence. Here is a sample of its usage:

import static Boolean.FALSE

assert !FALSE //use directly, without Boolean prefix!

As you can see, now we can able to refer the static variable FALSE in our code base cleanly.

Static imports along with as keyword can make elegant solution. Consider you want to get the Calendar instance, using getInstance() method. Its a static method, so we can do a static import. But instead of calling getInstance() everytime, we can do this which can increase code readability:

import static Calendar.getInstance as now

assert now().class == Calendar.getInstance().class

Thats clean and sweet!

Static star import

Its very similar to the star import that we have seen earlier. It will import all the static methods from the given class. For example, lets say we need to calculate sin and cos for our application. The class java.lang.Math has static methods named sin,cos which fits our need. With help of static star import, we can do:

import static java.lang.Math.*

assert sin(0) == 0.0
assert cos(0) == 1.0

As you can see, we were able to access the methods sin,cos directly, instead like Math.sin.

Import aliasing

With type aliasing, we can refer to a fully qualified class name with the name of your choice. This can be done with as keyword in Groovy.

Consider the class with the following library code:

package thirdpartylib

public class MultiplyTwo {
    def static multiply(def value) {
        return value * 3 //intentionally wrong.
    }
}

and we have some existing code using this library:

def result = new MultiplyTwo().multiply(2)

Obviously, the result variable contains the wrong result. And assume you have used this library through out your code-base. Groovy has an elegant way to fix this issue.

With the type aliasing in place, we can fix the bug using the below code:

import thirdpartylib.MultiplyTwo as OrigMultiplyTwo
class MultiplyTwo extends OrigMultiplyTwo {
    def multiply(def value)
    {
        return value * 2 //corrected here
    }
}
// nothing changes below here
def multiplylib = new MultiplyTwo()

//assert passes as well
assert 4 == new MultiplyTwo().multiply(2)

Thats it! Notice how Groovy allowed us to use as keyword to solve the typical problem.

With Type aliasing we can able to solve the name collision problem ( which can occur with * imports) elegantly.

1.3.5. Initializers (TBD)

Static initializers (TBD)
Instance initializers (TBD)

1.4. Object orientation

This chapter covers the object orientation of the Groovy programming language.

1.4.1. Types (TBD)

Primitive types (TBD)
Class (TBD)
Normal class (TBD)
Static class (TBD)
Inner class (TBD)
Anonymous inner class (TBD)
Abstract class (TBD)
Interface (TBD)
Annotation (TBD)
Closure annotation parameters (TBD)
Meta-annotations (TBD)
Annotation placement (TBD)
Constructors (TBD)
Named argument constructor (TBD)
Methods (TBD)
Method definition (TBD)
Named arguments (TBD)
Default arguments (TBD)
Varargs (TBD)
Method selection algorithm (TBD)
Exception declaration (TBD)
Fields and properties (TBD)
Fields (TBD)
Properties (TBD)
Inheritance (TBD)
Generics (TBD)

1.4.2. Traits

Traits are a a structural construct of the language which allow:

  • composition of behaviors

  • runtime implementation of interfaces

  • behavior overriding

  • compatibility with static type checking/compilation

They can be seen as interfaces carrying both default implementations and state. A trait is defined using the trait keyword:

trait FlyingAbility {                           (1)
        String fly() { "I'm flying!" }          (2)
}
1 declaration of a trait
2 declaration of a method inside a trait

Then it can be used like a normal interface using the implements keyword:

class Bird implements FlyingAbility {}          (1)
def b = new Bird()                              (2)
assert b.fly() == "I'm flying!"                 (3)
1 Adds the trait FlyingAbility to the Bird class capabilities
2 instantiate a new Bird
3 the Bird class automatically gets the behavior of the FlyingAbility trait

Traits allow a wide range of capabilities, from simple composition to testing, which are described throughfully in this section.

Methods
Public methods

Declaring a method in a trait can be done like any regular method in a class:

trait FlyingAbility {                           (1)
        String fly() { "I'm flying!" }          (2)
}
1 declaration of a trait
2 declaration of a method inside a trait
Abstract methods

In addition, traits may declare abstract methods too, which therefore need to be implemented in the class implementing the trait:

trait Greetable {
    abstract String name()                              (1)
    String greeting() { "Hello, ${name()}!" }           (2)
}
1 implementing class will have to declare the name method
2 can be mixed with a concrete method

Then the trait can be used like this:

class Person implements Greetable {                     (1)
    String name() { 'Bob' }                             (2)
}

def p = new Person()
assert p.greeting() == 'Hello, Bob!'                    (3)
1 implement the trait Greetable
2 since name was abstract, it is required to implement it
3 then greeting can be called
Private methods

Traits may also define private methods. Those methods will not appear in the trait contract interface:

trait Greeter {
    private String greetingMessage() {                      (1)
        'Hello from a private method!'
    }
    String greet() {
        def m = greetingMessage()                           (2)
        println m
        m
    }
}
class GreetingMachine implements Greeter {}                 (3)
def g = new GreetingMachine()
assert g.greet() == "Hello from a private method!"          (4)
try {
    assert g.greetingMessage()                              (5)
} catch (MissingMethodException e) {
    println "greetingMessage is private in trait"
}
1 define a private method greetingMessage in the trait
2 the public greet message calls greetingMessage by default
3 create a class implementing the trait
4 greet can be called
5 but not greetingMessage
Traits only support public and private methods. Neither protected nor package private scopes are supported.
The meaning of this

this represents the implementing instance. Think of a trait as a superclass. This means that when you write:

trait Introspector {
    def whoAmI() { this }
}
class Foo implements Introspector {}
def foo = new Foo()

then calling:

foo.whoAmI()

will return the same instance:

assert foo.whoAmI().is(foo)
Interfaces

Traits may implement interfaces, in which case the interfaces are declared using the implements keyword:

interface Named {                                       (1)
    String name()
}
trait Greetable implements Named {                      (2)
    String greeting() { "Hello, ${name()}!" }
}
class Person implements Greetable {                     (3)
    String name() { 'Bob' }                             (4)
}

def p = new Person()
assert p.greeting() == 'Hello, Bob!'                    (5)
assert p instanceof Named                               (6)
assert p instanceof Greetable                           (7)
1 declaration of a normal interface
2 add Named to the list of implemented interfaces
3 declare a class that implements the Greetable trait
4 implement the missing greet method
5 the greeting implementation comes from the trait
6 make sure Person implements the Named interface
7 make sure Person implements the Greetable trait
Properties

A trait may define properties, like in the following example:

trait Named {
    String name                             (1)
}
class Person implements Named {}            (2)
def p = new Person(name: 'Bob')             (3)
assert p.name == 'Bob'                      (4)
assert p.getName() == 'Bob'                 (5)
1 declare a property name inside a trait
2 declare a class which implements the trait
3 the property is automatically made visible
4 it can be accessed using the regular property accessor
5 or using the regular getter syntax
Fields
Private fields

Since traits allow the use of private methods, it can also be interesting to use private fields to store state. Traits will let you do that:

trait Counter {
    private int count = 0                   (1)
    int count() { count += 1; count }       (2)
}
class Foo implements Counter {}             (3)
def f = new Foo()
assert f.count() == 1                       (4)
This is a major difference with Java 8 virtual extension methods. While virtual extension methods do not carry state, traits can. Also interesting traits in Groovy are supported starting with Java 6, but their implementation do not rely on virtual extension methods. This means that even if a trait can be seen from a Java class as a regular interface, this interface will not have default methods, only abstract ones.
Public fields

Public fields work the same way as private fields, but in order to avoid the diamond problem, field names are remapped in the implementing class:

trait Named {
    public String name                      (1)
}
class Person implements Named {}            (2)
def p = new Person()                        (3)
p.Named__name = 'Bob'                       (4)
1 declare a public field inside the trait
2 declare a class implementing the trait
3 create an instance of that class
4 the public field is available, but renamed

The name of the field depends on the fully qualified name of the trait. All dots (.) in package are replaced with an underscore (_), and the final name includes a double underscore. So if the type of the field is String, the name of the package is my.package, the name of the trait is Foo and the name of the field is bar, in the implementing class, the public field will appear as:

String my_package_Foo__bar
While traits support public fields, it is not recommanded to use them and considered as a bad practice.
Composition of behaviors

Traits can be used to implement multiple inheritance in a controlled way, avoiding the diamond issue. For example, we can have the following traits:

trait FlyingAbility {                           (1)
        String fly() { "I'm flying!" }          (2)
}
trait SpeakingAbility {
    String speak() { "I'm speaking!" }
}

And a class implementing both traits:

class Duck implements FlyingAbility, SpeakingAbility {} (1)

def d = new Duck()                                      (2)
assert d.fly() == "I'm flying!"                         (3)
assert d.speak() == "I'm speaking!"                     (4)
1 the Duck class implements both FlyingAbility and SpeakingAbility
2 creates a new instance of Duck
3 we can call the method fly from FlyingAbility
4 but also the method speak from SpeakingAbility

Traits encourage the reuse of capabilities among objects, and the creation of new classes by the composition of existing behavior.

Overriding default methods

Traits provide default implementations for methods, but it is possible to override them in the implementing class. For example, we can slightly change the example above, by having a duck which quacks:

class Duck implements FlyingAbility, SpeakingAbility {
    String quack() { "Quack!" }                         (1)
    String speak() { quack() }                          (2)
}

def d = new Duck()
assert d.fly() == "I'm flying!"                         (3)
assert d.quack() == "Quack!"                            (4)
assert d.speak() == "Quack!"                            (5)
1 define a method specific to Duck, named quack
2 override the default implementation of speak so that we use quack instead
3 the duck is still flying, from the default implementation
4 quack comes from the Duck class
5 speak no longer uses the default implementation from SpeakingAbility
Extending traits
Simple inheritance

Traits may extend another trait, in which case you must use the extends keyword:

trait Named {
    String name                                     (1)
}
trait Polite extends Named {                        (2)
    String introduce() { "Hello, I am $name" }      (3)
}
class Person implements Polite {}
def p = new Person(name: 'Alice')                   (4)
assert p.introduce() == 'Hello, I am Alice'         (5)
1 the Named trait defines a single name property
2 the Polite trait extends the Named trait
3 Polite adds a new method which has access to the name property of the super-trait
4 the name property is visible from the Person class implementing Polite
5 as is the introduce method
Multiple inheritance

Alternatively, a trait may extend multiple traits. In that case, all super traits must be declared in the implements clause:

trait WithId {                                      (1)
    Long id
}
trait WithName {                                    (2)
    String name
}
trait Identified implements WithId, WithName {}     (3)
1 WithId trait defines the id property
2 WithName trait defines the name property
3 Identified is a trait which inherits both WithId and WithName
Duck typing and traits
Dynamic code

Traits can call any dynamic code, like a normal Groovy class. This means that you can, in the body of a method, call methods which are supposed to exist in an implementing class, without having to explicitly declare them in an interface. This means that traits are fully compatible with duck typing:

trait SpeakingDuck {
    String speak() { quack() }                      (1)
}
class Duck implements SpeakingDuck {
    String methodMissing(String name, args) {
        "${name.capitalize()}!"                     (2)
    }
}
def d = new Duck()
assert d.speak() == 'Quack!'                        (3)
1 the SpeakingDuck expects the quack method to be defined
2 the Duck class does implement the method using methodMissing
3 calling the speak method triggers a call to quack which is handled by methodMissing
Dynamic methods in a trait

It is also possible for a trait to implement MOP methods like methodMissing or propertyMissing, in which case implementing classes will inherit the behavior from the trait, like in this example:

trait DynamicObject {                               (1)
    private Map props = [:]
    def methodMissing(String name, args) {
        name.toUpperCase()
    }
    def propertyMissing(String prop) {
        props['prop']
    }
    void setProperty(String prop, Object value) {
        props['prop'] = value
    }
}

class Dynamic implements DynamicObject {
    String existingProperty = 'ok'                  (2)
    String existingMethod() { 'ok' }                (3)
}
def d = new Dynamic()
assert d.existingProperty == 'ok'                   (4)
assert d.foo == null                                (5)
d.foo = 'bar'                                       (6)
assert d.foo == 'bar'                               (7)
assert d.existingMethod() == 'ok'                   (8)
assert d.someMethod() == 'SOMEMETHOD'               (9)
1 create a trait implementing several MOP methods
2 the Dynamic class defines a property
3 the Dynamic class defines a method
4 calling an existing property will call the method from Dynamic
5 calling an non-existing property will call the method from the trait
6 will call setProperty defined on the trait
7 will call getProperty defined on the trait
8 calling an existing method on Dynamic
9 but calling a non existing method thanks to the trait methodMissing
Multiple inheritance conflicts
Default conflict resolution

It is possible for a class to implement multiple traits. If some trait defines a method with the same signature as a method in another trait, we have a conflict:

trait A {
    String exec() { 'A' }               (1)
}
trait B {
    String exec() { 'B' }               (2)
}
class C implements A,B {}               (3)
1 trait A defines a method named exec returning a String
2 trait B defines the very same method
3 class C implements both traits

In this case, the default behavior is that methods from the last declared trait wins. Here, B is declared after A so the method from B will be picked up:

def c = new C()
assert c.exec() == 'B'
User conflict resolution

In case this behavior is not the one you want, you can explicitly choose which method to call using the Trait.super.foo syntax. In the example above, we can force to choose the method from trait A, by writing this:

class C implements A,B {
    String exec() { A.super.exec() }    (1)
}
def c = new C()
assert c.exec() == 'A'                  (2)
1 explicit call of exec from the trait A
2 calls the version from A instead of using the default resolution, which would be the one from B
Runtime implementation of traits
Implementing a trait at runtime

Groovy also supports implementing traits dynamically at runtime. It allows you to "decorate" an existing object using a trait. As an example, let’s start with this trait and the following class:

trait Extra {
    String extra() { "I'm an extra method" }            (1)
}
class Something {                                       (2)
    String doSomething() { 'Something' }                (3)
}
1 the Extra trait defines an extra method
2 the Something class does not implement the Extra trait
3 Something only defines a method doSomething

Then if we do:

def s = new Something()
s.extra()

the call to extra would fail because Something is not implementing Extra. It is possible to do it at runtime with the following syntax:

def s = new Something() as Extra                        (1)
s.extra()                                               (2)
s.doSomething()                                         (3)
1 use of the as keyword to coerce an object to a trait at runtime
2 then extra can be called on the object
3 and doSomething is still callable
When coercing an object to a trait, the result of the operation is not the same instance. It is guaranteed that the coerced object will implement both the trait and the interfaces that the original object implements, but the result will not be an instance of the original class.
Implementing multiple traits at once

Should you need to implement several traits at once, you can use the withTraits method instead of the as keyword:

trait A { void methodFromA() {} }
trait B { void methodFromB() {} }

class C {}

def c = new C()
c.methodFromA()                     (1)
c.methodFromB()                     (2)
def d = c.withTraits A, B           (3)
d.methodFromA()                     (4)
d.methodFromB()                     (5)
1 call to methodFromA will fail because C doesn’t implement A
2 call to methodFromB will fail because C doesn’t implement B
3 withTrait will wrap c into something which implements A and B
4 methodFromA will now pass because d implements A
5 methodFromB will now pass because d also implements B
When coercing an object to multiple traits, the result of the operation is not the same instance. It is guaranteed that the coerced object will implement both the traits and the interfaces that the original object implements, but the result will not be an instance of the original class.
Chaining behavior

Groovy supports the concept of stackable traits. The idea is to delegate from one trait to the other if the current trait is not capable of handling a message. To illustrate this, let’s imagine a message handler interface like this:

interface MessageHandler {
    void on(String message, Map payload)
}

Then you can compose a message handler by applying small behaviors. For example, let’s define a default handler in the form of a trait:

trait DefaultHandler implements MessageHandler {
    void on(String message, Map payload) {
        println "Received $message with payload $payload"
    }
}

Then any class can inherit the behavior of the default handler by implementing the trait:

class SimpleHandler implements DefaultHandler {}

Now what if you want to log all messages, in addition to the default handler? One option is to write this:

class SimpleHandlerWithLogging implements DefaultHandler {
    void on(String message, Map payload) {                                  (1)
        println "Seeing $message with payload $payload"                     (2)
        DefaultHandler.super.on(message, payload)                           (3)
    }
}
1 explicitly implement the on method
2 perform logging
3 continue by delegating to the DefaultHandler trait

This works but this approach has drawbacks:

  1. the logging logic is bound to a "concrete" handler

  2. we have an explicit reference to DefaultHandler in the on method, meaning that if we happen to change the trait that our class implements, code will be broken

As an alternative, we can write another trait which responsability is limited to logging:

trait LoggingHandler implements MessageHandler {                            (1)
    void on(String message, Map payload) {
        println "Seeing $message with payload $payload"                     (2)
        super.on(message, payload)                                          (3)
    }
}
1 the logging handler is itself a handler
2 prints the message it receives
3 then super makes it delegate the call to the next trait in the chain

Then our class can be rewritten as this:

class HandlerWithLogger implements DefaultHandler, LoggingHandler {}
def loggingHandler = new HandlerWithLogger()
loggingHandler.on('test logging', [:])

which will print:

Seeing test logging with payload [:]
Received test logging with payload [:]

As the priority rules imply that LoggerHandler wins because it is declared last, then a call to on will use the implementation from LoggingHandler. But the latter has a call to super, which means the next trait in the chain. Here, the next trait is DefaultHandler so both will be called:

The interest of this approach becomes more evident if we add a third handler, which is responsible for handling messages that start with say:

trait SayHandler implements MessageHandler {
    void on(String message, Map payload) {
        if (message.startsWith("say")) {                                    (1)
            println "I say ${message - 'say'}!"
        } else {
            super.on(message, payload)                                      (2)
        }
    }
}
1 a handler specific precondition
2 if the precondition is not meant, pass the message to the next handler in the chain

Then our final handler looks like this:

class Handler implements DefaultHandler, SayHandler, LoggingHandler {}
def h = new Handler()
h.on('foo', [:])
h.on('sayHello', [:])

Which means:

  • messages will first go through the logging handler

  • the logging handler calls super which will delegate to the next handler, which is the SayHandler

  • if the message starts with say, then the hanlder consumes the message

  • if not, the say handler delegates to the next handler in the chain

This approach is very powerful because it allows you to write handlers that do not know each other and yet let you combine them in the order you want. For example, if we execute the code, it will print:

Seeing foo with payload [:]
Received foo with payload [:]
Seeing sayHello with payload [:]
I say Hello!

but if we move the logging handler to be the second one in the chain, the output is different:

class AlternateHandler implements DefaultHandler, LoggingHandler, SayHandler {}
h = new AlternateHandler()
h.on('foo', [:])
h.on('sayHello', [:])

prints:

Seeing foo with payload [:]
Received foo with payload [:]
I say Hello!

The reason is that now, since the SayHandler consumes the message without calling super, the logging handler is not called anymore.

Semantics of super inside a trait

If a class implements multiple traits and that a call to an unqualified super is found, then:

  1. if the class implements another trait, the call delegates to the next trait in the chain

  2. if there isn’t any trait left in the chain, super refers to the super class of the implementing class (this)

For example, it is possible to decorate final classes thanks to this behavior:

trait Filtering {                                       (1)
    StringBuilder append(String str) {                  (2)
        def subst = str.replace('o','')                 (3)
        super.append(subst)                             (4)
    }
    String toString() { super.toString() }              (5)
}
def sb = new StringBuilder().withTraits Filtering       (6)
sb.append('Groovy')
assert sb.toString() == 'Grvy'                          (7)
1 define a trait named Filtering, supposed to be applied on a StringBuilder at runtime
2 redefine the append method
3 remove all 'o’s from the string
4 then delegate to super
5 in case toString is called, delegate to super.toString
6 runtime implementation of the Filtering trait on a StringBuilder instance
7 the string which has been appended no longer contains the letter o

In this example, when super.append is encountered, there is no other trait implemented by the target object, so the method which is called is the original append method, that is to say the one from StringBuilder. The same trick is used for toString, so that the string representation of the proxy object which is generated delegates to the toString of the StringBuilder instance.

Advanced features
SAM type coercion

If a trait defines a single abstract method, it is candidate for SAM type coercion. For example, imagine the following trait:

trait Greeter {
    String greet() { "Hello $name" }        (1)
    abstract String getName()               (2)
}
1 the greet method is not abstract and calls the abstract method getName
2 getName is an abstract method

Since getName is the single abstract method in the Greeter trait, you can write:

Greeter greeter = { 'Alice' }               (1)
1 the closure "becomes" the implementation of the getName single abstract method

or even:

void greet(Greeter g) { println g.greet() } (1)
greet { 'Alice' }                           (2)
1 the greet method accepts the SAM type Greeter as parameter
2 we can call it directly with a closure
Differences with Java 8 default methods

In Java 8, interfaces can have default implementations of methods. If a class implements an interface and does not provide an implementation for a default method, then the implementation from the interface is chosen. Traits behave the same but with a major difference: the implementation from the trait is always used if the class declares the trait in its interface list and that it doesn’t provide an implementation.

This feature can be used to compose behaviors in an very precise way, in case you want to override the behavior of an already implemented method.

To illustrate the concept, let’s start with this simple example:

import groovy.transform.CompileStatic
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.codehaus.groovy.control.customizers.ImportCustomizer

class SomeTest extends GroovyTestCase {
    def config
    def shell

    void setup() {
        config = new CompilerConfiguration()
        shell = new GroovyShell(config)
    }
    void testSomething() {
        assert shell.evaluate('1+1') == 2
    }
    void otherTest() { /* ... */ }
}

In this example, we create a simple test case which uses two properties (config and shell) and uses those in multiple test methods. Now imagine that you want to test the same, but with another distinct compiler configuration. One option is to create a subclass of SomeTest:

class AnotherTest extends SomeTest {
    void setup() {
        config = new CompilerConfiguration()
        config.addCompilationCustomizers( ... )
        shell = new GroovyShell(config)
    }
}

It works, but what if you have actually multiple test classes, and that you want to test the new configuration for all those test classes? Then you would have to create a distinct subclass for each test class:

class YetAnotherTest extends SomeTest {
    void setup() {
        config = new CompilerConfiguration()
        config.addCompilationCustomizers( ... )
        shell = new GroovyShell(config)
    }
}

Then what you see is that the setup method of both tests is the same. The idea, then, is to create a trait:

trait MyTestSupport {
    void setup() {
        config = new CompilerConfiguration()
        config.addCompilationCustomizers( new ASTTransformationCustomizer(CompileStatic) )
        shell = new GroovyShell(config)
    }
}

Then use it in the subclasses:

class AnotherTest extends SomeTest implements MyTestSupport {}
class YetAnotherTest extends SomeTest2 implements MyTestSupport {}
...

It would allow us to dramatically reduce the boilerplate code, and reduces the risk of forgetting to change the setup code in case we decide to change it. Even if setup is already implemented in the super class, since the test class declares the trait in its interface list, the behavior will be borrowed from the trait implementation!

This feature is in particular useful when you don’t have access to the super class source code. It can be used to mock methods or force a particular implementation of a method in a subclass. It lets you refactor your code to keep the overriden logic in a single trait and inherit a new behavior just by implementing it. The alternative, of course, is to override the method in every place you would have used the new code.

It’s worth noting that if you use runtime traits, the methods from the trait are always preferred to those of the proxied object:
class Person {
    String name                                         (1)
}
trait Bob {
    String getName() { 'Bob' }                          (2)
}

def p = new Person(name: 'Alice')
assert p.name == 'Alice'                                (3)
def p2 = p as Bob                                       (4)
assert p2.name == 'Bob'                                 (5)
1 the Person class defines a name property which results in a getName method
2 Bob is a trait which defines getName as returning Bob
3 the default object will return Alice
4 p2 coerces p into Bob at runtime
5 getName returns Bob because getName is taken from the trait
Again, don’t forget that dynamic trait coercion returns a distinct object which only implements the original interfaces, as well as the traits.
Differences with mixins

There are several conceptual differences with mixins, as they are available in Groovy. Note that we are talking about runtime mixins, not the @Mixin annotation which is deprecated in favour of traits.

First of all, methods defined in a trait are visible in bytecode:

  • internally, the trait is represented as an interface (without default methods) and several helper classes

  • this means that an object implementing a trait effectively implements an interface

  • those methods are visible from Java

  • they are compatible with type checking and static compilation

Methods added through a mixin are, on the contrary, only visible at runtime:

class A { String methodFromA() { 'A' } }        (1)
class B { String methodFromB() { 'B' } }        (2)
A.metaClass.mixin B                             (3)
def o = new A()
assert o.methodFromA() == 'A'                   (4)
assert o.methodFromB() == 'B'                   (5)
assert o instanceof A                           (6)
assert !(o instanceof B)                        (7)
1 class A defines methodFromA
2 class B defines methodFromB
3 mixin B into A
4 we can call methodFromA
5 we can also call methodFromB
6 the object is an instance of A
7 but it’s not an instanceof B

The last point is actually a very important and illustrates a place where mixins have an advantage over traits: the instances are not modified, so if you mixin some class into another, there isn’t a third class generated, and methods which respond to A will continue responding to A even if mixed in.

Static methods, properties and fields
The following instructions are subject to caution. Static member support is work in progress and still experimental. The information below is valid for 2.3.6 only.

It is possible to define static methods in a trait, but it comes with numerous limitations:

  • traits with static methods cannot be compiled statically or type checked. All static methods/properties/field are accessed dynamically (it’s a limitation from the JVM).

  • the trait is interpreted as a template for the implementing class, which means that each implementing class will get its own static methods/properties/methods. So a static member declared on a trait doesn’t belong to the Trait, but to it’s implementing class.

Let’s start with a simple example:

trait TestHelper {
    public static boolean CALLED = false        (1)
    static void init() {                        (2)
        CALLED = true                           (3)
    }
}
class Foo implements TestHelper {}
Foo.init()                                      (4)
assert Foo.TestHelper__CALLED                   (5)
1 the static field is declared in the trait
2 a static method is also declared in the trait
3 the static field is updated within the trait
4 a static method init is made available to the implementing class
5 the static field is remapped to avoid the diamond issue

As usual, it is not recommanded to use public fields. Anyway, should you want this, you must understand that the following code would fail:

Foo.CALLED = true

because there is no static field CALLED defined on the trait itself. Likewise, if you have two distinct implementing classes, each one gets a distinct static field:

class Bar implements TestHelper {}              (1)
class Baz implements TestHelper {}              (2)
Bar.init()                                      (3)
assert Bar.TestHelper__CALLED                   (4)
assert !Baz.TestHelper__CALLED                  (5)
1 class Bar implements the trait
2 class Baz also implements the trait
3 init is only called on Bar
4 the static field CALLED on Bar is updated
5 but the static field CALLED on Baz is not, because it is distinct
Inheritance of state gotchas

We have seen that traits are stateful. It is possible for a trait to define fields or properties, but when a class implements a trait, it gets those fields/properties on a per-trait basis. So consider the following example:

trait IntCouple {
    int x = 1
    int y = 2
    int sum() { x+y }
}

The trait defines two properties, x and y, as well as a sum method. Now let’s create a class which implements the trait:

class BaseElem implements IntCouple {
    int f() { sum() }
}
def base = new BaseElem()
assert base.f() == 3

The result of calling f is 3, because f delegates to sum in the trait, which has state. But what if we write this instead?

class Elem implements IntCouple {
    int x = 3                                       (1)
    int y = 4                                       (2)
    int f() { sum() }                               (3)
}
def elem = new Elem()
1 Override property x
2 Override property y
3 Call sum from trait

If you call elem.f(), what is the expected output? Actually it is:

assert elem.f() == 3

The reason is that the sum method accesses the fields of the trait. So it is using the x and y values defined in the trait. If you want to use the values from the implementing class, then you need to derefencence fields by using getters and setters, like in this last example:

trait IntCouple {
    int x = 1
    int y = 2
    int sum() { getX()+getY() }
}

class Elem implements IntCouple {
    int x = 3
    int y = 4
    int f() { sum() }
}
def elem = new Elem()
assert elem.f() == 7
Limitations
Compatibility with AST transformations
Traits are not officially compatible with AST transformations. Some of them, like @CompileStatic will be applied on the trait itself (not on implementing classes), while others will apply on both the implementing class and the trait. There is absolutely no guarantee that an AST transformation will run on a trait as it does on a regular class, so use it at your own risk!
Prefix and postfix operations

Within traits, prefix and postfix operations are not allowed if they update a field of the trait:

trait Counting {
    int x
    void inc() {
        x++                             (1)
    }
    void dec() {
        --x                             (2)
    }
}
class Counter implements Counting {}
def c = new Counter()
c.inc()
1 x is defined within the trait, postfix increment is not allowed
2 x is defined within the trait, prefix decrement is not allowed

A workaround is to use the += operator instead. :leveloffset: 0

1.4.3. Closures (TBD)

This chapter covers Groovy Closures.

Syntax (TBD)
Parameters (TBD)
Normal parameters (TBD)
Implicit parameter (TBD)
Default parameter (TBD)
Varargs (TBD)
Delegation strategy (TBD)
Closures in GStrings (TBD)
Functional programming (TBD)
Currying (TBD)
Left currying (TBD)
Right currying (TBD)
Index based currying (TBD)
Memoization (TBD)
Composition (TBD)
Trampoline (TBD)

1.4.4. Semantics

This chapter covers the semantics of the Groovy programming language.

Statements
Variable definition

Variables can be defined using either their type (like String) or by using the keyword def:

String x
def o

def is a replacement for a type name. In variable definitions it is used to indicate that you don’t care about the type. In variable definitions it is mandatory to either provide a type name explicitly or to use "def" in replacement. This is needed to the make variable definitions detectable for the Groovy parser.

You can think of def as an alias of Object and you will understand it in an instant.

Variable definition types can be refined by using generics, like in List<String> names. To learn more about the generics support, please read the generics section.
Variable assignment

You can assign values to variables for later use. Try the following:

x = 1
println x

x = new java.util.Date()
println x

x = -3.1499392
println x

x = false
println x

x = "Hi"
println x
Multiple assignment

Groovy supports multiple assignment, i.e. where multiple variables can be assigned at once, e.g.:

def (a, b, c) = [10, 20, 'foo']
assert a == 10 && b == 20 && c == 'foo'

You can provide types as part of the declaration if you wish:

def (int i, String j) = [10, 'foo']
assert i == 10 && j == 'foo'

As well as used when declaring variables it also applies to existing variables:

def nums = [1, 3, 5]
def a, b, c
(a, b, c) = nums
assert a == 1 && b == 3 && c == 5

The syntax works for arrays as well as lists, as well as methods that return either of these:

def (_, month, year) = "18th June 2009".split()
assert "In $month of $year" == 'In June of 2009'
Overflow and Underflow

If the left hand side has too many variables, excess ones are filled with null’s:

def (a, b, c) = [1, 2]
assert a == 1 && b == 2 && c == null

If the right hand side has too many variables, the extra ones are ignored:

def (a, b) = [1, 2, 3]
assert a == 1 && b == 2
Object destructuring with multiple assignment

In the section describing the various Groovy operators, the case of the subscript operator has been covered, explaining how you can override the getAt()/putAt() method.

With this technique, we can combine multiple assignments and the subscript operator methods to implement object destructuring.

Consider the following immutable Coordinates class, containing a pair of longitude and latitude doubles, and notice our implementation of the getAt() method:

@Immutable
class Coordinates {
    double latitude
    double longitude

    double getAt(int idx) {
        if (idx == 0) latitude
        else if (idx == 1) longitude
        else throw new Exception("Wrong coordinate index, use 0 or 1")
    }
}

Now let’s instantiate this class and destructure its longitude and latitude:

def coordinates = new Coordinates(latitude: 43.23, longitude: 3.67) (1)

def (la, lo) = coordinates                                          (2)

assert la == 43.23                                                  (3)
assert lo == 3.67
1 we create an instance of the Coordinates class
2 then, we use a multiple assignment to get the individual longitude and latitude values
3 and we can finally assert their values.
Control structures (WIP)
Conditional structures
if / else

Groovy supports the usual if - else syntax from Java

def x = false
def y = false

if ( !x ) {
    x = true
}

assert x == true

if ( x ) {
    x = false
} else {
    y = true
}

assert x == y

Groovy also supports the normal Java "nested" if then else if syntax:

if ( ... ) {
    ...
} else if (...) {
    ...
} else {
    ...
}
switch / case

The switch statement in Groovy is backwards compatible with Java code; so you can fall through cases sharing the same code for multiple matches.

One difference though is that the Groovy switch statement can handle any kind of switch value and different kinds of matching can be performed.

def x = 1.23
def result = ""

switch ( x ) {
    case "foo":
        result = "found foo"
        // lets fall through

    case "bar":
        result += "bar"

    case [4, 5, 6, 'inList']:
        result = "list"
        break

    case 12..30:
        result = "range"
        break

    case Integer:
        result = "integer"
        break

    case Number:
        result = "number"
        break

    case ~/fo*/: // toString() representation of x matches the pattern?
        result = "foo regex"
        break

    case { it < 0 }: // or { x < 0 }
        result = "negative"
        break

    default:
        result = "default"
}

assert result == "number"

Switch supports the following kinds of comparisons:

  • Class case values matches if the switch value is an instance of the class

  • Regular expression case values match if the toString() representation of the switch value matches the regex

  • Collection case values match if the switch value is contained in the collection. This also includes ranges (since they are Lists)

  • Closure case values match if the calling the closure returns a result which is true according to the Groovy truth

  • If none of the above are used then the case value matches if the case value equals the switch value

default must go at the end of the switch/case. While in Java the default can be placed anywhere in the switch/case, the default in Groovy is used more as an else than assigning a default case.
when using a closure case value, the default it parameter is actually the switch value (in our example, variable x)
Looping structures
Classic for loop

Groovy supports the standard Java / C for loop:

String message = ''
for (int i = 0; i < 5; i++) {
    message += 'Hi '
}
assert message == 'Hi Hi Hi Hi Hi '
for in loop

The for loop in Groovy is much simpler and works with any kind of array, collection, Map, etc.

// iterate over a range
def x = 0
for ( i in 0..9 ) {
    x += i
}
assert x == 45

// iterate over a list
x = 0
for ( i in [0, 1, 2, 3, 4] ) {
    x += i
}
assert x == 10

// iterate over an array
def array = (0..4).toArray()
x = 0
for ( i in array ) {
    x += i
}
assert x == 10

// iterate over a map
def map = ['abc':1, 'def':2, 'xyz':3]
x = 0
for ( e in map ) {
    x += e.value
}
assert x == 6

// iterate over values in a map
x = 0
for ( v in map.values() ) {
    x += v
}
assert x == 6

// iterate over the characters in a string
def text = "abc"
def list = []
for (c in text) {
    list.add(c)
}
assert list == ["a", "b", "c"]
Groovy also supports the Java colon variation with colons: for (char c : text) {}, where the type of the variable is mandatory.
while loop

Groovy supports the usual while {…} loops like Java:

def x = 0
def y = 5

while ( y-- > 0 ) {
    x++
}

assert x == 5
Exception handling

Exception handling is the same as Java.

try / catch / finally

You can specify a complete try-catch-finally, a try-catch, or a try-finally set of blocks.

Braces are required around each block’s body.
try {
    'moo'.toLong()   // this will generate an exception
    assert false     // asserting that this point should never be reached
} catch ( e ) {
    assert e in NumberFormatException
}

We can put code within a finally clause following a matching try clause, so that regardless of whether the code in the try clause throws an exception, the code in the finally clause will always execute:

def z
try {
    def i = 7, j = 0
    try {
        def k = i / j
        assert false        //never reached due to Exception in previous line
    } finally {
        z = 'reached here'  //always executed even if Exception thrown
    }
} catch ( e ) {
    assert e in ArithmeticException
    assert z == 'reached here'
}
Multi-catch

With the multi catch block (since Groovy 2.0), we’re able to define several exceptions to be catch and treated by the same catch block:

try {
    /* ... */
} catch ( IOException | NullPointerException e ) {
    /* one block to handle 2 exceptions */
}
Power assertion (TBD)
Labeled statements (TBD)
Expressions (TBD)
GPath expressions (TBD)
Promotion and coercion (TBD)
Number promotion (TBD)
Closure to type coercion
Assigning a closure to a SAM type

A SAM type is a type which defines a single abstract method. This includes:

Functional interfaces
interface Predicate<T> {
    boolean accept(T obj)
}
Abstract classes with single abstract method
abstract class Greeter {
    abstract String getName()
    void greet() {
        println "Hello, $name"
    }
}

Any closure can be converted into a SAM type using the as operator:

Predicate filter = { it.contains 'G' } as Predicate
assert filter.accept('Groovy') == true

Greeter greeter = { 'Groovy' } as Greeter
greeter.greet()

However, the as Type expression is optional since Groovy 2.2.0. You can omit it and simply write:

Predicate filter = { it.contains 'G' }
assert filter.accept('Groovy') == true

Greeter greeter = { 'Groovy' }
greeter.greet()

which means you are also allowed to use method pointers, as shown in the following example:

boolean doFilter(String s) { s.contains('G') }

Predicate filter = this.&doFilter
assert filter.accept('Groovy') == true

Greeter greeter = GroovySystem.&getVersion
greeter.greet()
Calling a method accepting a SAM type with a closure

The second and probably more important use case for closure to SAM type coercion is calling a method which accepts a SAM type. Imagine the following method:

public <T> List<T> filter(List<T> source, Predicate<T> predicate) {
    source.findAll { predicate.accept(it) }
}

Then you can call it with a closure, without having to create an explicit implementation of the interface:

assert filter(['Java','Groovy'], { it.contains 'G'} as Predicate) == ['Groovy']

But since Groovy 2.2.0, you are also able to omit the explicit coercion and call the method as if it used a closure:

assert filter(['Java','Groovy']) { it.contains 'G'} == ['Groovy']

As you can see, this has the advantage of letting you use the closure syntax for method calls, that is to say put the closure outside of the parenthesis, improving the readability of your code.

Closure to arbitrary type coercion

In addition to SAM types, a closure can be coerced to any type and in particular interfaces. Let’s define the following interface:

interface FooBar {
    int foo()
    void bar()
}

You can coerce a closure into the interface using the as keyword:

def impl = { println 'ok'; 123 } as FooBar

This produces a class for which all methods are implemented using the closure:

assert impl.foo() == 123
impl.bar()

But it is also possible to coerce a closure to any class. For example, we can replace the interface that we defined with class without changing the assertions:

class FooBar {
    int foo() { 1 }
    void bar() { println 'bar' }
}

def impl = { println 'ok'; 123 } as FooBar

assert impl.foo() == 123
impl.bar()
Map to type coercion

Usually using a single closure to implement an interface or a class with multiple methods is not the way to go. As an alternative, Groovy allows you to coerce a map into an interface or a class. In that case, keys of the map are interpreted as method names, while the values are the method implementation. The following example illustrates the coercion of a map into an Iterator:

def map
map = [
  i: 10,
  hasNext: { map.i > 0 },
  next: { map.i-- },
]
def iter = map as Iterator

Of course this is a rather contrived example, but illustrates the concept. You only need to implement those methods that are actually called, but if a method is called that doesn’t exist in the map a MissingMethodException or an UnsupportedOperationException is thrown, depending on the arguments passed to the call, as in the following example:

interface X {
    void f()
    void g(int n)
    void h(String s, int n)
}

x = [ f: {println "f called"} ] as X
x.f() // method exists
x.g() // MissingMethodException here
x.g(5) // UnsupportedOperationException here

The type of the exception depends on the call itself:

  • MissingMethodException if the arguments of the call do not match those from the interface/class

  • UnsupportedOperationException if the arguments of the call match one of the overloaded methods of the interface/class

String to enum coercion

Groovy allows transparent String (or GString) to enum values coercion. Imagine you define the following enum:

enum State {
    up,
    down
}

then you can assign a string to the enum without having to use an explicit as coercion:

State st = 'up'
assert st == State.up

It is also possible to use a GString as the value:

def val = "up"
State st = "${val}"
assert st == State.up

However, this would throw a runtime error (IllegalArgumentException):

State st = 'not an enum value'

Note that it is also possible to use implicit coercion in switch statements:

State switchState(State st) {
    switch (st) {
        case 'up':
            return State.down // explicit constant
        case 'down':
            return 'up' // implicit coercion for return types
    }
}

in particular, see how the case use string constants. But if you call a method that uses an enum with a String argument, you still have to use an explicit as coercion:

assert switchState('up' as State) == State.down
assert switchState(State.down) == State.up
Custom type coercion

It is possible for a class to define custom coercion strategies by implementing the asType method. Custom coercion is invoked using the as operator and is never implicit. As an example, imagine you defined two classes, Polar and Cartesian, like in the following example:

class Polar {
    double r
    double phi
}
class Cartesian {
   double x
   double y
}

And that you want to convert from polar coordinates to cartesian coordinates. One way of doing this is to define the asType method in the Polar class:

def asType(Class target) {
    if (Cartesian==target) {
        return new Cartesian(x: r*cos(phi), y: r*sin(phi))
    }
}

which allows you to use the as coercion operator:

def sigma = 1E-16
def polar = new Polar(r:1.0,phi:PI/2)
def cartesian = polar as Cartesian
assert abs(cartesian.x-sigma) < sigma

Putting it all together, the Polar class looks like this:

class Polar {
    double r
    double phi
    def asType(Class target) {
        if (Cartesian==target) {
            return new Cartesian(x: r*cos(phi), y: r*sin(phi))
        }
    }
}

but it is also possible to define asType outside of the Polar class, which can be practical if you want to define custom coercion strategies for "closed" classes or classes for which you don’t own the source code, for example using a metaclass:

Polar.metaClass.asType = { Class target ->
    if (Cartesian==target) {
        return new Cartesian(x: r*cos(phi), y: r*sin(phi))
    }
}
Class literals vs variables and the as operator

Using the as keyword is only possible if you have a static reference to a class, like in the following code:

interface Greeter {
    void greet()
}
def greeter = { println 'Hello, Groovy!' } as Greeter // Greeter is known statically
greeter.greet()

But what if you get the class by reflection, for example by calling Class.forName?

Class clazz = Class.forName('Greeter')

Trying to use the reference to the class with the as keyword would fail:

greeter = { println 'Hello, Groovy!' } as clazz
// throws:
// unable to resolve class clazz
// @ line 9, column 40.
//   greeter = { println 'Hello, Groovy!' } as clazz

It is failing because the as keyword only works with class literals. Instead, you need to call the asType method:

greeter = { println 'Hello, Groovy!' }.asType(clazz)
greeter.greet()
Optionality (TBD)
Optional parentheses (TBD)
Optional semicolons (TBD)
Optional return keyword (TBD)
Optional public keyword (TBD)
The Groovy Truth (TBD)
Customizing the truth with asBoolean() methods (TBD)
Typing (WIP)
Optional typing

Optional typing is the idea that a program can work even if you don’t put an explicit type on a variable. Being a dynamic language, Groovy naturally implements that feature, for example when you declare a variable:

String aString = 'foo'                      (1)
assert aString.toUpperCase()                (2)
1 foo is declared using an explicit type, String
2 we can call the toUpperCase method on a String

Groovy will let you write this instead:

def aString = 'foo'                         (1)
assert aString.toUpperCase()                (2)
1 foo is declared using def
2 we can still call the toUpperCase method, because the type of aString is resolved at runtime

So it doesn’t matter that you use an explicit type here. It is in particular interesting when you combine this feature with static type checking, because the type checker performs type inference.

Likewise, Groovy doesn’t make it mandatory to declare the types of a parameter in a method:

String concat(String a, String b) {
    a+b
}
assert concat('foo','bar') == 'foobar'

can be rewritten using def as both return type and parameter types, in order to take advantage of duck typing, as illustrated in this example:

def concat(def a, def b) {                              (1)
    a+b
}
assert concat('foo','bar') == 'foobar'                  (2)
assert concat(1,2) == 3                                 (3)
1 both the return type and the parameter types use def
2 it makes it possible to use the method with String
3 but also with int`s since the `plus method is defined
Using the def keyword here is recommanded to describe the intent of a method which is supposed to work on any type, but technically, we could use Object instead and the result would be the same: def is, in Groovy, strictly equivalent to using Object.

Eventually, the type can be removed altogether from both the return type and the descriptor. But if you want to remove it from the return type, you then need to add an explicit modifier for the method, so that the compiler can make a difference between a method declaration and a method call, like illustrated in this example:

private concat(a,b) {                                   (1)
    a+b
}
assert concat('foo','bar') == 'foobar'                  (2)
assert concat(1,2) == 3                                 (3)
1 if we want to omit the return type, an explicit modifier has to be set.
2 it is still possible to use the method with String
3 and also with `int`s
Omitting types is in general considered a bad practice in method parameters or method return types for public APIs. While using def in a local variable is not really a problem because the visibility of the variable is limited to the method itself, while set on a method parameter, def will be converted to Object in the method signature, making it difficult for users to know which is the expected type of the arguments. This means that you should limit this to cases where you are explicitly relying on duck typing.
Static type checking

By default, Groovy performs minimal type checking at compile time. Since it is primarily a dynamic language, most checks that a static compiler would normally do aren’t possible at compile time. A method added via runtime metaprogramming might alter a class or object’s runtime behavior. Let’s illustrate why in the following example:

class Person {                                                          (1)
    String firstName
    String lastName
}
def p = new Person(firstName: 'Raymond', lastName: 'Devos')             (2)
assert p.formattedName == 'Raymond Devos'                               (3)
1 the Person class only defines two properties, firstName and lastName
2 we can create an instance of Person
3 and call a method named formattedName

It is quite common in dynamic languages for code such as the above example not to throw any error. How can this be? In Java, this would typically fail at compile time. However, in Groovy, it will not fail at compile time, and if coded correctly, will also not fail at runtime. In fact, to make this work at runtime, one possibility is to rely on runtime metaprogramming. So just adding this line after the declaration of the Person class is enough:

Person.metaClass.getFormattedName = { "$delegate.firstName $delegate.lastName" }

This means that in general, in Groovy, you can’t make any assumption about the type of an object beyond its declaration type, and even if you know it, you can’t determine at compile time what method will be called, or which property will be retrieved, and this is perfectly fine. This is how dynamic languages work, and it has a lot of interest.

However, if your program doesn’t rely on dynamic features and that you come from the static world (in particular, from a Java mindset), not catching such "errors" at compile time can be surprising. As we have seen in the previous example, the compiler cannot be sure this is an error. To make it aware that it is, you have to explicitly instruct the compiler that you are switching to a type checked mode. This can be done by annotating a class or a method with @groovy.lang.TypeChecked.

When type checking is activated, the compiler performs much more work:

  • type inference is activated, meaning that even if you use def on a local variable for example, the type checker will be able to infer the type of the variable from the assignments

  • method calls are resolved at compile time, meaning that if a method is not declared on a class, the compiler will throw an error

  • in general, all the compile time errors that you are used to find in a static language will appear: method not found, property not found, incompatible types for method calls, number precision errors, …

In this section, we will describe the behavior of the type checker in various situations and explain the limits of using @TypeChecked on your code.

The @TypeChecked annotation
Activating type checking at compile time

The groovy.lang.TypeChecked annotation enabled type checking. It can be placed on a class:

@groovy.transform.TypeChecked
class Calculator {
    int sum(int x, int y) { x+y }
}

Or on a method:

class Calculator {
    @groovy.transform.TypeChecked
    int sum(int x, int y) { x+y }
}

In the first case, all methods, properties, fields, inner classes, … of the annotated class will be type checked, whereas in the second case, only the method and potential closures or anonymous inner classes that it contains will be type checked.

Skipping sections

The scope of type checking can be restricted. For example, if a class is type checked, you can instruct the type checker to skip a method by annotating it with @TypeChecked(TypeCheckingMode.SKIP):

import groovy.transform.TypeChecked
import groovy.transform.TypeCheckingMode

@TypeChecked                                        (1)
class GreetingService {
    String greeting() {                             (2)
        doGreet()
    }

    @TypeChecked(TypeCheckingMode.SKIP)             (3)
    private String doGreet() {
        def b = new SentenceBuilder()
        b.Hello.my.name.is.John                     (4)
        b
    }
}
def s = new GreetingService()
assert s.greeting() == 'Hello my name is John'
1 the GreetingService class is marked as type checked
2 so the greeting method is automatically type checked
3 but doGreet is marked with SKIP
4 the type checker doesn’t complain about missing properties here

In the previous example, SentenceBuilder relies on dynamic code. There’s no real Hello method or property, so the type checker would normally complain and compilation would fail. Since the method that uses the builder is marked with TypeCheckingMode.SKIP, type checking is skipped for this method, so the code will compile, even if the rest of the class is type checked.

The following sections describe the semantics of type checking in Groovy.

Type checking assignments

An object o of type A can be assigned to a variable of type T if and only if:

  • T equals A

    Date now = new Date()
  • or T is one of String, boolean, Boolean or Class

    String s = new Date() // implicit call to toString
    Boolean boxed = 'some string'       // Groovy truth
    boolean prim = 'some string'        // Groovy truth
    Class clazz = 'java.lang.String'    // class coercion
  • or o is null and T is not a primitive type

    String s = null         // passes
    int i = null            // fails
  • or T is an array and A is an array and the component type of A is assignable to the component type of B

    int[] i = new int[4]        // passes
    int[] i = new String[4]     // fails
  • or T is an array and A is a list and the component type of A is assignable to the component type of B

    int[] i = [1,2,3]               // passes
    int[] i = [1,2, new Date()]     // fails
  • or T is a superclass of A

    AbstractList list = new ArrayList()     // passes
    LinkedList list = new ArrayList()       // fails
  • or T is an interface implemented by A

    List list = new ArrayList()             // passes
    RandomAccess list = new LinkedList()    // fails
  • or T or A are a primitive type and their boxed types are assignable

    int i = 0
    Integer bi = 1
    int x = new Integer(123)
    double d = new Float(5f)
  • or T extends groovy.lang.Closure and A is a SAM-type (single abstract method type)

    Runnable r = { println 'Hello' }
    interface SAMType {
        int doSomething()
    }
    SAMType sam = { 123 }
    assert sam.doSomething() == 123
    abstract class AbstractSAM {
        int calc() { 2* value() }
        abstract int value()
    }
    AbstractSAM c = { 123 }
    assert c.calc() == 246
  • or T and A derive from java.lang.Number and conform to the following table

Table 2. Number types (java.lang.XXX)
T A Examples

Double

Any but BigDecimal or BigInteger

Double d1 = 4d
Double d2 = 4f
Double d3 = 4l
Double d4 = 4i
Double d5 = (short) 4
Double d6 = (byte) 4

Float

Any type but BigDecimal, BigInteger or Double

Float f1 = 4f
Float f2 = 4l
Float f3 = 4i
Float f4 = (short) 4
Float f5 = (byte) 4

Long

Any type but BigDecimal, BigInteger, Double or Float

Long l1 = 4l
Long l2 = 4i
Long l3 = (short) 4
Long l4 = (byte) 4

Integer

Any type but BigDecimal, BigInteger, Double, Float or Long

Integer i1 = 4i
Integer i2 = (short) 4
Integer i3 = (byte) 4

Short

Any type but BigDecimal, BigInteger, Double, Float, Long or Integer

Short s1 = (short) 4
Short s2 = (byte) 4

Byte

Byte

Byte b1 = (byte) 4
List and map constructors

In addition to the assignment rules above, if an assignment is deemed invalid, in type checked mode, a list literal or a map literal A can be assigned to a variable of type T if:

  • the assignment is a variable declaration and A is a list literal and T has a constructor whose parameters match the types of the elements in the list literal

  • the assignment is a variable declaration and A is a map literal and T has a no-arg constructor and a property for each of the map keys

For example, instead of writing:

@groovy.transform.TupleConstructor
class Person {
    String firstName
    String lastName
}
Person classic = new Person('Ada','Lovelace')

You can use a "list constructor":

Person list = ['Ada','Lovelace']

or a "map constructor":

Person map = [firstName:'Ada', lastName:'Lovelace']

If you use a map constructor, additional checks are done on the keys of the map to check if a property of the same name is defined. For example, the following will fail at compile time:

@groovy.transform.TupleConstructor
class Person {
    String firstName
    String lastName
}
Person map = [firstName:'Ada', lastName:'Lovelace', age: 24]     (1)
1 The type checker will throw an error No such property: age for class: Person at compile time
Method resolution

In type checked mode, methods are resolved at compile time. Resolution works by name and arguments. The return type is irrelevant to method selection. Types of arguments are matched against the types of the parameters following those rules:

An argument o of type A can be used for a parameter of type T if and only if:

  • T equals A

    int sum(int x, int y) {
        x+y
    }
    assert sum(3,4) == 7
  • or T is a String and A is a GString

    String format(String str) {
        "Result: $str"
    }
    assert format("${3+4}") == "Result: 7"
  • or o is null and T is not a primitive type

    String format(int value) {
        "Result: $value"
    }
    assert format(7) == "Result: 7"
    format(null)           // fails
  • or T is an array and A is an array and the component type of A is assignable to the component type of B

    String format(String[] values) {
        "Result: ${values.join(' ')}"
    }
    assert format(['a','b'] as String[]) == "Result: a b"
    format([1,2] as int[])              // fails
  • or T is a superclass of A

    String format(AbstractList list) {
        list.join(',')
    }
    format(new ArrayList())              // passes
    String format(LinkedList list) {
        list.join(',')
    }
    format(new ArrayList())              // fails
  • or T is an interface implemented by A

    String format(List list) {
        list.join(',')
    }
    format(new ArrayList())                  // passes
    String format(RandomAccess list) {
        'foo'
    }
    format(new LinkedList())                 // fails
  • or T or A are a primitive type and their boxed types are assignable

    int sum(int x, Integer y) {
        x+y
    }
    assert sum(3, new Integer(4)) == 7
    assert sum(new Integer(3), 4) == 7
    assert sum(new Integer(3), new Integer(4)) == 7
    assert sum(new Integer(3), 4) == 7
  • or T extends groovy.lang.Closure and A is a SAM-type (single abstract method type)

    interface SAMType {
        int doSomething()
    }
    int twice(SAMType sam) { 2*sam.doSomething() }
    assert twice { 123 } == 246
    abstract class AbstractSAM {
        int calc() { 2* value() }
        abstract int value()
    }
    int eightTimes(AbstractSAM sam) { 4*sam.calc() }
    assert eightTimes { 123 } == 984
  • or T and A derive from java.lang.Number and conform to the same rules as assignment of numbers

If a method with the appropriate name and arguments is not found at compile time, an error is thrown. The difference with "normal" Groovy is illustrated in the following example:

class MyService {
    void doSomething() {
        printLine 'Do something'            (1)
    }
}
1 printLine is an error, but since we’re in a dynamic mode, the error is not caught at compile time

The example above shows a class that Groovy will be able to compile. However, if you try to create an instance of MyService and call the doSomething method, then it will fail at runtime, because printLine doesn’t exist. Of course, we already showed how Groovy could make this a perfectly valid call, for example by catching MethodMissingException or implementing a custom meta-class, but if you know you’re not in such a case, @TypeChecked comes handy:

class MyService {
    void doSomething() {
        printLine 'Do something'            (1)
    }
}
1 printLine is this time a compile-time error

Just adding @TypeChecked will trigger compile time method resolution. The type checker will try to find a method printLine accepting a String on the MyService class, but cannot find one. It will fail compilation with the following message:

Cannot find matching method MyService#printLine(java.lang.String)

It is important to understand the logic behind the type checker: it is a compile-time check, so by definition, the type checker is not aware of any kind of runtime metaprogramming that you do. This means that code which is perfectly valid without @TypeChecked will not compile anymore if you activate type checking. This is in particular true if you think of duck typing:
class Duck {
    void quack() {              (1)
        println 'Quack!'
    }
}
class QuackingBird {
    void quack() {              (2)
        println 'Quack!'
    }
}
@groovy.transform.TypeChecked
void accept(quacker) {
    quacker.quack()             (3)
}
accept(new Duck())              (4)
1 we define a Duck class which defines a quack method
2 we define another QuackingBird class which also defines a quack method
3 quacker is loosely typed, so since the method is @TypeChecked, we will obtain a compile-time error
4 even if in non type-checked Groovy, this would have passed

There are possible workarounds, like introducing an interface, but basically, by activating type checking, you gain type safety but you loose some features of the language. Hopefully, Groovy introduces some features like flow typing to reduce the gap between type-checked and non type-checked Groovy.

Type inference
Principles

When code is annotated with @TypeChecked, the compiler performs type inference. It doesn’t simply rely on static types, but also uses various techniques to infer the types of variables, return types, literals, … so that the code remains as clean as possible even if you activate the type checker.

The simplest example is infering the type of a variable:

def message = 'Welcome to Groovy!'              (1)
println message.toUpperCase()                   (2)
println message.upper() // compile time error   (3)
1 a variable is declared using the def keyword
2 calling toUpperCase is allowed by the type checker
3 calling upper will fail at compile time

The reason the call to toUpperCase works is because the type of message was inferred as being a String.

Variables vs fields in type inference

It is worth noting that although the compiler performs type inference on local variables, it does not perform any kind of type inference on fields, always falling back to the declared type of a field. To illustrate this, let’s take a look at this example:

class SomeClass {
    def someUntypedField                                                                (1)
    String someTypedField                                                               (2)

    void someMethod() {
        someUntypedField = '123'                                                        (3)
        someUntypedField = someUntypedField.toUpperCase()  // compile-time error        (4)
    }

    void someSafeMethod() {
        someTypedField = '123'                                                          (5)
        someTypedField = someTypedField.toUpperCase()                                   (6)
    }

    void someMethodUsingLocalVariable() {
        def localVariable = '123'                                                       (7)
        someUntypedField = localVariable.toUpperCase()                                  (8)
    }
}
1 someUntypedField uses def as a declaration type
2 someTypedField uses String as a declaration type
3 we can assign anything to someUntypedField
4 yet calling toUpperCase fails at compile time because the field is not typed properly
5 we can assign a String to a field of type String
6 and this time toUpperCase is allowed
7 if we assign a String to a local variable
8 then calling toUpperCase is allowed on the local variable

Why such a difference? The reason is thread safety. At compile time, we can’t make any guarantee about the type of a field. Any thread can access any field at any time and between the moment a field is assigned a variable of some type in a method and the time is is used the line after, another thread may have changed the contents of the field. This is not the case for local variables: we know if they "escape" or not, so we can make sure that the type of a variable is constant (or not) over time. Note that even if a field is final, the JVM makes no guarantee about it, so the type checker doesn’t behave differently if a field is final or not.

This is one of the reasons why we recommend to use typed fields. While using def for local variables is perfectly fine thanks to type inference, this is not the case for fields, which also belong to the public API of a class, hence the type is important.
Collection literal type inference

Groovy provides a syntax for various type literals. There are three native collection literals in Groovy:

  • lists, using the [] literal

  • maps, using the [:] literal

  • ranges, using the (..,..) literal

The inferred type of a literal depends on the elements of the literal, as illustrated in the following table:

Literal Inferred type
def list = []

java.util.List

def list = ['foo','bar']

java.util.List<String>

def list = ["${foo}","${bar}"]

java.util.List<GString> be careful, a GString is not a String!

def map = [:]

java.util.LinkedHashMap

def map1 = [someKey: 'someValue']
def map2 = ['someKey': 'someValue']

java.util.LinkedHashMap<String,String>

def map1 = [someKey: 'someValue']
def map2 = ['someKey': 'someValue']

java.util.LinkedHashMap<GString,String> be careful, the key is a GString!

def intRange = (0..10)

groovy.lang.IntRange

def charRange = ('a'..'z')

groovy.lang.Range<String> : uses the type of the bounds to infer the component type of the range

As you can see, with the noticeable exception of the IntRange, the inferred type makes use of generics types to describe the contents of a collection. In case the collection contains elements of different types, the type checker still performs type inference of the components, but uses the notion of least upper bound.

Least upper bound

In Groovy, the least upper bound of two types A and B is defined as a type which:

  • superclass corresponds to the common super class of A and B

  • interfaces correspond to the interfaces implemented by both A and B

  • if A or B is a primitive type and that A isn’t equal to B, the least upper bound of A and B is the least upper bound of their wrapper types

If A and B only have one (1) interface in common and that their common superclass is Object, then the LUB of both is the common interface.

The least upper bound represents the minimal type to which both A and B can be assigned. So for example, if A and B are both String, then the LUB (least upper bound) of both is also String.

class Top {}
class Bottom1 extends Top {}
class Bottom2 extends Top {}

assert leastUpperBound(String, String) == String                    (1)
assert leastUpperBound(ArrayList, LinkedList) == AbstractList       (2)
assert leastUpperBound(ArrayList, List) == List                     (3)
assert leastUpperBound(List, List) == List                          (4)
assert leastUpperBound(Bottom1, Bottom2) == Top                     (5)
assert leastUpperBound(List, Serializable) == Object                (6)
1 the LUB of String and String is String
2 the LUB of ArrayList and LinkedList is their common super type, AbstractList
3 the LUB of ArrayList and List is their only common interface, List
4 the LUB of two identical interfaces is the interface itself
5 the LUB of Bottom1 and Bottom2 is their superclass Top
6 the LUB of two types which have nothing in common is Object

In those examples, the LUB is always representable as a normal, JVM supported, type. But Groovy internally represents the LUB as a type which can be more complex, and that you wouldn’t be able to use to define a variable for example. To illustrate this, let’s continue with this example:

interface Foo {}
class Top {}
class Bottom extends Top implements Serializable, Foo {}
class SerializableFooImpl implements Serializable, Foo {}

What is the least upper bound of Bottom and SerializableFooImpl? They don’t have a common super class (apart from Object), but they do share 2 interfaces (Serializable and Foo), so their least upper bound is a type which represents the union of two interfaces (Serializable and Foo). This type cannot be defined in the source code, yet Groovy knows about it.

In the context of collection type inference (and generic type inference in general), this becomes handy, because the type of the components is inferred as the least upper bound. We can illustrate why this is important in the following example:

interface Greeter { void greet() }                  (1)
interface Salute { void salute() }                  (2)

class A implements Greeter, Salute {                (3)
    void greet() { println "Hello, I'm A!" }
    void salute() { println "Bye from A!" }
}
class B implements Greeter, Salute {                (4)
    void greet() { println "Hello, I'm B!" }
    void salute() { println "Bye from B!" }
    void exit() { println 'No way!' }               (5)
}
def list = [new A(), new B()]                       (6)
list.each {
    it.greet()                                      (7)
    it.salute()                                     (8)
    it.exit()                                       (9)
}
1 the Greeter interface defines a single method, greet
2 the Salute interface defines a single method, salute
3 class A implements both Greeter and Salute but there’s no explicit interface extending both
4 same for B
5 but B defines an additional exit method
6 the type of list is inferred as "list of the LUB of A and B"
7 so it is possible to call greet which is defined on both A and B through the Greeter interface
8 and it is possible to call salut which is defined on both A and B through the Salut interface
9 yet calling exit is a compile time error because it doesn’t belong to the LUB of A and B (only defined in B)

The error message will look like:

[Static type checking] - Cannot find matching method Greeter or Salute#exit()

which indicates that the exit method is neither defines on Greeter nor Salute, which are the two interfaces defined in the least upper bound of A and B.

instanceof inference

In normal, non type checked, Groovy, you can write things like:

class Greeter {
    String greeting() { 'Hello' }
}

void doSomething(def o) {
    if (o instanceof Greeter) {     (1)
        println o.greeting()        (2)
    }
}

doSomething(new Greeter())
1 guard the method call with an instanceof check
2 make the call

The method call works because of dynamic dispatch (the method is selected at runtime). The equivalent code in Java would require to cast o to a Greeter before calling the greeting method, because methods are selected at compile time:

if (o instanceof Greeter) {
    System.out.println(((Greeter)o).greeting());
}

However, in Groovy, even if you add @TypeChecked (and thus activate type checking) on the doSomething method, the cast is not necessary. The compiler embeds instanceof inference that makes the cast optional.

Flow typing

Flow typing is an important concept of Groovy in type checked mode and an extension of type inference. The idea is that the compiler is capable of infering the type of variables in the flow of the code, not just at initialization:

@groovy.transform.TypeChecked
void flowTyping() {
    def o = 'foo'                       (1)
    o = o.toUpperCase()                 (2)
    o = 9d                              (3)
    o = Math.sqrt(o)                    (4)
}
1 first, o is declared using def and assigned a String
2 the compiler inferred that o is a String, so calling toUpperCase is allowed
3 o is reassigned with a double
4 calling Math.sqrt passes compilation because the compiler knows that at this point, o is a double

So the type checker is aware of the fact that the concrete type of a variable is different over time. In particular, if you replace the last assignment with:

o = 9d
o = o.toUpperCase()

The type checker will now fail at compile time, because it knows that o is a double when toUpperCase is called, so it’s a type error.

It is important to understand that it is not the fact of declaring a variable with def that triggers type inference. Flow typing works for any variable of any type. Declaring a variable with an explicit type only constraints what you can assign to a variable:

@groovy.transform.TypeChecked
void flowTypingWithExplicitType() {
    List list = ['a','b','c']           (1)
    list = list*.toUpperCase()          (2)
    list = 'foo'                        (3)
}
1 list is declared as an unchecked List and assigned a list literal of `String`s
2 this line passes compilation because of flow typing: the type checker knows that list is at this point a List<String>
3 but you can’t assign a String to a List so this is a type checking error

You can also note that even if the variable is declared without generics information, the type checker knows what is the component type. Therefore, such code would fail compilation:

@groovy.transform.TypeChecked
void flowTypingWithExplicitType() {
    List list = ['a','b','c']           (1)
    list.add(1)                         (2)
}
1 list is inferred as List<String>
2 so adding an int to a List<String> is a compile-time error

Fixing this requires adding an explicit generic type to the declaration:

@groovy.transform.TypeChecked
void flowTypingWithExplicitType() {
    List<? extends Serializable> list = []                      (1)
    list.addAll(['a','b','c'])                                  (2)
    list.add(1)                                                 (3)
}
1 list declared as List<? extends Serializable> and initialized with an empty list
2 elements added to the list conform to the declaration type of the list
3 so adding an int to a List<? extends Serializable> is allowed

Flow typing has been introduced to reduce the difference in semantics between classic and static Groovy. In particular, consider the behavior of this code in Java:

public Integer compute(String str) {
    return str.length();
}
public String compute(Object o) {
    return "Nope";
}
// ...
Object string = "Some string";          (1)
Object result = compute(string);        (2)
System.out.println(result);             (3)
1 o is declared as an Object and assigned a String
2 we call the compute method with o
3 and print the result

In Java, this code will output 0, because method selection is done at compile time and based on the declared types. So even if o is a String at runtime, it is still the Object version which is called, because o has been declared as an Object. To be short, in Java, declared types are most important, be it variable types, parameter types or return types.

In Groovy, we could write:

int compute(String string) { string.length() }
String compute(Object o) { "Nope" }
Object o = 'string'
def result = compute(o)
println result

But this time, it will return 6, because the method which is chosen is chosen at runtime, based on the actual argument types. So at runtime, o is a String so the String variant is used. Note that this behavior has nothing to do with type checking, it’s the way Groovy works in general: dynamic dispatch.

In type checked Groovy, we want to make sure the type checker selects the same method at compile time, that the runtime would choose. It is not possible in general, due to the semantics of the language, but we can make things better with flow typing. With flow typing, o is inferred as a String when the compute method is called, so the version which takes a String and returns an int is chosen. This means that we can infer the return type of the method to be an int, and not a String. This is important for subsequent calls and type safety.

So in type checked Groovy, flow typing is a very important concept, which also implies that if @TypeChecked is applied, methods are selected based on the inferred types of the arguments, not on the declared types. This doesn’t ensure 100% type safety, because the type checker may select a wrong method, but it ensures the closest semantics to dynamic Groovy.

Advanced type inference

A combination of flow typing and least upper bound inference is used to perform advanced type inference and ensure type safety in multiple situations. In particular, program control structures are likely to alter the inferred type of a variable:

class Top {
   void methodFromTop() {}
}
class Bottom extends Top {
   void methodFromBottom() {}
}
def o
if (someCondition) {
    o = new Top()                               (1)
} else {
    o = new Bottom()                            (2)
}
o.methodFromTop()                               (3)
o.methodFromBottom()  // compilation error      (4)
1 if someCondition is true, o is assigned a Top
2 if someCondition is false, o is assigned a Bottom
3 calling methodFromTop is safe
4 but calling methodFromBottom is not, so it’s a compile time error

When the type checker visits an if/else control structure, it checks all variables which are assigned in if/else branches and computes the least upper bound of all assignments. This type is the type of the inferred variable after the if/else block, so in this example, o is assigned a Top in the if branch and a Bottom in the else branch. The LUB of those is a Top, so after the conditional branches, the compiler infers o as being a Top. Calling methodFromTop will therefore be allowed, but not methodFromBottom.

The same reasoning exists with closures and in particular closure shared variables. A closure shared variable is a variable which is defined outside of a closure, but used inside a closure, as in this example:

def text = 'Hello, world!'                          (1)
def closure = {
    println text                                    (2)
}
1 a variable named text is declared
2 text is used from inside a closure. It is a closure shared variable.

Groovy allows developers to use those variables without requiring them to be final. This means that a closure shared variable can be reassigned inside a closure:

String result
doSomething { String it ->
    result = "Result: $it"
}
result = result?.toUpperCase()

The problem is that a closure is an independent block of code that can be executed (or not) at any time. In particular, doSomething may be asynchronous, for example. This means that the body of a closure doesn’t belong to the main control flow. For that reason, the type checker also computes, for each closure shared variable, the LUB of all assignments of the variable, and will use that LUB as the inferred type outside of the scope of the closure, like in this example:

class Top {
   void methodFromTop() {}
}
class Bottom extends Top {
   void methodFromBottom() {}
}
def o = new Top()                               (1)
Thread.start {
    o = new Bottom()                            (2)
}
o.methodFromTop()                               (3)
o.methodFromBottom()  // compilation error      (4)
1 a closure-shared variable is first assigned a Top
2 inside the closure, it is assigned a Bottom
3 methodFromTop is allowed
4 methodFromBottom is a compilation error

Here, it is clear that when methodFromBottom is called, there’s no guarantee, at compile-time or runtime that the type of o will effectively be a Bottom. There are chances that it will be, but we can’t make sure, because it’s asynchronous. So the type checker will only allow calls on the least upper bound, which is here a Top.

Closures and type inference

The type checker performs special inference on closures, resulting on additional checks on one side and improved fluency on the other side.

Return type inference

The first thing that the type checker is capable of doing is infering the return type of a closure. This is simply illustrated in the following example:

@groovy.transform.TypeChecked
int testClosureReturnTypeInference(String arg) {
    def cl = { "Arg: $arg" }                                (1)
    def val = cl()                                          (2)

    val.length()                                            (3)
}
1 a closure is defined, and it returns a string (more precisely a GString)
2 we call the closure and assign the result to a variable
3 the type checker inferred that the closure would return a string, so calling length() is allowed

As you can see, unlike a method which declares its return type explicitly, there’s no need to declare the return type of a closure: its type is inferred from the body of the closure.

Closures vs methods

It’s worth noting that return type inference is only applicable to closures. While the type checker could do the same on a method, it is in practice not desirable: in general, methods can be overriden and it is not statically possible to make sure that the method which is called is not an overriden version. So flow typing would actually think that a method returns something, while in reality, it could return something else, like illustrated in the following example:

@TypeChecked
class A {
    def compute() { 'some string' }             (1)
    def computeFully() {
        compute().toUpperCase()                 (2)
    }
}
@TypeChecked
class B extends A {
    def compute() { 123 }                       (3)
}
1 class A defines a method compute which effectively returns a String
2 this will fail compilation because the return type of compute is def(aka Object)
3 class B extends A and redefines compute, this type returning an int

As you can see, if the type checker relied on the inferred return type of a method, with flow typing, the type checker could determine that it is ok to call toUpperCase. It is in fact an error, because a subclass can override compute and return a different object. Here, B#compute returns an int, so someone calling computeFully on an instance of B would see a runtime error. The compiler prevents this from happening by using the declared return type of methods instead of the inferred return type.

For consistency, this behavior is the same for every method, even if they are static or final.

Parameter type inference

In addition to the return type, it is possible for a closure to infer its parameter types from the context. There are two ways for the compiler to infer the parameter types:

  • through implicit SAM type coercion

  • through API metadata

To illustrate this, lets start with an example that will fail compilation due to the inability for the type checker to infer the parameter types:

class Person {
    String name
    int age
}

void inviteIf(Person p, Closure<Boolean> predicate) {           (1)
    if (predicate.call(p)) {
        // send invite
        // ...
    }
}

@groovy.transform.TypeChecked
void failCompilation() {
    Person p = new Person(name: 'Gerard', age: 55)
    inviteIf(p) {                                               (2)
        it.age >= 18 // No such property: age                   (3)
    }
}
1 the inviteIf method accepts a Person and a Closure
2 we call it with a Person and a Closure
3 yet it is not statically known as being a Person and compilation fails

In this example, the closure body contains it.age. With dynamic, not type checked code, this would work, because the type of it would be a Person at runtime. Unfortunately, at compile-time, there’s no way to know what is the type of it, just by reading the signature of inviteIf.

Explicit closure parameters

To be short, the type checker doesn’t have enough contextual information on the inviteIf method to determine statically the type of it. This means that the method call needs to be rewritten like this:

inviteIf(p) { Person it ->                                  (1)
    it.age >= 18
}
1 the type of it needs to be declared explicitly

By explicitly declaring the type of the it variable, you can workaround the problem and make this code statically checked.

Parameters inferred from single-abstract method types

For an API or framework designer, there are two ways to make this more elegant for users, so that they don’t have to declare an explicit type for the closure parameters. The first one, and easiest, is to replace the closure with a SAM type:

interface Predicate<On> { boolean apply(On e) }                 (1)

void inviteIf(Person p, Predicate<Person> predicate) {          (2)
    if (predicate.apply(p)) {
        // send invite
        // ...
    }
}

@groovy.transform.TypeChecked
void passesCompilation() {
    Person p = new Person(name: 'Gerard', age: 55)

    inviteIf(p) {                                               (3)
        it.age >= 18                                            (4)
    }
}
1 declare a SAM interface with an apply method
2 inviteIf now uses a Predicate<Person> instead of a Closure<Boolean>
3 there’s no need to declare the type of the it variable anymore
4 it.age compiles properly, the type of it is inferred from the Predicate#apply method signature
By using this technique, we leverage the automatic coercion of closures to SAM types feature of Groovy. The question whether you should use a SAM type or a Closure really depends on what you need to do. In a lot of cases, using a SAM interface is enough, especially if you consider functional interfaces as they are found in Java 8. However, closures provide features that are not accessible to functional interfaces. In particular, closures can have a delegate, and owner and can be manipulated as objects (for example, cloned, serialized, curried, …) before being called. They can also support multiple signatures (polymorphism). So if you need that kind of manipulation, it is preferable to switch to the most advanced type inference annotations which are described below.

The original issue that needs to be solved when it comes to closure parameter type inference, that is to say, statically determining the types of the arguments of a closure without having to have them explicitly declared, is that the Groovy type system inherits the Java type system, which is insufficient to describe the types of the arguments.

The @ClosureParams annotation

Groovy provides an annotation, @ClosureParams which is aimed at completing type information. This annotation is primarily aimed at framework and API developers who want to extend the capabilities of the type checker by providing type inference metadata. This is important if your library makes use of closures and that you want the maximum level of tooling support too.

Let’s illustrate this by fixing the original example, introducing the @ClosureParams annotation:

import groovy.transform.stc.ClosureParams
import groovy.transform.stc.FirstParam
void inviteIf(Person p, @ClosureParams(FirstParam) Closure<Boolean> predicate) {        (1)
    if (predicate.call(p)) {
        // send invite
        // ...
    }
}
inviteIf(p) {                                                                       (2)
    it.age >= 18
}
1 the closure parameter is annotated with @ClosureParams
2 it’s not necessary to use an explicit type for it, which is inferred

The @ClosureParams annotation minimally accepts one argument, which is named a type hint. A type hint is a class which is reponsible for completing type information at compile time for the closure. In this example, the type hint being used is groovy.transform.stc.FirstParam which indicated to the type checker that the closure will accept one parameter whose type is the type of the first parameter of the method. In this case, the first parameter of the method is Person, so it indicates to the type checker that the first parameter of the closure is in fact a Person.

The second argument is optional and named options. It’s semantics depends on the type hint class. Groovy comes with various bundled type hints, illustrated in the table below:

Table 3. Predefined type hints
Type hint Polymorphic? Description and examples

FirstParam
SecondParam
ThirdParam

No

The first (resp. second, third) parameter type of the method

import groovy.transform.stc.FirstParam
void doSomething(String str, @ClosureParams(FirstParam) Closure c) {
    c(str)
}
doSomething('foo') { println it.toUpperCase() }
import groovy.transform.stc.SecondParam
void withHash(String str, int seed, @ClosureParams(SecondParam) Closure c) {
    c(31*str.hashCode()+seed)
}
withHash('foo', (int)System.currentTimeMillis()) {
    int mod = it%2
}
import groovy.transform.stc.ThirdParam
String format(String prefix, String postfix, String o, @ClosureParams(ThirdParam) Closure c) {
    "$prefix${c(o)}$postfix"
}
assert format('foo', 'bar', 'baz') {
    it.toUpperCase()
} == 'fooBAZbar'

FirstParam.FirstGenericType
SecondParam.FirstGenericType
ThirdParam.FirstGenericType

No

The first generic type of the first (resp. second, third) parameter of the method

import groovy.transform.stc.FirstParam
public <T> void doSomething(List<T> strings, @ClosureParams(FirstParam.FirstGenericType) Closure c) {
    strings.each {
        c(it)
    }
}
doSomething(['foo','bar']) { println it.toUpperCase() }
doSomething([1,2,3]) { println(2*it) }

Variants for SecondGenericType and ThirdGenericType exist for all FirstParam, SecondParam and ThirdParam type hints.

SimpleType

No

A type hint for which the type of closure parameters comes from the options string.

import groovy.transform.stc.SimpleType
public void doSomething(@ClosureParams(value=SimpleType,options=['java.lang.String','int']) Closure c) {
    c('foo',3)
}
doSomething { str, len ->
    assert str.length() == len
}

This type hint supports a single signature and each of the parameter is specified as a value of the options array using a fully-qualified type name or a primitive type.

MapEntryOrKeyValue

Yes

A dedicated type hint for closures that either work on a Map.Entry single parameter, or two parameters corresponding to the key and the value.

import groovy.transform.stc.MapEntryOrKeyValue
public <K,V> void doSomething(Map<K,V> map, @ClosureParams(MapEntryOrKeyValue) Closure c) {
    // ...
}
doSomething([a: 'A']) { k,v ->
    assert k.toUpperCase() == v.toUpperCase()
}
doSomething([abc: 3]) { e ->
    assert e.key.length() == e.value
}

This type hint requires that the first argument is a Map type, and infers the closure parameter types from the map actual key/value types.

FromAbstractTypeMethods

Yes

Infers closure parameter types from the abstract method of some type. A signature is inferred for each abstract method.

import groovy.transform.stc.FromAbstractTypeMethods
abstract class Foo {
    abstract void firstSignature(int x, int y)
    abstract void secondSignature(String str)
}
void doSomething(@ClosureParams(value=FromAbstractTypeMethods, options=["Foo"]) Closure cl) {
    // ...
}
doSomething { a, b -> a+b }
doSomething { s -> s.toUpperCase() }

If there are multiple signatures like in the example above, the type checker will only be able to infer the types of the arguments if the arity of each method is different. In the example above, firstSignature takes 2 arguments and secondSignature takes 1 argument, so the type checker can infer the argument types based on the number of arguments.

FromString

Yes

Infers the closure parameter typs from the options argument. The options argument consists of an array of comma-separated non-primitive types. Each element of the array corresponds to a single signature, and each comma in an element separate parameters of the signature. In short, this is the most generic type hint, and each string of the options map is parsed as if it was a signature literal. While being very powerful, this type hint must be avoided if you can because it increases the compilation times due to the necessity of parsing the type signatures.

A single signature for a closure accepting a String:

import groovy.transform.stc.FromString
void doSomething(@ClosureParams(value=FromString, options=["String","String,Integer"]) Closure cl) {
    // ...
}
doSomething { s -> s.toUpperCase() }
doSomething { s,i -> s.toUpperCase()*i }

A polymorphic closure, accepting either a String or a String, Integer:

import groovy.transform.stc.FromString
void doSomething(@ClosureParams(value=FromString, options=["String","String,Integer"]) Closure cl) {
    // ...
}
doSomething { s -> s.toUpperCase() }
doSomething { s,i -> s.toUpperCase()*i }

A polymorphic closure, accepting either a T or a pair T,T:

import groovy.transform.stc.FromString
public <T> void doSomething(T e, @ClosureParams(value=FromString, options=["T","T,T"]) Closure cl) {
    // ...
}
doSomething('foo') { s -> s.toUpperCase() }
doSomething('foo') { s1,s2 -> assert s1.toUpperCase() == s2.toUpperCase() }
Even though you use FirstParam, SecondParam or ThirdParam as a type hint, it doesn’t stricly mean that the argument which will be passed to the closure will be the first (resp. second, third) argument of the method call. It only means that the type of the parameter of the closure will be the same as the type of the first (resp. second, third) argument of the method call.

In short, the lack of the @ClosureParams annotation on a method accepting a Closure will not fail compilation. If present (and it can be present in Java sources as well as Groovy sources), then the type checker has more information and can perform additional type inference. This makes this feature particularily interesting for framework developers.

@DelegatesTo

The @DelegatesTo annotation is used by the type checker to infer the type of the delegate. It allows the API designer to instruct the compiler what is the type of the delegate and the delegation strategy. The @DelegatesTo annotation is discussed in a specific section.

Static compilation (WIP)
Dynamic vs static

In the type checking section, we have seen that Groovy provides optional type checking thanks to the @TypeChecked annotation. The type checker runs at compile time and performs a static analysis of dynamic code. The program will behave exactly the same whether type checking has been enabled or not. This means that the @TypeChecked annotation is neutral with regards to the semantics of a program. Even though it may be necessary to add type information in the sources so that the program is considered type safe, in the end, the semantics of the program are the same.

While this may sound fine, there is actually one issue with this: type checking of dynamic code, done at compile time, is by definition only correct if no runtime specific behavior occurs. For example, the following program passes type checking:

class Computer {
    int compute(String str) {
        str.length()
    }
    String compute(int x) {
        String.valueOf(x)
    }
}

@groovy.transform.TypeChecked
void test() {
    def computer = new Computer()
    computer.with {
        assert compute(compute('foobar')) =='6'
    }
}

There are two compute methods. One accepts a String and returns an int, the other accepts an int and returns a String. If you compile this, it is considered type safe: the inner compute('foobar') call will return an int, and calling compute on this int will in turn return a String.

Now, before calling test(), consider adding the following line:

Computer.metaClass.compute = { String str -> new Date() }

Using runtime metaprogramming, we’re actually modifying the behavior of the compute(String) method, so that instead of returning the length of the provided argument, it will return a Date. If you execute the program, it will fail at runtime. Since this line can be added from anywhere, in any thread, there’s absolutely no way for the type checker to statically make sure that no such thing happens. In short, the type checker is vulnerable to monkey patching. This is just one example, but this illustrates the concept that doing static analysis of a dynamic program is inherently wrong.

The Groovy language provides an alternative annotation to @TypeChecked which will actually make sure that the methods which are inferred as being called will effectively be called at runtime. This annotation turns the Groovy compiler into a static compiler, where all method calls are resolved at compile time and the generated bytecode makes sure that this happens: the annotation is @groovy.transform.CompileStatic.

The @CompileStatic annotation

The @CompileStatic annotation can be added anywhere the @TypeChecked annotation can be used, that is to say on a class or a method. It is not necessary to add both @TypeChecked and @CompileStatic, as @CompileStatic performs everything @TypeChecked does, but in addition triggers static compilation.

Let’s take the example which failed, but this time let’s replace the @TypeChecked annotation with @CompileStatic:

class Computer {
    int compute(String str) {
        str.length()
    }
    String compute(int x) {
        String.valueOf(x)
    }
}

@groovy.transform.CompileStatic
void test() {
    def computer = new Computer()
    computer.with {
        assert compute(compute('foobar')) =='6'
    }
}
Computer.metaClass.compute = { String str -> new Date() }
run()

This is the only difference. If we execute this program, this time, there is no runtime error. The test method became immune to monkey patching, because the compute methods which are called in its body are linked at compile time, so even if the metaclass of Computer changes, the program still behaves as expected by the type checker.

Key benefits

There are several benefits of using @CompileStatic on your code:

The performance improvements depend on the kind of program you are executing. It it is I/O bound, the difference between statically compiled code and dynamic code is barely noticeable. On highly CPU intensive code, since the bytecode which is generated is very close, if not equal, to the one that Java would produce for an equivalent program, the performance is greatly improved.

Using the invokedynamic version of Groovy, which is accessible to people using JDK 7 and above, the performance of the dynamic code should be very close to the performance of statically compiled code. Sometimes, it can even be faster! There is only one way to determine which version you should choose: measuring. The reason is that depending on your program and the JVM that you use, the performance can be significantly different. In particular, the invokedynamic version of Groovy is very sensitive to the JVM version in use.