Reputation: 157
I'm a Groovy newbie. When I run the following script Groovy reports "No such property: tailFactorial for class ***". Shouldn't the closure access the local variable tailFactorial?
def factorial(int factorialFor) {
def tailFactorial = { int number, BigInteger theFactorial = 1 ->
number == 1 ? theFactorial :
tailFactorial.trampoline(number - 1, number * theFactorial)
}.trampoline()
tailFactorial(factorialFor)
}
println "factorial of 5 is ${factorial(5)}"
println "Number of bits in the result is ${factorial(5000).bitCount()}"
What makes me confused is that If I change the above code to the following one:
def factorial(int factorialFor) {
def tailFactorial
tailFactorial = { int number, BigInteger theFactorial = 1 ->
number == 1 ? theFactorial :
tailFactorial.trampoline(number - 1, number * theFactorial)
}.trampoline()
tailFactorial(factorialFor)
}
println "factorial of 5 is ${factorial(5)}"
println "Number of bits in the result is ${factorial(5000).bitCount()}"
It runs well.
We can find that the only difference between the two pieces of code is that in the first one we declare and define the closure at the same time but in the second one we declare the closure without definition. The definition goes in a separated line.
How could this happen? I'm using Groovy 2.4.3 and Java 7 and look forward to your help. Thanks.
Upvotes: 2
Views: 408
Reputation: 37008
You can not access the variable, to which the closure will be assigned to, since it pops into existence after the right hand side (or at least get's not captured).
This is the reason, why the second example (the same code like in the groovy docs) works. The variable is already declared and the closure can capture it by this name. (remember, that the closure code it not executed at once - at this exact point in time tailFactorial
would be null).
But since you are only interested in the trampoline call on the closure, you can simply call it on the closure itself. trampoline
is a method of Closure
:
def factorial(int factorialFor) {
def tailFactorial = { int number, BigInteger theFactorial = 1 ->
number == 1 ? theFactorial :
// XXX
trampoline(number - 1, number * theFactorial)
}.trampoline()
tailFactorial(factorialFor)
}
println "factorial of 5 is ${factorial(5)}"
println "Number of bits in the result is ${factorial(5000).bitCount()}"
Upvotes: 5