Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Global constants in Groovy

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.

like image 536
justGroovy Avatar asked Feb 01 '11 03:02

justGroovy


People also ask

How do you set a global variable in Groovy?

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. }

How do you define a constant in Groovy?

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 @field in Groovy?

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.

What is def in Groovy script?

The def keyword is used to define an untyped variable or a function in Groovy, as it is an optionally-typed language.


2 Answers

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.

like image 157
ataylor Avatar answered Sep 17 '22 15:09

ataylor


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() 
like image 32
bmaupin Avatar answered Sep 20 '22 15:09

bmaupin