Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy: What's the difference between defining a variable without "def" versus using anchoring?

Tags:

scope

groovy

I'm learning Groovy now and I bumped into something that I don't understand and I hope you'd be able to shed some light.

In regard to the following example:

import groovy.transform.Field
  @Field List awe = [1, 2, 3]
  def awesum() { awe.sum() }
  assert awesum() == 6

I understand that this anchoring allows me to change the scope of the awe variable from being run at the method level of the script to the class level of the script.

But then I think about the difference between defining a variables with def or without, example:

def var = "foo"

and

var = "foo"

As far as I understand the difference between the two examples is a difference of scope. When I assign a value to a variable without a "def" or other type, in a Groovy script, it's added to the "binding", the global variables for the script. Which means it can be accessed from all functions within the script.

So taking into consideration both "@Field" and defining a variable without using "def" and following that line of thought I've changed the example code to this:

import groovy.transform.Field
  awe = [1, 2, 3]
  def awesum() { awe.sum() }
  assert awesum() == 6

And it works.

So my question is why use anchoring? if you can achieve the same goal by defining a variable without the "def"?

like image 414
Itai Ganot Avatar asked Mar 11 '23 17:03

Itai Ganot


2 Answers

You do not achieve the same goal - see the difference below

import groovy.transform.Field
awe = [1, 2, 3]
def awesum() { awe.sum() }
assert awesum() == 6
awe = 1

work fine as the variable is dynamically typed. On contrary this fails

import groovy.transform.Field
@Field List awe = [1, 2, 3]
def awesum() { awe.sum() }
assert awesum() == 6
awe = 1

As the variable is strong typed (java.util.ArrayList)

Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '1' with class 'java.lang.Integer' to class 'java.util.List'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '1' with class 'java.lang.Integer' to class 'java.util.List'
        at FieldTest1.run(FieldTest1.groovy:5)
like image 62
Marmite Bomber Avatar answered Apr 06 '23 01:04

Marmite Bomber


@Field is younger than scripts and the intended use is to give open blocks the ability to have additional state. If you are happy with the binding there is not really a big reason for doing it different. If you need the values in the binding of course, then @Field is no alternative. On the other hand, if the binding must contain only certain variables, then @Field can become a must

Example for intended usage:

def cl = {
  Field x = 1
  x++
}

In this example the open block cl would have a field x, the script would not have x in the binding, nor is there a local variable x. But the assignment x=1 is done only once when the open block is created. But you can still change the value by operations on that field. That way each call cl() will produce a new value, starting with 1.

like image 43
blackdrag Avatar answered Apr 06 '23 00:04

blackdrag