It is often desired to declare constants at the top of a script that can be referenced anywhere else in the script. In Groovy, it seems that if you declare a constant using final then it isnot accessible in child scopes. What is the solution for this very basic and common requirement? The workaround I have right now is to create an unbound variable but this is not a constant and is not elegant.
import groovy. transform. Field var1 = 'var1' @Field String var2 = 'var2' def var3 = 'var3' void printVars() { println var1 println var2 println var3 // This won't work, because not in script scope. }
It is often desired to declare constants at the top of a script that can be referenced anywhere else in the script. In Groovy, it seems that if you declare a constant using final then it isnot accessible in child scopes.
Using @Field annotation on a script variable changes a scope of this variable from a local one to a Script class one: Variable annotation used for changing the scope of a variable within a script from being within the run method of the script to being at the class level for the script.
The def keyword is used to define an untyped variable or a function in Groovy, as it is an optionally-typed language.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With