I have a question about groovy and variable scoping within closures.
Here is my first example, which prints out 1 2 3 by accessing an
instance variable in the class in which the closure is being executed
(using a 'delegate')
class Utility {
def x = 1
def run = { closure ->
closure.delegate = this
3.times closure
}
}
new Utility().run { println delegate.x++ }
Since x is being reference thru the delegate object, I am able to
increment it within my closure. This is good.
But what I really want is for x to be a local variable inside the run
method, not an instance variable on the class.
I'd like this code to work but it doesn't:
class Utility {
def run = { closure ->
def x = 1
3.times closure
}
}
new Utility().run { println x++ }
at the time println x++ is called, the x variable is not in scope.
Making it delegate doesn't help either b/c I can only reference
instance variables thru the delegate object and not variables on the
local stack.
The typical way to pass this local data into the closure is to use a
parameter, but this doesn't really help me b/c the parameter is by
value, not be reference, so I can't manipulate it. This example
compiles and runs but prints out 1 1 1 instead of 1 2 3
class Utility {
def run = { closure ->
def x = 1
3.times { closure(x) }
}
}
new Utility().run { x -> println x++ }
Any ideas on how I can access a local variable from within my closure
when that local variable is defined in the enclosing method?
Thanks,
Hamlet
If you defined the closure in the method that called it, I would
expect that to work (but that doesn't really help what you're trying
to do). The only other thing I can think of immediately is to use an
object that holds the int and pass that in, so that you have a
reference to the same variable.
def xHolder = [x:x] // or an object, rather than a map
Scott
--
-------------------------------------------------
Scott Vlaminck // sc...@refactr.com
Refactr LLC // http://refactr.com
mobile // 612-386-9382
-------------------------------------------------
class Utility {
def run = { closure ->
def m = [x:1]
3.times { closure(m) }
}
}
new Utility().run {m -> println m.x++ }
I just had another thought as well, although this may still not solve
the problem you are trying to address. Depending on the complexity of
the closure, you could set it's delegate to some other random object,
the example below uses a map.
class Utility {
def run = { closure ->
def closureDelegate = [x:1]
closure.delegate = closureDelegate
3.times closure
}
}
new Utility().run { println delegate.x++ }
Since closures have access to variables in the defining scope (rather
than the executing scope), I thought that it may be possible to work
around this by perhaps creating a temporary closure in the 'run'
method and using it's 'this' or 'delegate', but I tried everything I
could think of and didn't get anywhere more than the above ideas.
Scott
Here is a quick example of how you might address your issue:
class Utility {
def run = { x, closure ->
3.times { closure.call(x++)}
}
}
def myRun = new Utility().run.curry(1)
myRun{ x -> println x }
> > > Refactr LLC //http://refactr.com
> > > mobile // 612-386-9382
> > > -------------------------------------------------
>
> > --
> > -------------------------------------------------
> > Scott Vlaminck // sc...@refactr.com
> > Refactr LLC //http://refactr.com
> > mobile // 612-386-9382
> > -------------------------------------------------