What is the scope of class definition in DM script? - multithreading

I have defined a thread derived class at the beginning of the script:
class procthread : thread
{
......
object init( object self)
{
...
}
void RunThread( object self )
{
.....
}
}
and then MyDialog class, which is supposed to use this thread:
Class MyDialog: UIFrame
{
object wrkthread
.....
TagGroup CreateMyDialog(Object self, number nref)
{
........
btn0=DLGCreatePushButton("+","DoBut0").DLGIdentifier("#PushB0")
wrkthread=alloc(procthread) ////<----- works
return DialogTG
}
Object Init(Object self, number nref) return self.super.Init(self.CreateMyDialog(nref))
Void DoBut0(Object self)
{
wrkthread=alloc(procthread) ////<---- does not work
}
}
To the logic of the script the thread should be allocated and activated every time the button is pressed.
However "wrkthread=alloc(procthread)" called in the on_button_pressed handler throws an exception "Cannot find class 'procthread'". At the same time the same call from Init function works nicely and the thread runs.
What is the problem here? I cannot believe that class definitions are visible within the main thread only, this makes no sense.
If I make a mistake, could you please correct?
If this is a feature - how to get around it?

The problem is, UI actions are (and have to, if you think of it) run on the DM-Application main thread. Hence the DoBut0 action acts on a different thread than the one from your script. So in a way, yes, launching a script interpreter keeps the script code only in "its" scope, and separately created threads (like UI actions) do not know about it.
One way around it is to have your class keep a member object of the class you want to execute from the button and so forces it to stay in scope. (Which is your "working" solution above.) If you need a "new" object with each UI action, you can achieve this by cloning the object instead of allocating it in the member function. (i.e. the member object is just a 'template' object)
Here is another example:
Class AClass
{
AClass(Object self) Result("\n object AClass created: ID=" + self.ScriptObjectGetID() ) // Just for debugging info
~AClass(Object self) Result("\n object AClass destroyed: ID=" + self.ScriptObjectGetID()) // Just for debugging info . Check no memory leak!!
void AAction(Object self) Result("\t ACTION A")
}
Class BClass : UIFrame
{
BClass(Object self) Result("\n object BClass created: ID=" + self.ScriptObjectGetID() ) // Just for debugging info
~BClass(Object self) Result("\n object BClass destroyed: ID=" + self.ScriptObjectGetID()) // Just for debugging info . Check no memory leak!!
Object keepOtherOBJ
void CreateOtherObject(Object self)
{
result("\nAllocation prepare")
keepOtherOBJ = Alloc(AClass)
result("\nAllocation done")
}
void CallOtherAction(Object self)
{
Result("\n Calling other action:")
keepOtherOBJ.AAction()
}
void ButtonAction(Object self)
{
Result("\n Pressing button")
// self.CreateOtherObject() // ==> THIS IS NOT working. Button action is called separately in memory which doesn't know about "Class A"
self.CallOtherAction()
// Or you may want to clone the "template" and run it like this
keepOtherObj.Clone().AAction()
}
Object InitAndShow(Object self)
{
TagGroup DLGtg,DLGitems
DLGtg = DLGCreateDialog("Test",DLGitems)
DLGitems.DLGAddElement( DLGCreatePushButton("Other Class Action","ButtonAction") )
self.Init(DLGtg)
self.CreateOtherObject() // ==> THIS IS working. The object is created and kept as local member
self.Display("Test")
}
}
// MAIN script
{
Object BObject = Alloc(BClass)
BObject.InitAndShow()
}

Related

Handle function calls on a class in Node.JS

