Reputation: 24907
I have a question about scoping rules in Groovy. In the following snippet, I have three variables, a
has local scope, b
has script scope, and c
should get script scope as well using the @Field
annotation.
#!/usr/bin/groovy
import groovy.transform.Field;
//println org.codehaus.groovy.runtime.InvokerHelper.getVersion()
def a = 42;
b = "Tea"
@Field def c = "Cheese"
void func()
{
// println a // MissingPropertyException
println b // prints "Tea"
println c // prints "Cheese" with groovy 2.1.2, MissingPropertyException with groovy 1.8.6
}
class Main
{
def method()
{
// println a // MissingPropertyException
// println b // MissingPropertyException
// println c // MissingPropertyException with both 1.8.6. and 2.1.2
}
}
func();
new Main().method();
I get MissingPropertyException
s on the lines indicated with comments. The exceptions on a
are expected, as that variable has local scope. But I would expect b
to be accessible inside method()
- it isn't.
@Field
doesn't do anything in groovy 1.8.6, although after upgrading it works, so I guess that is an old bug. Nevertheless, c
is inaccessible inside method()
with either version.
So my questions are:
@Field
inside
method()
? method()
?Upvotes: 41
Views: 52415
Reputation: 66059
When you have methods or statements outside of a class
declaration in a groovy script, an implicit class is created. To answer your questions:
In your example, func()
can access the field c
because they are both members of the implicit class. The Main
class is not, so it can't.
You need to pass a reference to the script variable to method()
. One way is to pass the implicitly defined binding
object, through which you can access all the script scope variables.
Example:
#!/usr/bin/groovy
import groovy.transform.Field;
//println org.codehaus.groovy.runtime.InvokerHelper.getVersion()
def a = 42;
b = "Tea"
@Field def c = "Cheese"
void func()
{
// println a // MissingPropertyException
println b // prints "Tea"
println c // prints "Cheese" with groovy 2.1.2, MissingPropertyException with groovy 1.8.6
}
class Main
{
def scriptObject
def binding
def method()
{
// println a // MissingPropertyException
println binding.b
println scriptObject.c
}
}
func();
new Main(scriptObject: this, binding: binding).method();
Upvotes: 40
Reputation: 171054
This script and Main
are generated as two separate classes inside the same file.
As Main
is not an internal class of the Script class, it cannot see the java.lang.Object c
field inside the script class.
You would either have to explicitly wrap this script in a class with a static main( args )
method (and an internal Main
class) or you would need to pass an instance of the script class to the method like: Main.method( this )
This is the sort of thing that the above script generates:
class Script032034034 {
Object c
Script032034034() {
c = 'Cheese'
}
Object run() {
Object a = 42
b = 'Tea'
func()
new Main().method()
}
void func() {
println b
println c
}
}
class Main {
Object method() {
}
}
Upvotes: 11