views:

52

answers:

3

I think this is a newbie question but why it fails on the last assertion? I was thinking that the closure binds the value on it, so changing it from the closure will change the value outside the closure.

def value = 5

def foo(n){

  return {

    ++n

  }
}

def test = foo(value)

assert test() == 6
assert test() == 7

assert value == 7

Thanks for help.

+1  A: 

Remember that Integer (the runtime type of value) is immutable. So although n and value initially refer to the same object, when you execute ++n it creates a new Integer. The value reference is not updated to refer to this new object, so when execution completes it is still referring to the initial object (5).

Don
+1  A: 

That does seem to be strange behaviour but I think it is correct. All objects event integegers are passed by reference. The call foo(value) passes value into the function. The variable 'n' is a reference to the same object as 'value' references. Essentially you have two pointers to the same object. When you increment 'n', you are incrementing that variable only.

Since the Integer class is immutable ++n is actually doing something like:

n = n + 1

This is assigning the incremented value to the variable n. The variable 'value' declared at the top is still pointing to the original object 5.

Chris Dail
A: 

You are assigning a new value to the name n, which is different than the name value. You can get the behaviour you want by making value a mutable object. Then you can change it instead of creating and assigning a new object.

Here's a simple example that wraps the value in a list:

def value = [5]

def foo(n){

    return {

        n[0]++
        n
    }
}

def test = foo(value)

assert test() == [6]
assert test() == [7]

assert value == [7]
ataylor