Method closure and custom MetaClass

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
16 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Method closure and custom MetaClass

Edward Povazan
Hello,

Is there something special about using methods as closures vs normal closures?

I have been weaving some Groovy magic, making Swing coding easier. The idea is
to specify blocks where Swing code must be run in the event dispatch queue. The
update* blocks represent code that runs in the EDT, the rest runs in a non EDT
thread. Works like magic:

def work = {
        try {
                updateUI {
                        buttonExit.enabled = false
                        buttonDownload.text = "Cancel"
                }
                for (i in 1..100) {
                        Thread.sleep(50)
                        updateProgress(i) {
                                progressDownload.value = it
                        }
                }
        } finally {
                updateUI {
                        buttonExit.enabled = true
                        buttonDownload.text = "Download"
                        progressDownload.value = 0
                }
        }
        return true
}

However, if I define work as a method:
def work { ... }
and say
Swing.run(this.&work)
nothing happens.

I give the work closure a custom metaclass like this:
private void initGroovySwingWorker(Closure work, Closure progressHandler) {
        synchronized (work) {
                work.metaClass = new WorkClosureMetaClass(this, work.metaClass)
        }
...
}

In the snipped above, the work Closure is a MethodClosure (this.&work)
What gives? No exceptions, just no work being processed. It is as it the
MethodClosure's MetaClass does nothing.

Any insights please?
-Ed

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

Re: Method closure and custom MetaClass

tugwilson

On 12 Jul 2006, at 06:19, Edward Povazan wrote:

> Hello,
>
> Is there something special about using methods as closures vs  
> normal closures?

Hi Ed!

There shouldn't be but that doesn't mean there isn't!


It's possible that ther's code in byteCodAdapter, Invoker,  
InvokerHelper or some such which should really be in the MetaClass.  
You will see a whole bunch of "instanceof" tests in this code. Each  
one (other than a test to see if it's a GroovyObject in order to  
determine how to get the MetaClass instance) is a sign that the  
following code should be migrated into the MetaClass. However, a  
quick search in the code base only finds on instanceof MethodClosure  
in Invoker which is to do with asCollection. This code will  
eventually have to be migrated into the MetaClass but does not seem  
to explain your problem.

In cases like this I would suggest that you throw an exception from  
the method and run your code under GroovyShell with the -d switch.  
You can then walk back up the stack trace and see how it's being  
invoked and why your metaclass isn't involved.


John Wilson
The Wilson Partnership
web http://www.wilson.co.uk
blog http://eek.ook.org



---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

RE: Method closure and custom MetaClass

Dierk König
> However, a
> quick search in the code base only finds on instanceof MethodClosure
> in Invoker which is to do with asCollection.

this is used with the
 for (ident in iterable) {}
loop where iterable can be a MethodClosure that yields items successively.

I currently don't see how that could be handled by MetaClass.
I also quite like that the whole logic is in (almost) one place, even though
it is not very elegant...

cheers
Mittie


---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

Re: Method closure and custom MetaClass

tugwilson

On 12 Jul 2006, at 11:59, Dierk Koenig wrote:

>> However, a
>> quick search in the code base only finds on instanceof MethodClosure
>> in Invoker which is to do with asCollection.
>
> this is used with the
>  for (ident in iterable) {}
> loop where iterable can be a MethodClosure that yields items  
> successively.
>
> I currently don't see how that could be handled by MetaClass.
> I also quite like that the whole logic is in (almost) one place,  
> even though
> it is not very elegant...


because the MethodClosure MetaClass *knows* it's acting for a object  
which is an instanceof MethodClosure and so it can implement  
asCollection() and provide this behaviour.

It's not just inelegant but it completely violates the principle that  
"the MetaClass decides" which is what we all signed up to at the  
Paris meeting.



John Wilson
The Wilson Partnership
web http://www.wilson.co.uk
blog http://eek.ook.org



---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

Re: Method closure and custom MetaClass

Edward Povazan
In reply to this post by tugwilson
John Wilson wrote:
> It's possible that ther's code in byteCodAdapter, Invoker, InvokerHelper
> or some such which should really be in the MetaClass. You will see a
> whole bunch of "instanceof" tests in this code.
...
> In cases like this I would suggest that you throw an exception from the
> method
I don't follow - which code? You mean a custom Groovy build?

I've been looking at the source, MethodClosure seems to be the only one with a
doCall method. Somehow its doCall() is no called.
Object invokeMethod(Object object, String methodName, Object[] arguments) {
   if (methodName == 'updateUI') {
     ...
   } else if (methodName == 'updateProgress') {
     ...
   }
   println "method=$methodName"
   return super.invokeMethod(object, methodName, arguments)
}

When using a normal closure, the println emits
call
doCall
With the method closure
call
is the only thing emitted.

I am not sure what this means. Well, I will run it under JSwat sometime and
follow it around. It is not serious, as using a normal closure is no problem.

Thanks
-Ed

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

Re: Method closure and custom MetaClass

Jochen Theodorou
Edward Povazan schrieb:
> John Wilson wrote:
>> It's possible that ther's code in byteCodAdapter, Invoker,
>> InvokerHelper or some such which should really be in the MetaClass.
>> You will see a whole bunch of "instanceof" tests in this code.
> ...
>> In cases like this I would suggest that you throw an exception from
>> the method
> I don't follow - which code? You mean a custom Groovy build?

in the method you want to use through the MethodClosure.

> I've been looking at the source, MethodClosure seems to be the only one
> with a doCall method.

doCall is normally created by the Compiler.

