blob: 43f86a99d93327a87f95d0e68298e1379efa43c2 [file] [log] [blame]
//////////////////////////////////////////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
//////////////////////////////////////////
= Closures
:lambdas: http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html[lambda expressions in Java 8]
This chapter covers Groovy Closures. A closure in Groovy is an open, anonymous, block of code that can take arguments,
return a value and be assigned to a variable. A closure may reference variables declared in its surrounding scope. In
opposition to the formal definition of a closure, `Closure` in the Groovy language can also contain free variables which
are defined outside of its surrounding scope. While breaking the formal concept of a closure, it offers a variety of
advantages which are described in this chapter.
== Syntax
=== Defining a closure
A closure definition follows this syntax:
[source,groovy]
-----------------------------------
{ [closureParameters -> ] statements }
-----------------------------------
Where `+[closureParameters->]+` is an optional comma-delimited list of
parameters, and statements are 0 or more Groovy statements. The parameters
look similar to a method parameter list, and these parameters may be
typed or untyped.
When a parameter list is specified, the `+->+` character
is required and serves to separate the arguments from the closure body.
The _statements_ portion consists of 0, 1, or many Groovy statements.
Some examples of valid closure definitions:
[source,groovy]
-----------------------------------------------------------
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_1,indent=0]
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_1bis,indent=0]
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_2,indent=0]
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_3,indent=0]
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_4,indent=0]
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_5,indent=0]
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_6,indent=0]
-----------------------------------------------------------
<1> A closure referencing a variable named `item`
<2> It is possible to explicitly separate closure parameters from code by adding an arrow (`+->+`)
<3> A closure using an implicit parameter (`it`)
<4> An alternative version where `it` is an explicit parameter
<5> In that case it is often better to use an explicit name for the parameter
<6> A closure accepting two typed parameters
<7> A closure can contain multiple statements
[[closure-as-object]]
=== Closures as an object
A closure is an instance of the `groovy.lang.Closure` class, making it assignable to a variable or a field as any
other variable, despite being a block of code:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_is_an_instance_of_Closure,indent=0]
----
<1> You can assign a closure to a variable, and it is an instance of `groovy.lang.Closure`
<2> If not using `def`, you can assign a closure to a variable of type `groovy.lang.Closure`
<3> Optionally, you can specify the return type of the closure by using the generic type of `groovy.lang.Closure`
=== Calling a closure
A closure, as an anonymous block of code, can be called like any other method. If you define a closure which takes
no argument like this:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_call_1,indent=0]
----
Then the code inside the closure will only be executed when you _call_ the closure, which can be done by using the
variable as if it was a regular method:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_call_1_direct,indent=0]
----
Alternatively, you can be explicit and use the `call` method:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_call_1_explicit,indent=0]
----
The principle is the same if the closure accepts arguments:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_call_2,indent=0]
----
<1> define a closure which accepts an `int` as a parameter
<2> it can be called directly
<3> or using the `call` method
<4> same goes for a closure with an implicit argument (`it`)
<5> which can be called directly using `(arg)`
<6> or using `call`
Unlike a method, a closure *always* returns a value when called. The next section discusses how to declare closure arguments, when to use them and what is the <<implicit-it,implicit
"it" parameter>>.
== Parameters
=== Normal parameters
Parameters of closures follow the same principle as parameters of regular methods:
* an optional type
* a name
* an optional default value
Parameters are separated with commas:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_param_declaration,indent=0]
----
[[implicit-it]]
=== Implicit parameter
When a closure does not explicitly define a parameter list (using `+->+`), a closure *always* defines an implicit
parameter, named `it`. This means that this code:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=implicit_it,indent=0]
----
is stricly equivalent to this one:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=implicit_it_equiv,indent=0]
----
If you want to declare a closure which accepts no argument and must be restricted to calls without arguments,
then you *must* declare it with an explicit empty argument list:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_no_arg_def,indent=0]
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_no_arg_fail,indent=0]
----
=== Varargs
It is possible for a closure to declare variable arguments like any other method. _Vargs_ methods are methods that
can accept a variable number of arguments if the last parameter is of variable length (or an array) like in the next
examples:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_vargs,indent=0]
----
<1> A closure accepting a variable number of strings as first parameter
<2> It may be called using any number of arguments *without* having to explicitly wrap them into an array
<3> The same behavior is directly available if the _args_ parameter is declared as an array
<4> As long as the *last* parameter is an array or an explicit vargs type
== Delegation strategy
=== Groovy closures vs lambda expressions
Groovy defines closures as <<closure-as-object, instances of the Closure class>>. It makes it very different from
{lambdas}. Delegation is a
key concept in Groovy closures which has no equivalent in lambdas. The ability to _change the delegate_ or _change the
delegation strategy_ of closures make it possible to design beautiful domain specific languages (DSLs) in Groovy.
[[closure-owner]]
=== Owner, delegate and this
To understand the concept of delegate, we must first explain the meaning of `this` inside a closure. A closure actually
defines 3 distinct things:
- `this` corresponds to the _enclosing class_ where the closure is defined
- `owner` corresponds to the _enclosing object_ where the closure is defined, which may be either a class or a closure
- `delegate` corresponds to a third party object where methods calls or properties are resolved whenever the receiver of
the message is not defined
[[closure-this]]
==== The meaning of this
In a closure, calling `getThisObject` will return the enclosing class where the closure is defined. It is equivalent to
using an explicit `this`:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_this,indent=0]
----
<1> a closure is defined inside the `Enclosing` class, and returns `getThisObject`
<2> calling the closure will return the instance of `Enclosing` where the closure is defined
<3> in general, you will just want to use the shortcut `this` notation
<4> and it returns *exactly* the same object
<5> if the closure is defined in a inner class
<6> `this` in the closure *will* return the inner class, not the top-level one
<7> in case of nested closures, like here `cl` being defined inside the scope of `nestedClosures`
<8> then `this` corresponds to the closest outer class, not the enclosing closure!
It is of course possible to call methods from the enclosing class this way:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_this_call,indent=0]
----
<1> the closure calls `toString` on `this`, which will actually call the `toString` method on the enclosing object,
that is to say the `Person` instance
==== Owner of a closure
The owner of a closure is very similar to the definition of <<closure-this,this in a closure>> with a subtle difference:
it will return the direct enclosing object, be it a closure or a class:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_owner,indent=0]
----
<1> a closure is defined inside the `Enclosing` class, and returns `getOwner`
<2> calling the closure will return the instance of `Enclosing` where the closure is defined
<3> in general, you will just want to use the shortcut `owner` notation
<4> and it returns *exactly* the same object
<5> if the closure is defined in a inner class
<6> `owner` in the closure *will* return the inner class, not the top-level one
<7> but in case of nested closures, like here `cl` being defined inside the scope of `nestedClosures`
<8> then `owner` corresponds to the enclosing closure, hence a different object from `this`!
==== Delegate of a closure
The delegate of a closure can be accessed by using the `delegate` property or calling the `getDelegate` method. It is a
powerful concept for building domain specific languages in Groovy. While <<this,closure-this>> and <<owner,closure-owner>>
refer to the lexical scope of a closure, the delegate is a user defined object that a closure will use. By default, the
delegate is set to `owner`:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=delegate_is_owner,indent=0]
----
<1> you can get the delegate of a closure calling the `getDelegate` method
<2> or using the `delegate` property
<3> both return the same object
<4> which is the enclosing class or closure
<5> in particular in case of nested closures
<6> `delegate` will correspond to the `owner`
The delegate of a closure can be changed to *any object*. Let's illustrate this by creating two classes which are not
subclasses of each other but both define a property called `name`:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=change_delegate_classes,indent=0]
----
Then let's define a closure which fetches the `name` property on the delegate:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=change_delegate_closure,indent=0]
----
Then by changing the delegate of the closure, you can see that the target object will change:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=change_delegate_asserts,indent=0]
----
At this point, the behavior is not different from having a `target` variable defined in the lexical scope of the closure:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=delegate_alernative,indent=0]
----
However, there are major differences:
* in the last example, _target_ is a local variable referenced from within the closure
* the delegate can be used transparently, that is to say without prefixing method calls with `delegate.` as explained
in the next paragraph.
==== Delegation strategy
Whenever, in a closure, a property is accessed without explicitly setting a receiver object, then a delegation strategy
is involved:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=delegation_strategy_intro,indent=0]
----
<1> `name` is not referencing a variable in the lexical scope of the closure
<2> we can change the delegate of the closure to be an instance of `Person`
<3> and the method call will succeed
The reason this code works is that the `name` property will be resolved transparently on the `delegate` object! This is
a very powerful way to resolve properties or method calls inside closures. There's no need to set an explicit `delegate.`
receiver: the call will be made because the default delegation strategy of the closure makes it so. A closure actually
defines multiple resolution strategies that you can choose:
* `Closure.OWNER_FIRST` is the *default strategy*. If a property/method exists on the *owner*, then it will be called on
the owner. If not, then the *delegate* is used.
* `Closure.DELEGATE_FIRST` reverses the logic: the *delegate* is used first, then the *owner*
* `Closure.OWNER_ONLY` will only resolve the property/method lookup on the owner: the delegate will be ignored.
* `Closure.DELEGATE_ONLY` will only resolve the property/method lookup on the delegate: the owner will be ignored.
* `Closure.TO_SELF` can be used by developers who need advanced meta-programming techniques and wish to implement a
custom resolution strategy: the resolution will not be made on the owner or the delegate but only on the closure class
itself. It makes only sense to use this if you implement your own subclass of `Closure`.
Let's illustrate the default "owner first" strategy with this code:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_owner_first,indent=0]
----
<1> for the illustration, we define a closure member which references "name"
<2> both the `Person` and the `Thing` class define a `name` property
<3> Using the default strategy, the `name` property is resolved on the owner first
<4> so if we change the `delegate` to `t` which is an instance of `Thing`
<5> there is no change in the result: `name` is first resolved on the `owner` of the closure
However, it is possible to change the resolution strategy of the closure:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_delegate_first,indent=0]
----
By changing the `resolveStrategy`, we are modifying the way Groovy will resolve the "implicit this" references: in this
case, `name` will first be looked in the delegate, then if not found, on the owner. Since `name` is defined in the
delegate, an instance of `Thing`, then this value is used.
The difference between "delegate first" and "delegate only" or "owner first" and "owner only" can be illustrated if one
of the delegate (resp. owner) does *not* have such a method or property:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=delegate_only,indent=0]
----
In this example, we define two classes which both have a `name` property but only the `Person` class declares an `age`.
The `Person` class also declares a closure which references `age`. We can change the default resolution strategy from
"owner first" to "delegate only". Since the owner of the closure is the `Person` class, then we can check that if the
delegate is an instance of `Person`, calling the closure is successful, but if we call it with a delegate being an
instance of `Thing`, it fails with a `groovy.lang.MissingPropertyException`. Despite the closure being defined inside
the `Person` class, the owner is not used.
NOTE: A comprehensive explanation about how to use this feature to develop DSLs can be found in a
link:core-domain-specific-languages.html[dedicated section of the manual].
== Closures in GStrings
Take the following code:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_eager_intro,indent=0]
----
The code behaves as you would expect, but what happens if you add:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_eager_outro,indent=0]
----
You will see that the assert fails! There are two reasons for this:
* a GString only evaluates lazily the `toString` representation of values
* the syntax `${x}` in a GString does *not* represent a closure but an *expression* to `$x`, evaluated when the GString
is created.
In our example, the `GString` is created with an expression referencing `x`. When the `GString` is created, the *value*
of `x` is 1, so the `GString` is created with a value of 1. When the assert is triggered, the `GString` is evaluated
and 1 is converted to a `String` using `toString`. When we change `x` to 2, we did change the value of `x`, but it is
a different object, and the `GString` still references the old one.
TIP: A `GString` will only change its `toString` representation if the values it references are mutating. If the references
change, nothing will happen.
If you need a real closure in a GString and for example enforce lazy evaluation of variables, you need to use the
alternate syntax `${-> x}` like in the fixed example:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_lazy,indent=0]
----
And let's illustrate how it differs from mutation with this code:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_mutation,indent=0]
----
<1> the `Person` class has a `toString` method returning the `name` property
<2> we create a first `Person` named _Sam_
<3> we create another `Person` named _Lucy_
<4> the `p` variable is set to `Sam`
<5> and a closure is created, referencing the value of `p`, that is to say _Sam_
<6> so when we evaluate the string, it returns _Sam_
<7> if we change `p` to _Lucy_
<8> the string still evaluates to _Sam_ because it was the *value* of `p` when the `GString` was created
<9> so if we mutate _Sam_ to change his name to _Lucy_
<10> this time the `GString` is correctly mutated
So if you don't want to rely on mutating objects or wrapping objects, you *must* use closures in `GString` by explicitly
declaring an empty argument list:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_no_mutation,indent=0]
----
== Closure coercion
Closures can be converted into interfaces or single-abstract method types. Please refer to
link:core-semantics.html#closure-coercion[this section of the manual] for a complete description.
== Functional programming
Closures, like {lambdas} are at the core of the functional programming paradigm in Groovy. Some functional programming
operations on functions are available directly on the `Closure` class, like illustrated in this section.
=== Currying
In Groovy, currying refers to the concept of partial application. It does *not* correspond to the real concept of currying
in functional programming because of the different scoping rules that Groovy applies on closures. Currying in Groovy will
let you set the value of one parameter of a closure, and it will return a new closure accepting one less argument.
==== Left currying
Left currying is the fact of setting the left-most parameter of a closure, like in this example:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=left_curry,indent=0]
----
<1> the `nCopies` closure defines two parameters
<2> `curry` will set the first parameter to `2`, creating a new closure (function) which accepts a single `String`
<3> so the new function call be called with only a `String`
<4> and it is equivalent to calling `nCopies` with two parameters
==== Right currying
Similarily to left currying, it is possible to set the right-most parameter of a closure:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=right_curry,indent=0]
----
<1> the `nCopies` closure defines two parameters
<2> `rcurry` will set the last parameter to `bla`, creating a new closure (function) which accepts a single `int`
<3> so the new function call be called with only an `int`
<4> and it is equivalent to calling `nCopies` with two parameters
==== Index based currying
In case a closure accepts more than 2 parameters, it is possible to set an arbitrary parameter using `ncurry`:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=ncurry,indent=0]
----
<1> the `volume` function defines 3 parameters
<2> `ncurry` will set the second parameter (index = 1) to `2d`, creating a new volume function which accepts length and height
<3> that function is equivalent to calling `volume` omitting the width
<4> it is also possible to set multiple parameters, starting from the specified index
<5> the resulting function accepts as many parameters as the initial one minus the number of parameters set by `ncurry`
=== Memoization
Memoization allows the result of the call of a closure to be cached. It is interesting if the computation done by a
function (closure) is slow, but you know that this function is going to be called often with the same arguments. A
typical example is the Fibonacci suite. A naive implementation may look like this:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=naive_fib,indent=0]
----
It is a naive implementation because 'fib' is often called recursively with the same arguments, leading to an exponential
algorithm:
- computing `fib(15)` requires the result of `fib(14)` and `fib(13)`
- computing `fib(14)` requires the result of `fib(13)` and `fib(12)`
Since calls are recursive, you can already see that we will compute the same values again and again, although they could
be cached. This naive implementation can be "fixed" by caching the result of calls using `memoize`:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=memoized_fib,indent=0]
----
WARNING: The cache works *using the actual values of the arguments*. This means that you should be very careful if you use
memoization with something else than primitive or boxed primitive types.
The behavior of the cache can be tweaked using alternate methods:
* `memoizeAtMost` will generate a new closure which caches *at most* _n_ values
* `memoizeAtLeast` will generate a new closure which caches *at least* _n_ values
* `memoizeBetween` will generate a new closure which caches *at least* _n_ values and *at most* _n_ values
The cache used in all memoize variants is a LRU cache.
=== Composition
Closure composition corresponds to the concept of function composition, that is to say creating a new function by
composing two or more functions (chaining calls), as illustrated in this example:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_composition,indent=0]
----
=== Trampoline
Recursive algorithms are often restricted by a physical limit: the maximum stack height. For example, if you call a method
that recursively calls itself too deep, you will eventually receive a `StackOverflowException`.
An approach that helps in those situations is by using `Closure` and its trampoline capability.
Closures are wrapped in a `TrampolineClosure`. Upon calling, a trampolined `Closure` will call the original `Closure` waiting
for its result. If the outcome of the call is another instance of a `TrampolineClosure`, created perhaps as a result
to a call to the `trampoline()` method, the `Closure` will again be invoked. This repetitive invocation of returned
trampolined Closures instances will continue until a value other than a trampolined `Closure` is returned. That value
will become the final result of the trampoline. That way, calls are made serially, rather than filling the stack.
Heres an example of the use of `trampoline()` to implement the factorial function:
[source,groovy]
----
include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=trampoline,indent=0]
----
=== Method pointers
It is often practical to be able to use a regular method as a closure. For example, you might want to use the currying
abilities of a closure, but those are not available to normal methods. In Groovy, you can obtain a closure from any
method with the link:core-operators.html#method-pointer-operator[method pointer operator].