Groovy variable scope
The scope of variables is where we can access the variables.
By default variables are global
By assigning value to a new variable name we create that variable. Groovy does not require any special syntax or keyword to declare a variable.
If we access the same variable name within a function (either reading it with println in this case or writing it when we assign a new value to it), we access the same global variable.
examples/groovy/global_variable.groovy
x = 42 def f() { println(x) // 42 x = 23 println(x) // 23 } f() println(x) // 23
Create global variable inside a function
We don't need the first global definition. If we assign a value to a variable inside a function, it will create a global variable that will remain in scope even after the function has finished running.
examples/groovy/create_global_in_function.groovy
def f() { x = 23 println(x) } f() // 23 println(x) // 23
Declare local variable with def
We can use the def keyword to declare a variable local. In the first example we can see that there is a global variable (which was not declared using def) which is then accessible inside the function (println) just as we saw in the first example. Once we use the def keyword to declare the same variable name inside the function it creates a new variable, hiding the global one.
Once we exit the function the local version is destroyed and outside the function we access the global variable again.
examples/groovy/global_and_local_variables.groovy
x = 42 def f() { println(x) // 42 def x = 23 println(x) // 23 } f() println(x) // 42
If you use def to declare the variable outside of all the functions, you won't be able to access it inside the function. (The first print statement in the next example would throw the exception shown in the comment.)
Assiging to a variable inside the function, even if we don't use def to declare it, will create a new, local variable:
examples/groovy/local_and_automatic.groovy
def x = 42 def f() { //println(x) // Caught: groovy.lang.MissingPropertyException: No such property: x for class: scope x = 23 println(x) // 23 } f() println(x) // 42
The best option is when you declare your variables both inside and outside of functions using the def keyword. That makes it clear both to Groovy and to the reader that your intention was to create locally scoped variables.
examples/groovy/local_and_local.groovy
def x = 42 def f() { // println(x) // Caught: groovy.lang.MissingPropertyException: No such property: x for class: scope def x = 23 println(x) // 23 } f() println(x) // 42
Shall we use global or local variables?
Global variables might make it easy to write the first version of the program, but then, as the program grows it becomes harder and harder to maintain it. Not a recommended practice. You are much better off working a bit harder and always declaring your variables in every scope.
Scope in a block?
Some languages (most notably Perl) would create a scope for every block - for every pair of curly braces. This is not the case in Groovy.
examples/groovy/scope_in_a_block.groovy
def x = 42 if (x > 10) { x = 12 } println(x) // 12
In this example you can see that you cannot re-declare a variable inside a block as that would cause a compile-time error:
examples/groovy/def_in_a_block.groovy
def x = 42 if (x > 10) { def x = 12 // Exception } println(x)
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: scope_in_a_block.groovy: 6: The current scope already contains a variable of the name x @ line 6, column 9. def x = 12 ^ 1 error
On the other hand you can declare variables inside a block (but apparently only if they did not exist outsdide the block) and they will cease to exist at the end of the block.
This example prints the 12 and then when it tries to access the variable outside of the block it will raise an exception.
examples/groovy/def_only_in_a_block.groovy
if (true) { def x = 12 println(x) // 12 } println(x)
12 Caught: groovy.lang.MissingPropertyException: No such property: x for class: def_only_in_a_block groovy.lang.MissingPropertyException: No such property: x for class: def_only_in_a_block at def_only_in_a_block.run(def_only_in_a_block.groovy:9)
Published on 2019-04-12