> Somehow its doCall() is no called.
> Object invokeMethod(Object object, String methodName, Object[] arguments) {
>   if (methodName == 'updateUI') {
>     ...
>   } else if (methodName == 'updateProgress') {
>     ...
>   }
>   println "method=$methodName"
>   return super.invokeMethod(object, methodName, arguments)
> }
>
> When using a normal closure, the println emits
> call
> doCall
> With the method closure
> call
> is the only thing emitted.
 >
> I am not sure what this means. Well, I will run it under JSwat sometime
> and follow it around. It is not serious, as using a normal closure is no
> problem.

well, there is this code in MetaClass:

                if (object.getClass()==MethodClosure.class) {
                    MethodClosure mc = (MethodClosure) object;
                    methodName = mc.getMethod();
                    MetaClass ownerMetaClass =
registry.getMetaClass(owner.getClass());
                    return
ownerMetaClass.invokeMethod(owner,methodName,arguments);

that means doCall is not called, instead the saved Method is called
directly. MethodClosures are not thought to be overwritten, so there is
no need to call doCall. doCall is there only because you can use
closure.doCall(), so its for compatibility.

bye blackdrag


--
Jochen Theodorou
Groovy Tech Lead

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

Re: Method closure and custom MetaClass

tugwilson

On 13 Jul 2006, at 10:59, Jochen Theodorou wrote:

> well, there is this code in MetaClass:
>
>                if (object.getClass()==MethodClosure.class) {
>                    MethodClosure mc = (MethodClosure) object;
>                    methodName = mc.getMethod();
>                    MetaClass ownerMetaClass = registry.getMetaClass
> (owner.getClass());
>                    return ownerMetaClass.invokeMethod
> (owner,methodName,arguments);
>
> that means doCall is not called, instead the saved Method is called  
> directly. MethodClosures are not thought to be overwritten, so  
> there is no need to call doCall. doCall is there only because you  
> can use closure.doCall(), so its for compatibility.


That's interesting.

However it seems completely unnecessary. I presume the doCall  
implementation has exactly the same effect. If so there seems no  
reason to have this code in the MetaClass.

Am I missing something?


John Wilson
The Wilson Partnership
web http://www.wilson.co.uk
blog http://eek.ook.org



---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

Re: Method closure and custom MetaClass

Jochen Theodorou
John Wilson schrieb:

>
> On 13 Jul 2006, at 10:59, Jochen Theodorou wrote:
>
>> well, there is this code in MetaClass:
>>
>>                if (object.getClass()==MethodClosure.class) {
>>                    MethodClosure mc = (MethodClosure) object;
>>                    methodName = mc.getMethod();
>>                    MetaClass ownerMetaClass =
>> registry.getMetaClass(owner.getClass());
>>                    return
>> ownerMetaClass.invokeMethod(owner,methodName,arguments);
>>
>> that means doCall is not called, instead the saved Method is called
>> directly. MethodClosures are not thought to be overwritten, so there
>> is no need to call doCall. doCall is there only because you can use
>> closure.doCall(), so its for compatibility.
>
>
> That's interesting.
>
> However it seems completely unnecessary. I presume the doCall
> implementation has exactly the same effect. If so there seems no reason
> to have this code in the MetaClass.
>
> Am I missing something?


well we ahve to change the MethodClosure anyway, because it uses
Reflection to find out the maximum parameters instead of using the
MetaClass for it. I would say we remove doCall, beuase you need the
MethodClosure case in MetaClass anyway. CurriedClisure doesn't have a
doCall method.

the program that Edward should test is:

def work(){
   throw new Exception("test exception from inside work")
}
Swing.run(this.&work)

that should throw an Exception. The the same code, but with a custom
MetaClass and the Exception should still be thrown. If it, then the
MetaClass is wrong.

bye blackdrag

--
Jochen Theodorou
Groovy Tech Lead

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

Re: Method closure and custom MetaClass

tugwilson

On 13 Jul 2006, at 11:28, Jochen Theodorou wrote:

>
> well we ahve to change the MethodClosure anyway, because it uses  
> Reflection to find out the maximum parameters instead of using the  
> MetaClass for it. I would say we remove doCall, beuase you need the  
> MethodClosure case in MetaClass anyway. CurriedClisure doesn't have  
> a doCall method.


Yes MethodClosure is rather strange, isn't it?

Its doCall() uses the delegate rather than the owner which is wrong  
and can potentially cause failure.

I quite agree the use of reflection need to be removed.
I also don't understand why it implements getProperty - the normal  
MetaClass process will handle this perfectly well.


John Wilson
The Wilson Partnership
web http://www.wilson.co.uk
blog http://eek.ook.org



---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply | Threaded
Open this post in threaded view
|

Re: Method closure and custom MetaClass

Jochen Theodorou
John Wilson schrieb:

>
> On 13 Jul 2006, at 11:28, Jochen Theodorou wrote:
>
>>
>> well we ahve to change the MethodClosure anyway, because it uses
>> Reflection to find out the maximum parameters instead of using the
>> MetaClass for it. I would say we remove doCall, beuase you need the
>> MethodClosure case in MetaClass anyway. CurriedClisure doesn't have a
>> doCall method.
>
> Yes MethodClosure is rather strange, isn't it?
 >
> Its doCall() uses the delegate rather than the owner which is wrong and
> can potentially cause failure.

What is the owner of a MethodClosure? Is it the method owner, or the
class the closure is defined in. A BlockClosure sets owner to the
class/closure the closure is defined in. And in case of a curried
closure or a method closure owner should be what? for a curried closure
I would sayy to reuse the values from the original closure. For the
method closure... well... you opinion?

> I quite agree the use of reflection need to be removed.
> I also don't understand why it implements getProperty - the normal
> MetaClass process will handle this perfectly well.

hehe, yes, because there is no "inside" for MethodClosures.

bye blackdrag

--
Jochen Theodorou
Groovy Tech Lead

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

12