1

This question extends my previous one Groovy equivalent for Scala implicit parameters

Not sure if this is the right way to develop from a previous topic, but anyway..

I am looking for a way to express in groovy something like this:

// scala
object A {
    def doSomethingWith(implicit i:Int) = println ("Got "+i)
}
implicit var x = 5

A.doSomethingWith(6)  // Got 6
A.doSomethingWith     // Got 5

x = 0
A.doSomethingWith     // Got 0

In general, I would like to execute a piece of logic, and have variables in it resolved based on the execution 'context'. With implicits in scala I seem to be able to control this scenario. I am trying to find a way to do something similar in groovy.

Based on the feedback from the first question I tried to approach it like this:

// groovy
class A {
    static Closure getDoSomethingWith() {return { i = value -> println "Got $i" }} 
}

value = 5

A.doSomethingWith(6)  // Got 6
A.doSomethingWith()   /* breaks with
                         Caught: groovy.lang.MissingPropertyException: 
                         No such property: value for class: A */

Now, I went through the groovy closure definition at http://groovy.codehaus.org/Closures+-+Formal+Definition

As I understand it, when the getter is called, the failure happens as "the compiler cannot statically determine that 'value' is available"

So, has anyone a suggestion for this scenario? Cheers

Community
  • 1
  • 1
Ghiro
  • 500
  • 1
  • 4
  • 11

2 Answers2

2

You could also try changing the delegate of the returned Closure:

value = 5

Closure clos = A.doSomethingWith

// Set the closure delegate
clos.delegate = [ value: value ]

clos(6)  // Got 6
clos()   // Got 5
tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • btw, keeping a reference to the map will let you change the value later and it will be effective in future closure invocations. – Brian Henry Nov 14 '12 at 18:10
1

I managed to do what you want by checking for unresolved properties in the script binding:

class A {
  static Closure getDoSomethingWith() { { i = value -> println "Got $i" } } 
}
A.metaClass.static.propertyMissing = { String prop -> binding[prop] }

value = 5


A.doSomethingWith 6  // Got 6
A.doSomethingWith() // prints "Got 5"
Will
  • 14,348
  • 1
  • 42
  • 44
  • Yes, you need to use this in a plain class? – Will Nov 14 '12 at 16:06
  • Yes, I do. Ideally the caller of the closure should not need to 'set up' anything on the closure instance, but just ensure that the context is initialized (the 'value' variable in this example). – Ghiro Nov 14 '12 at 16:26
  • 2
    you can modify this to use `this[prop]` instead of `binding[prop]` to use variables of the surrounding class (or binding if being run from a script). – Brian Henry Nov 14 '12 at 16:44
  • Brian, thanks, that seem to work for Class properties. Do you know a way to have the binding work for local variable of the executing context? – Ghiro Nov 14 '12 at 17:13
  • What does it looks like? If the variables start with `def`, i think they aren't available in a container (or something like that). If they are not preceded by `def`, then it either is happening in a script OR it is in a class where you intercept the `propertyMissing` method, creating your own variable "container" – Will Nov 14 '12 at 17:19
  • @Ghiro: I don't think so. I don't think there's a context to local scope in that way. You can inject variables as tim_yates shows via the delegate, or you could have some closure factory method or curry in the local var you want. There's perhaps some way you can pass a closure to a factory method for your doSomethingWith closure, but it makes my head hurt right now. – Brian Henry Nov 14 '12 at 18:03