Why isn't the value of an instance variable set in a Groovy closure visible outside of it?
Question
Why methodA()
print set within run
instead set within closure
?
Sample code
class GroovyClosureVariableScopingTest extends Script {
String s
Object run() {
s = "set within run"
println "value of s in run(): $s"
[1].each {
s = "set within closure"
println "value of s in each()-closure: $s"
methodA()
}
}
void methodA() {
println "value of s in methodA(): $s"
}
}
Actual output
value of s in run(): set within run
value of s in each()-closure: set within closure
value of s in methodA(): set within run // <- Surprised to see the original value
Expected Result
value of s in run(): set in run
value of s in each()-closure: set within closure
value of s in methodA(): set within closure // <- Whould have expected this value
Development of
I didn't quite understand how the variable scope works in the above example. I would expect to s
be a property (public instance variable) of the class and I thought I was assigning a value from each
-closure to it to be stored. But it doesn't seem to be the case.
Why s
doesn't it store the value that was assigned from the closure?
Solution / workaround
Passing s
as an argument to methodA()
works. See the lines commented with // Change
.
class GroovyClosureVariableScopingTest extends Script {
String s
Object run() {
s = "set within run"
println "value of s in run(): $s"
[1].each {
s = "set within closure"
println "value of s in each()-closure: $s"
methodA(s) // Change
}
}
void methodA(s) { // Change
println "value of s in methodA(): $s"
}
}
Link
At the same time, variables are still generally available for the enclosing scope, so the closure can read / modify any such values, and code from the outer scope can read / modify the same variables.
Versions
- Groovy 1.8.6
- Groovy -Eclipse plugin 2.8.0
- Eclipse 3.8.1 Platform
source to share
After user cfrick confirmed that it works on his machine, I ran it from the console and it actually works.
On the console
C:\temp>java -jar C:\...\lib\groovy-all-1.8.6.jar C:\temp\GroovyClosureVariableScopingTest.groovy
value of s in run(): set within run
value of s in each()-closure: set within closure
value of s in methodA(): set within closure // <- Here
With a clean install of Eclipse
But I still don't get the original script to run with a clean install
- Eclipse 4.3 Kepler
- Groovy Eclipse Plugin http://dist.springsource.org/release/GRECLIPSE/e4.3/
- Groovy Compiler 1.8.x as well as 2.3.4
Summary
I still don't know why this doesn't work - even with a clean install of Eclipse. However, it works from the console, it works on cfrick machine and there is a workaround.
source to share