Assuming that you have a class
class MyClass {
world() {
console.log("hello world");
}
}
I can run the method similar to the following:
var hello = new MyClass();
hello.world();
# outputs: hello world
Is there a way to handle direct function calls on an object? For example:
hello();
Returns: TypeError: hello is not a function.
Can I make this call a default function? For example, similar to PHP's invoke function ...
We can only make something callable in JavaScript if that thing is an object which, at some point, delegates to Function.prototype. Therefore, our class will need to extend Function or extend from a class which extends Function. We also need to be able to access instance variables from our class object (in order to call invoke()), so it needs to be bound to itself. This binding can only happen in the constructor.
Since our class will inherit from Function, we need to call super before being able to use this . However, the Function constructor actually takes a code string, which we won't have, because we want to be able to set invoke later on. So we'll need to extend Function in a different class which will be the parent class to our class and which will do the work of setting the prototype of our dummy function (which we need in order to be able to call the returned object). Bringing all of this together, we get:
class ExtensibleFunction extends Function {
constructor(f) {
// our link to Function is what makes this callable,
// however, we want to be able to access the methods from our class
// so we need to set the prototype to our class's prototype.
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class MyClass extends ExtensibleFunction {
constructor() {
// we build an ExtensibleFunction which accesses
// the late-bound invoke method
super(function() { return this.invoke(); });
return this.bind(this); // and bind our instance
// so we have access to instance values.
}
invoke() {
console.log("Hello, world!");
}
}
x = new MyClass();
x(); //prints "Hello, world!"
I mostly adapted the techniques found in this answer in order to do this.
An interesting aspect of using this technique is that you could name MyClass something like Callable and remove the invoke method - then any class which extends Callable would become callable as long as it had an invoke() method. In fact...
class ExtensibleFunction extends Function {
constructor(f) {
// our link to Function is what makes this callable,
// however, we want to be able to access the methods from our class
// so we need to set the prototype to our class's prototype.
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class Callable extends ExtensibleFunction {
constructor() {
// we build an ExtensibleFunction which accesses
// the late-bound invoke method
super(function() { return this.invoke(); });
return this.bind(this); // and bind our instance
// so we have access to instance values.
}
}
class CallableHello extends Callable {
invoke() {
console.log("Hello, world!");
}
}
class CallableBye extends Callable {
invoke() {
console.log("Goodbye cruel world!");
}
}
x = new CallableHello();
x(); //prints "Hello, world!"
y = new CallableBye();
y(); //prints "Goodbye cruel world!"
(Of course, you could get the same effect by setting properties on function objects, but this is more consistent I guess)

How to access Closure properties from inside closure code?

I'm banging my head against this wall for more than a week now, let me explain briefly what I'm trying to achieve.
I have a DSL defined like this (brief example)
TestingSpec
.newInstance()
.sayHello() --> print "Hello "+something
.sayGoddbye() --> print "Goddbye"+something
Note the something in there that is not passed anywhere intentionally, because I want to limit the scope of use of my DSL by the will be users, so what I actually want is to somehow "inject" the something in that DSL instance programmatically. This is being done by using a Closure.
Myscript.execute( {
TestingSpec
.newInstance()
.sayHello() --> print "Hello "+something
.sayGoddbye() --> print "Goddbye"+something
})
and MyScript will invoke it by passing the something value to it, either by passing a parameter, or by adding a property or by adding a Binding (don't know what's the best, really)
close.call("Toni")
close.metaClass.something = "Toni"
def binding = new Binding()
binding.setVariable("something", "Toni")
close.setBinding(binding)
But now I'm stuck in what I thought it was going to be easy, how from the TestingSpec code can I access the Closure something? For instance
public newInstance() {
def instance = new TestingSpec()
instance.something = *MY CLOSURE SOMETHING*
return instance
}
I've tried several options, like messing with the this, owner and delegate of the closure, but couldn't do it.
Any hint will be very welcome...
Cheers.
I don't think that's doable. TestingSpec is too high on the stack to be aware he is being invoked from a closure. I'd like to suggest two solutions
1. Pass something to TestingSpec programmatically.
Myscript.execute( {
TestingSpec
.newInstance(something)
.sayHello() --> print "Hello "+something
.sayGoddbye() --> print "Goddbye"+something
})
2. Make the TestingSpec instance be created by MyScript
I like this solution more. It is about MyScript.execute({}) being responsible for creating and handling the lifecycle of TestingSpec:
class TestingSpec {
def something
def sayHello() {
println "Hello " + something
this
}
def sayGoddbye() {
println "Goddbye " + something
this
}
}
class Myscript {
static TestingSpec testingSpec
static execute(closure) {
def binding = new Binding(something: 'test for echo')
testingSpec = new TestingSpec(something: binding.something)
binding.testingSpec = testingSpec
closure.binding = binding
closure()
}
}
Myscript.execute( {
testingSpec // this is an instance, and not a static call
.sayHello() // print "Hello "+something
.sayGoddbye() // print "Goddbye"+something
})
Output:
$ groovy Spec.groovy
Hello test for echo
Goddbye test for echo
3. Delegate the closure to testingSpec
If you set the closure delegate to testingSpec, you can invoke its methods without referencing testingSpec directly, providing a very clean code. Note i also updated the example to remove MyScript:
class TestingSpec {
static TestingSpec testingSpec
static execute(closure) {
def binding = new Binding(something: 'test for echo')
testingSpec = new TestingSpec(something: binding.something)
binding.testingSpec = testingSpec
closure.delegate = testingSpec
closure.binding = binding
closure()
}
def something
def sayHello() {
println "Hello " + something
this
}
def sayGoddbye() {
println "Goddbye " + something
this
}
}
TestingSpec.execute( {
sayHello() // print "Hello "+something
sayGoddbye() // print "Goddbye"+something
})
4. Inject testingSpec as a parameter into your closure
As per your answer, a simple suggestion: consider giving a testingSpec var that you've built yourself to the user, since it allows more control and customization to you. Think a simple inversion of control (this allows testingSpec to see dynamic variables in the closure's binding):
.withDistinctNames({ testingSpec ->
testingSpec
.from(name)
.withAddress(email)
.sendEmail(template)
})
With a full test:
class TestingSpec {
def commands = []
static newInstance(listOfNames) {
new TestingSpec()
}
def sayHello() { commands << "sayHello"; this }
def waveGoddbye() { commands << "waveGoddbye"; this }
def withAddress(address) { commands << "withAddress $address"; this }
def sendEmail(template) { commands << "sendEmail $template"; this }
def withDistinctNames(closure) {
commands << "withDistinctNames"
closure.binding = new Binding(address: "sunset boulevard", template: 'email is $email')
closure(this)
this
}
}
test = TestingSpec
.newInstance([:])
.sayHello()
.withDistinctNames({ me ->
me
.withAddress(address)
.sendEmail(template)
})
.waveGoddbye()
assert test.commands == [
'sayHello',
'withDistinctNames',
'withAddress sunset boulevard',
'sendEmail email is $email',
'waveGoddbye'
]
I finally reach a solution to my problem that while not ideal it's "elegant" enough and "easy" to understand by would-be users of my DSL. So, what I want to do is allow the DSL users to write things like this:
TestingSpec
.newInstance()
.from(listOfNames)
.sayHello()
.withDistinctNames({
TestingSpec
.newInstance()
.from(*****) <---- problem
.withAddress()
.sendEmail(template)
})
.waveGoddbye()
There could be a number of with methods that basically serve as a filter+loop, so in this example it will filter the names to be unique and then apply the Closure to each name in turn. Of course this would be extremely easy to do by just doing
.withDistinctNames({
TestingSpec
.newInstance()
.from(it)
.withAddress()
.sendEmail(template)
})
or for more complicated cases
.withDistinctNames({ name, email, template ->
TestingSpec
.newInstance()
.from(name)
.withAddress(email)
.sendEmail(template)
})
The prob is I don't know who is going to use this DSL, it may not be people familiar with closures, parameters, functions, whatnots, it may be people even from outside my organization, so my goal was to keep it simple by passing the needed variables from the outer Spec to the inner Spec. In my TestingSpec implementation I would have:
public TestingSpec withAll(Closure k, Closure f) { // withAll is used by all with* methods
def result = k.call(root) // root is the entire listOfNames
def results = result
.collect {
// HERE'S THE PROBLEM, HOW TO INJECT ALL THE PARAMETERS INTO THE INNER SPEC?
f.call(it) // this line passes vars to the Closure, not the inner Spec, and I found no way for the Closure itself to inject them in the Spec
}
return this;
}
After I saw it was impossible to inject params in the inner Spec itself (that is yet to be instantiated) I tried to pass them to the Closure and from there to the Spec, like this:
.withDistinctNames({
TestingSpec
.newInstance()
.from(this) <-------------------
.withAddress()
.sendEmail(template)
})
I supposed that this would be the outer Spec that contains all the info I need, but it was not. I tried with this, this.thisObject, this.owner, this.delegate.
But then, with the help of the 3rd above suggestion I ended up doing this:
public TestingSpec withAll(Closure k, Closure f) {
f = f.rehydrate(f.getDelegate(), f.getOwner(), this)
def result = k.call(root)
def results = result
.collect {
this.parameters = [whatever I need]
f.call()
}
return this;
}
This way the this in the DSL is actually the outer Spec, so the users can now use the more intuitive "this" keyword. To avoid confusion I got rid of the .from() method, like this:
TestingSpec
.newInstance(listOfNames)
.sayHello()
.withDistinctNames({
TestingSpec
.newInstance(this) // my newInstance implementation can parse all the parameters as it wishes
.withAddress()
.sendEmail(template)
})
.waveGoddbye()
While it's not ideal is close enough, from the perspective of the potential users, I think. If somebody has suggestions please let me know.
Thanks Will P and all.
After working on a small similar Groovy DSL tool recently and digging a bit into griffon and swing and other material I currently ended with the following, that I submit as another suggestion to the answer.
Any comment/suggestion will be greatly appreciated.
IMHO a clear separation between the domain model (a Model class) , and the support classes (building, aggregation , context sharing, and filtering part of the model, at least a Builder class) is one of the key elements
to have a simple and efficient model. This is the pattern used in groovy swing and griffon and showed to be very flexible.
It allows constructs with each {}, with {} and collection operations which are clean and understandable enough,
and mostly without chaining operations (ie adding an annoying return this at the end of each operation).
Like here for example (source code at the end, MSys is a Facade to the underlying system):
MSys.with {
model.each {
it.sayHello
it.sayGoodBye
it.setAddress randomAddress(it.name);
it.sendEmail
}
println " Hello counts"
model.each {
def key = it.name
def value = MSys.context[key]
println "Counter for ${key} = ${value}"
}
}
or
MSys.model.each {
it.with {
sayHello
sayGoodBye
setAddress randomAddress(name) ;
sendEmail
}
}
or
MSys.eachModelDo {
sayHello
sayGoodBye
setAddress randomAddress(it.name);
sendEmail
}
or ...
(lot of possibilities)
It also allows to have some shared context very easily (in the example , context is a Map shared between all the Model elements where almost anything could be put, connection information, user preferences, cache etc.),
and to hide all the boiler plate to the user by putting it in another class/script .
The responsibilities would be :
SpecModel : Domain model : say hello, goodbye, properties etc
SpecBuilder : creates models (from a list in the example), holds shared context (a map) and eventually take care of the closure delegate context for some operations
This separation is important to deal with set operations on one side and entity (model) operations on the other.
Apart from beeing a builder, from a user POV it is a facade
and from a developer POV BTW it should be a Facade to several classes including the builder -but better start simple.
The next step would be to integrate FactoryBuilderSupport in this builder in order to benefit from Groovy DSL builder facilities, but this one big step beyond and I'm not comfortable with that yet ... (WIP right now)
Few Groovy recaps that you certainly already know but part of the problem if you want a light syntax :
In Groovy , , ; and () are optional except when there is a conflict.
Even where there is no direct conflict, the delegation strategy is not always direct and
run time errors are not always clear (see link on closures doc below)
Having a public getter method for properties, allows the use of property like access methods without the (),
the get and set prefixes are inferred
ie with a method like
public getSendEmail() {
println "email for ${name}"
}
you can use the syntax :
myObject sendEmail
Groovy assumes a property getter call and do the rest.
This helps removing the () in the dsl syntax.
The context is the delegate context of the closure it not the this
When you use closures, you use it to reference the object you are working on in the closure
(ie the receiver of the message).
Example:
[1, 2, 3].each { println it }
is ok
If you haved used
[1, 2, 3].each { println this }
you would have print a reference to the outer object, the console in groovy console
(Which IIRC was one of the problem you had in your first post)
This is well explained in the Groovy Closures doc :
(excerpt:)
this : the enclosing class where the closure is defined
owner : the enclosing object where the closure is defined, a class or a closure
delegate : third party object where methods calls or properties are resolved whenever the receiver of the message is not defined
The message delegation strategy (explained in the same document) is not always direct and this was your real problem I think.
That said, another key point in a DSL is the coherence from a user POV.
This means consistence in data access patterns and here the standard Groovy collections (Lists, maps each{} etc) can help a lot.
Plus it can be a huge plus for power users.
Syntactic sugar methods like eachModelDo can easily be done on a builder/facade class:
MSys.eachModelDo {
sayHello
sayGoodBye
setAddress randomAddress(it.name);
sendEmail
}
NB: eachModelDo is very simple but a bit tricky to debug
At one point it "worked" well without accessing correct variables :(
I have the feeling that something is wrong here (?) or at least it should be improved (comments welcome)
/**
* syntactic sugar
* direct access without 'it' (optional)
*/
public SpecBuilder eachModelDo(closure) {
model.each {
closure.delegate = it;
closure(it)
}
}
Bellow is the source code of a small test I did that you can cut and paste in a groovy console
The only part visible to the user should be the method Demo.run()
All the other stuff should be hidden
Any comments are welcome
/**
* The builder build Specs and defines utility methods, filters
* It shares its context with all elements in the domain
*/
class SpecBuilder {
/** the context will be shared with all domain model objects */
private context
/** model = all the domain model objects */
private model
/** getters / setters */
public getModel() { return model }
public getContext() {
return context
}
/** constructors and helpers */
public SpecBuilder(aContext) {
context = aContext
}
/** Default constructor forbidden */
private SpecBuilder() {}
public from(aList, closure) {
from(aList);
model.each { closure(it) }
return this
}
public from(aList) {
model = aList.collect { new SpecModel(it, context) }
return this
}
/* TODO filters etc */
/** stats: print counters */
public stats() {
println " Hello counts"
model.each {
def key = it.name
def value = this.context[key]
println "Counter for ${key} = ${value}"
}
}
/**
* syntactic sugar
* direct access without 'it' (optional)
*/
public SpecBuilder eachModelDo(closure) {
model.each {
closure.delegate = it;
closure(it)
}
}
}
/**
* The Spec Domain Model
*/
class SpecModel {
/** the shared context */
private context;
/** other properties */
private name;
public address;
/** getters and setters */
public getName() { return name }
public void setAddress(a) { address = a }
public getAddress() { return address }
public sayHello() { return getSayHello }
public sayGoodBye() { return getSayGoodBye }
public sendEmail() { return getSendEmail }
/** constructors */
public SpecModel(aName, aContext) {
name = aName
context = aContext
}
/** Default constructor forbidden */
private SpecModel() {}
/** method used like properties, without 'get' and ()*/
public getSayHello() {
println "(!) hello ${name}"
context[name] = context.get(name,0) +1;
}
public getSayGoodBye() {
println "goodBye ${name} !"
}
public getSendEmail() {
println "email for ${name}"
if (address)
println "Address ${address}"
}
public getPrintContext() {
println context
}
/**
* Returns info to caller
*/
public gatherInfo() {
"info for ${name} : ${new java.util.Random().nextInt(50000)}"
}
}
class Demo {
// several Groots here to test uniques ...
def customers = ['Groot', 'Gamora', 'Groot', 'Groot', 'Groot', 'Star-Lord']
/**
* Utility function who generates a random address
* #param name will prefix the address
* #return the address
*/
public randomAddress(def name) {
// good places ... :)
def places = [
"Grande Rue",
"Cours Emile Zola",
"Place Antonin Poncet",
"Rue de la République",
"Boulevard de la Croix Rousse",
"Place Bellecour"
]
def random = new java.util.Random();
return new StringBuilder().append(name).append(" ... ")
// why not 42?
.append( random.nextInt(155)).append(" ")
.append( places[random.nextInt(places.size())] )
.toString();
}
/**
* ======================== Main user program =========================
*/
def run() {
/** the shared context */
def context = [:].asSynchronized() // In case of multi threading access
/** The whole system From a user POV : a big façade */
def MSys = new SpecBuilder(context).from(customers) ;
println "*** 1 ==================== "
/** First form */
MSys.model.each {
it.with {
sayHello
sayGoodBye
setAddress randomAddress(name) ;
sendEmail
}
}
/** other forms
* MSys.with{ is handy
* one could write MSys... on each line
*/
MSys.with {
println "*** 2 ==================== "
model.each { it.sayHello };
println "*** 3 ==================== "
model.with { println " a Model entry = ${it.name} + ${it.address}" }
println "*** 4 ==================== "
/** false not to mutate the model !!! */
model.unique(false, { a, b -> a.name <=> b.name }).each { it.sayHello }
println "*** 5 ==================== "
context['aKey'] = 42
// verify that each entity has the same context
model.with { println " a shared context for ${it.name} : " + it.context }
println "*** Stats ================ "
/** stats on the shared context */
stats()
}
println "*** 6 Info to process ======== "
/** Gather info to process (addresses)*/
def data = MSys.model.inject([:]) { result, entity ->
result[entity.name] = entity.address
result
}
println data
MSys.with {
println "*** 7 ==================== "
model.each {
it.sayHello
it.sayGoodBye
it.setAddress randomAddress(it.name);
it.sendEmail
}
println "*** 8 ==================== "
println " Hello counts"
model.each {
def key = it.name
def value = MSys.context[key]
println "Counter for ${key} = ${value}"
}
}
println "*** 9 ==================== "
MSys.eachModelDo {
sayHello
sayGoodBye
setAddress randomAddress(it.name);
sendEmail
}
}
}
new Demo().run()
/* end of script */

Access a property inside invokeMethod() implemented in a trait

The following Groovy trait implements the GroovyInterceptable interface to allow execution of code before and after method calls.
trait Bar implements GroovyInterceptable {
def bar = "bar"
#Override
invokeMethod(String name, Object args) {
System.out.println(bar)
metaClass.getMetaMethod(name, args).invoke(this, args)
}
def doSomething() {
}
}
The following class implements the trait Bar.
class Foo implements Bar {
}
Have a look at the following code.
def foo = new Foo()
foo.doSomething()
The call to doSomething() is being intercepted by invokeMethod(). A java.lang.StackOverflowError occurs because accessing the property bar inside invokeMethod() implicitly makes a call to the getter of bar which in turn is intercepted by invokeMethod() just trying to access bar again.
How can I access a class property inside invokeMethod without calling this property's getter or setter?
In combination with the trait using this.#bar to access the property does not work.
The code metaClass.getMetaMethod(name, args).invoke(this, args) to invoke the intercepted method could be incorrect although it works when using the trait logic directly inside a class.
Edit for Solution:
The accepted answer contributed by user Opal works like a charm in a script environment. Since the trait is part of a larger project and defined in its own file I made it work like this:
package com.example.project
trait Bar implements GroovyInterceptable {
def bar = "bar"
#Override
invokeMethod(String name, Object args) {
System.out.println(this.com_example_project_Bar__bar)
metaClass.getMetaMethod(name, args).invoke(this, args)
}
def doSomething() {
}
}
It turns out that there's no need to use # for direct field access:
trait Bar implements GroovyInterceptable {
def bar = "bar"
#Override
invokeMethod(String name, Object args) {
System.out.println(Bar__bar)
metaClass.getMetaMethod(name, args).invoke(this, args)
}
def doSomething() {
}
}
class Foo implements Bar {
}
def foo = new Foo()
foo.doSomething()

How do I get the class (scope) from which a closure is called in Groovy?

class Box {
Closure click
Box () {
click = {}
}
void onClick() {
click()
}
}
class TextBox extends Box {
List<String> content
TextBox (String[] a) {
super()
content = a
}
}
class Main {
public static void main(String[] args) {
Main m = new Main()
}
Main() {
String[] a = ["Hello world!"]
Box b = new TextBox(a)
b.click = {content.add("You clicked this box!")}
b.onClick() //throws Exception
}
}
(The above is, obviously, a simplification; in reality, the classes are a bit more involved, and calling of onClick() is due to a click on a JFrame)
Now, when I try to run that (i.e. run Main.main()), I get an exception:
Exception in thread "AWT-EventQueue-0" groovy.lang.MissingPropertyException: No such property: content for class: Main
Clearly, it is, for some reason, searching for the List in Main, not in TextBox or Box, from where it is called. I also tried using this, owner and delegate, but they all point to Main as well.
I managed to have it work by giving this as an argument:
...
void onClick() {
click(this)
}
...
b.click = {it.content.add("You clicked this box!")}
It seems, however, weird to actually need to pass "this" to a closure just for it to be able to know where it was called from. Isn't there a more elegant solution? Also, even if it is indeed impossible to get into the TextBox-scope, is it somehow possible to get into the Box-scope?
Main() {
String[] a = ["Hello world!"]
Box b = new TextBox(a)
println "1:- $b.click.delegate" //Will print TextBox
b.click = {
println "2:- $b.click.delegate" //Will print Main
//Since the closure is now defined inside Main(),
//Main becomes the delegate. Reset the delegate to TextBox.
b.click.delegate = b
println "3:- $b.click.delegate" //Will print TextBox
content.add("You clicked this box!")
}
println "4:- $b.click.delegate" //Will print Main
b.onClick()
println b.content //Will print [Hello world!, You clicked this box!]
}
//Output:
1:- TextBox#c166770
4:- Main#6dbdc863
2:- Main#6dbdc863
3:- TextBox#c166770
[Hello world!, You clicked this box!]
Points to note:
Sequence 4 is present before 2 and 3 since the closure is not called/invoked at that point of time.
Sequence 1 prints TextBox but Sequence 4 prints Main. Note that the delegate has changed (after defining closure b.click) from TextBox to Main by now.
To make things easier, instead of changing things in Main, you can just modify onClick() as
void onClick() {
click.delegate = this
click()
}
Refer this script for details.
See closures groovy docs. Pay attention on Implicit variables: this, owner, and delegate.
Edit:
Fix delegate before call:
b.click = {content.add("You clicked this box!")}
b.click.delegate = b

How do I delegate methodMissing calls to nested classes?

I'd like to create a DSL with syntax like:
Graph.make {
foo {
bar()
definedMethod1() // isn't missing!
}
baz()
}
Where when the handler for this tree encounters the outermost closure, it creates an instance of some class, which has some defined methods and also its own handler for missing methods.
I figured this would be easy enough with some structure like:
public class Graph {
def static make(Closure c){
Graph g = new Graph()
c.delegate = g
c()
}
def methodMissing(String name, args){
println "outer " + name
ObjImpl obj = new ObjImpl(type: name)
if(args.length > 0 && args[0] instanceof Closure){
Closure closure = args[0]
closure.delegate = obj
closure()
}
}
class ObjImpl {
String type
def methodMissing(String name, args){
println "inner " + name
}
def definedMethod1(){
println "exec'd known method"
}
}
}
But the methodMissing handler interprets the entire closure inside Graph rather than delegating the inner closure to ObjImpl, yielding output:
outer foo
outer bar
exec'd known method
outer baz
How do I scope the missing method call for the inner closure to the inner object that I create?
The easy answer is to set the inner closure's resolveStrategy to "delegate first", but doing that when the delegate defines a methodMissing to intercept all method calls has the effect of making it impossible to define a method outside the closure and call it from inside, e.g.
def calculateSomething() {
return "something I calculated"
}
Graph.make {
foo {
bar(calculateSomething())
definedMethod1()
}
}
To allow for this sort of pattern it's better to leave all the closures as the default "owner first" resolve strategy, but have the outer methodMissing be aware of when there is an inner closure in progress and hand back down to that:
public class Graph {
def static make(Closure c){
Graph g = new Graph()
c.delegate = g
c()
}
private ObjImpl currentObj = null
def methodMissing(String name, args){
if(currentObj) {
// if we are currently processing an inner ObjImpl closure,
// hand off to that
return currentObj.invokeMethod(name, args)
}
println "outer " + name
if(args.length > 0 && args[0] instanceof Closure){
currentObj = new ObjImpl(type: name)
try {
Closure closure = args[0]
closure()
} finally {
currentObj = null
}
}
}
class ObjImpl {
String type
def methodMissing(String name, args){
println "inner " + name
}
def definedMethod1(){
println "exec'd known method"
}
}
}
With this approach, given the above DSL example, the calculateSomething() call will pass up the chain of owners and reach the method defined in the calling script. The bar(...) and definedMethod1() calls will go up the chain of owners and get a MissingMethodException from the outermost scope, then try the delegate of the outermost closure, ending up in Graph.methodMissing. That will then see that there is a currentObj and pass the method call back down to that, which in turn will end up in ObjImpl.definedMethod1 or ObjImpl.methodMissing as appropriate.
If your DSL can be nested more than two levels deep then you'll need to keep a stack of "current objects" rather than a single reference, but the principle is exactly the same.
An alternative approach might be to make use of groovy.util.BuilderSupport, which is designed for tree building DSLs like yours:
class Graph {
List children
void addChild(ObjImpl child) { ... }
static Graph make(Closure c) {
return new GraphBuilder().build(c)
}
}
class ObjImpl {
List children
void addChild(ObjImpl child) { ... }
String name
void definedMethod1() { ... }
}
class GraphBuilder extends BuilderSupport {
// the various forms of node builder expression, all of which
// can optionally take a closure (which BuilderSupport handles
// for us).
// foo()
public createNode(name) { doCreate(name, [:], null) }
// foo("someValue")
public createNode(name, value) { doCreate(name, [:], value) }
// foo(colour:'red', shape:'circle' [, "someValue"])
public createNode(name, Map attrs, value = null) {
doCreate(name, attrs, value)
}
private doCreate(name, attrs, value) {
if(!current) {
// root is a Graph
return new Graph()
} else {
// all other levels are ObjImpl, but you could change this
// if you need to, conditioning on current.getClass()
def = new ObjImpl(type:name)
current.addChild(newObj)
// possibly do something with attrs ...
return newObj
}
}
/**
* By default BuilderSupport treats all method calls as node
* builder calls. Here we change this so that if the current node
* has a "real" (i.e. not methodMissing) method that matches
* then we call that instead of building a node.
*/
public Object invokeMethod(String name, Object args) {
if(current?.respondsTo(name, args)) {
return current.invokeMethod(name, args)
} else {
return super.invokeMethod(name, args)
}
}
}
The way BuilderSupport works, the builder itself is the closure delegate at all levels of the DSL tree. It calls all its closures with the default "owner first" resolve strategy, which means that you can define a method outside the DSL and call it from inside, e.g.
def calculateSomething() {
return "something I calculated"
}
Graph.make {
foo {
bar(calculateSomething())
definedMethod1()
}
}
but at the same time any calls to methods defined by ObjImpl will be routed to the current object (the foo node in this example).
There are at least two problems with this approach:
Defining ObjImpl within the same context as Graph means that any missingMethod call will hit Graph first
Delegation appears to happen locally unless a resolveStrategy is set, e.g.:
closure.resolveStrategy = Closure.DELEGATE_FIRST

Resources