Global constants in Groovy
Groovy doesn't really have a global scope. When you have a groovy script that doesn't declare a class, it implicitly gets stuck in a class with the name of the script. So final variables at the top-level scope are really just fields of the implicit class. For example:
// foo.groovy
final MYCONSTANT = "foobar"
println MYCONSTANT
class Helper {
def hello() { println MYCONSTANT } // won't work
}
new Helper().hello()
Is more or less equivalent to:
class foo {
def run() {
final MYCONSTANT = "foobar"
println MYCONSTANT
new Helper().hello()
}
static main(args) {
new foo().run()
}
}
class Helper {
def hello() { println MYCONSTANT } // won't work
}
It's easy to see why it doesn't work expanded out. An easy work around is to declare your "globals" in a dummy class called e.g. Constants, and then just do a static import on it. It even works all in a single script. Example:
import static Constants.*
class Constants {
static final MYCONSTANT = "foobar"
}
println MYCONSTANT
class Helper {
def hello() { println MYCONSTANT } // works!
}
new Helper().hello()
EDIT:
Also, scripts are bit of a special case. If you declare a variable without def
or any modifiers such as final
, (i.e. just use it) it goes into a script-wide binding. So in this case:
CONSTANT = "foobar"
println "foobar"
CONSTANT is in the script-wide binding, but in:
final CONSTANT = "foobar"
println "foobar"
CONSTANT is a local variable in the script's run()
method. More information on this can be found at the archived link to some Groovy - Scoping and the Semantics of "def" page.
In Groovy 1.8+, you can achieve this using the @Field
annotation:
import groovy.transform.Field
@Field final String MY_CONSTANT = 'constant'
def printConstant() { println MY_CONSTANT }
printConstant()