group of people sitting on floor

Variables in Apache Groovy: Powerful, concise and easy

Apache Groovy variables can be defined by explicitly specifying the data type or using the def…
Home » Blog » Variables in Apache Groovy: Powerful, concise and easy

Groovy is a powerful, concise and easy-to-learn language; I’ve loved it since 2008. My mission with this series is to show what it can do for you. (If you haven’t installed Groovy yet, please read the intro.)

Why variables now, in article six? I promise interesting stuff ahead.

Start by writing a very simple script that declares an integer, sets its value, prints it out and prints out its class:

1 int s
2 s = 42
3 println s
4 println s.getClass()

Now run the script:

$ groovy Groovy05a.groovy
42
class java.lang.Integer
$

Notice that despite declaring the variable s as type int, it appears that it’s actually an instance of the class java.lang.Integer. That’s in fact the case — things that appear to be primitive types in Groovy (int, float, double, boolean) aren’t primitive at all. They’re classes just like String or Date.

You also know that you don’t need to specify the type of the variable s. You can use the def keyword to declare it, as in this script:

1 def s
2 s = 42
3 println s
4 println s.getClass()

Run this script and see what happens:

$ groovy Groovy05b.groovy
42
class java.lang.Integer
$

So it seems that assigning 42 to s above somehow made s into an instance of java.lang.Integer. But is that right? Try another experiment:

1 def s
2 s = 42
3 println s
4 println s.getClass()
5 s = “The meaning of everything”
6 println s
7 println s.getClass()

Wait, do you really think that’s going to work? Well, try it:

$ groovy Groovy05c.groovy
42
class java.lang.Integer
The meaning of everything
class java.lang.String
$

Okay, so it seems you’re free to use s to hold an instance of any class. But what happens if you go back to explicitly typing s?

1 int s
2 s = 42
3 println s
4 println s.getClass()
5 s = "The meaning of everything"
6 println s
7 println s.getClass()

Run that:

$ groovy Groovy05d.groovy
42
class java.lang.Integer
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object ‘The meaning of everything’ with class ‘java.lang.String’ to class ‘int’
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object ‘The meaning of everything’ with class ‘java.lang.String’ to class ‘int’
at Groovy05d.run(Groovy05d.groovy:5)
$

So there’s a big difference between explicitly typing a variable in its declaration or just using def. That’s good to know. Imagine if you declare a variable you intend to hold a year value and later you (or someone else) is confused and tries to assign a date to that variable. You can rest easy knowing that, as long as you declare the variable as int, a Date value cannot be assigned to it.

The one gotcha — there’s always one — is declaring something to be a String and later assigning an int value to it. Doesn’t work, right? Well, it kinda does work —  most Groovy classes have a toString() method and can be automatically “converted” to a String value.

For instance:

1 String s
2 s = 42
3 println s
4 println s.getClass()
5 s = “The meaning of everything”
6 println s
7 println s.getClass()

 It produces this when run:

$ groovy Groovy05e.groovy
42
class java.lang.String
The meaning of everything
class java.lang.String
$

Here you can see that the integer value 42 has been converted to a string. This can produce some weird bugs, for instance:

1 String s
2 s = 42
3 println s
4 println s.getClass()
5 s *= 2
6 println s
7 println s.getClass()

See there in line five where you “forgot” s was a string and tried to multiply it by two? Run this:

$ groovy Groovy05f.groovy
42
class java.lang.String
4242
class java.lang.String
$

Sure enough, 42 * 2 = 4242.

Here’s a cool thought: What if you don’t declare s at all? Let’s try it:

1 s = 42
2 println s
3 println s.getClass()
4 s *= 2
5 println s
6 println s.getClass()

Groovy should complain, right? Run this:

$ groovy Groovy05g.groovy
42
class java.lang.Integer
84
class java.lang.Integer
$

Where did the s in line one come from? Turns out that Groovy scripts have this thing called a “binding” — specifically, there’s always an instance of groovy.lang.Binding, called binding, that is implicitly declared and available in any Groovy script. Any undeclared variables appear in the binding. This script demonstrates it:

1 s = 42
2 println s
3 println s.getClass()
4 println binding.getVariables()

Run it:

$ groovy Groovy05h.groovy
42
class java.lang.Integer
[args:[], s:42]
$

Notice the variable s in there with its value 42. You should also notice  the variable args — that’s where the arguments on the command line come from inside the Groovy script. Finally, notice that the getVariables() method returns a map of the variables and their values.

I close by admiring some of the nice syntactic support that Groovy provides for working with the Binding instance:

1 s = 42
2 println s
3 println “binding.getVariable(‘s’) ${binding.getVariable(‘s’)}”
4 println “binding.getProperty(‘s’) ${binding.getProperty(‘s’)}”
5 println “binding.s ${binding.s}”
6 println “binding[‘s’] ${binding[‘s’]}”

Run it:

$ groovy Groovy05i.groovy
42
binding.getVariable(‘s’) 42
binding.getProperty(‘s’) 42
binding.s 42
binding[‘s’] 42
$

See the equivalence of all those different ways of accessing the “variable” s?

Binding is a cool mechanism provided by Groovy to allow useful stuff to be injected into scripts from outside. It’s especially useful when making domain-specific languages in Groovy.

Conclusion

It turns out that declaring variables — and even more, not declaring variables — in Groovy scripts is a topic with some depth. In my experience, it’s always better to declare the type of variable in any kind of code I expect to maintain over time, rather than to use the def keyword. Plus, be careful with variables declared to be String. Finally, I urge you to dig into bindings as they are one of the things that makes Groovy, well, groovy!

Photo by Alina Grubnyak on Unsplash

Author

If you enjoyed this post, you might also enjoy these