Groovy: what's the purpose of "def" in "def x = 0"?

GroovyKeyword

Groovy Problem Overview


In the following piece of code (taken from the Groovy Semantics Manual page), why prefix the assignment with the keyword def?

def x = 0
def y = 5

while ( y-- > 0 ) {
    println "" + x + " " + y
    x++
}

assert x == 5

The def keyword can be removed, and this snippet would produce the same results. So what's the effect of the keyword def ?

Groovy Solutions


Solution 1 - Groovy

It's syntactic sugar for basic scripts. Omitting the "def" keyword puts the variable in the bindings for the current script and groovy treats it (mostly) like a globally scoped variable:

x = 1
assert x == 1
assert this.binding.getVariable("x") == 1

Using the def keyword instead does not put the variable in the scripts bindings:

def y = 2

assert y == 2

try {
    this.binding.getVariable("y") 
} catch (groovy.lang.MissingPropertyException e) {
    println "error caught"
} 

Prints: "error caught"

Using the def keyword in larger programs is important as it helps define the scope in which the variable can be found and can help preserve encapsulation.

If you define a method in your script, it won't have access to the variables that are created with "def" in the body of the main script as they aren't in scope:

 x = 1
 def y = 2


public bar() {
    assert x == 1

    try {
        assert y == 2
    } catch (groovy.lang.MissingPropertyException e) {
        println "error caught"
    }
}

bar()

prints "error caught"

The "y" variable isn't in scope inside the function. "x" is in scope as groovy will check the bindings of the current script for the variable. As I said earlier, this is simply syntactic sugar to make quick and dirty scripts quicker to type out (often one liners).

Good practice in larger scripts is to always use the "def" keyword so you don't run into strange scoping issues or interfere with variables you don't intend to.

Solution 2 - Groovy

Ted's answer is excellent for scripts; Ben's answer is standard for classes.

As Ben says, think of it as "Object" -- but it is much cooler in that it does not constrain you to the Object methods. This has neat implications with respect to imports.

e.g. In this snippet I have to import FileChannel

// Groovy imports java.io.* and java.util.* automatically
// but not java.nio.*

import java.nio.channels.*

class Foo {
    public void bar() {
        FileChannel channel = new FileInputStream('Test.groovy').getChannel()
		println channel.toString()
    }
}

new Foo().bar()

e.g. But here I can just 'wing it' as long as everything is on the classpath

// Groovy imports java.io.* and java.util.* automatically
// but not java.nio.*
class Foo {
    public void bar() {
        def channel = new FileInputStream('Test.groovy').getChannel()
		println channel.toString()
    }
}

new Foo().bar()

Solution 3 - Groovy

According to this page, def is a replacement for a type name and can simply be thought of as an alias for Object (i.e. signifying that you don't care about the type).

Solution 4 - Groovy

As far as this single script is concerned there is no practical difference.

However, variables defined using the keyword "def" are treated as local variables, that is, local to this one script. Variables without the "def" in front of them are stored in a so called binding upon first use. You can think of the binding as a general storage area for variables and closures that need to be available "between" scripts.

So, if you have two scripts and execute them with the same GroovyShell, the second script will be able to get all variables that were set in the first script without a "def".

Solution 5 - Groovy

The reason for "def" is to tell groovy that you intend to create a variable here. It's important because you don't ever want to create a variable by accident.

It's somewhat acceptable in scripts (Groovy scripts and groovysh allow you to do so), but in production code it's one of the biggest evils you can come across which is why you must define a variable with def in all actual groovy code (anything inside a class).

Here's an example of why it's bad. This will run (Without failing the assert) if you copy the following code and paste it into groovysh:

bill = 7
bi1l = bill + 3
assert bill == 7

This kind of problem can take a lot of time to find and fix--Even if it only bit you once in your life it would still cost more time than explicitly declaring the variables thousands of times throughout your career. It also becomes clear to the eye just where it's being declared, you don't have to guess.

In unimportant scripts/console input (like the groovy console) it's somewhat acceptable because the script's scope is limited. I think the only reason groovy allows you to do this in scripts is to support DSLs the way Ruby does (A bad trade-off if you ask me, but some people love the DSLs)

Solution 6 - Groovy

Actually, I don't think it would behave the same...

variables in Groovy still require declaration, just not TYPED declaration, as the right-hand side generally contains enough information for Groovy to type the variable.

When I try to use a variable that I haven't declared with def or a type, I get an error "No such property", since it assumes that I'm using a member of the class containing the code.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLeonelView Question on Stackoverflow
Solution 1 - GroovyTed NaleidView Answer on Stackoverflow
Solution 2 - GroovyMichael EasterView Answer on Stackoverflow
Solution 3 - GroovyBen HoffsteinView Answer on Stackoverflow
Solution 4 - GroovyMartin StephanView Answer on Stackoverflow
Solution 5 - GroovyBill KView Answer on Stackoverflow
Solution 6 - GroovybilljamesdevView Answer on Stackoverflow