Russel Winder | 3 Jul 13:37

[groovy-dev] Meta Object Protocol woes

Clearly I really don't understand the Meta Object Protocol.  However,
before launching into the deep and detailed, let me ask an easy
question.

MetaObjectProtocol requires there to be:

	invokeMethod ( Object , String , Object[] )
	invokeMethod ( Object , String , Object )

is there any obvious reason why?  Are they supposed to have different
purposes, and different implementations?  OK, that was three qeustions.

If I can get a definitive answer to these, then I may be able to save
boring the list with the real problems which involve Gant, Grails, and
why the GantMetaClass implementated one way causes incomprehensible
errors and implemented a different way works fine except for GANT-49.  I
mention this to give people motivation to avoid the detail :-)

--

-- 
Russel.
====================================================
Dr Russel Winder                 Partner

Concertant LLP                   t: +44 20 7585 2200, +44 20 7193 9203
41 Buckmaster Road,              f: +44 8700 516 084
London SW11 1EN, UK.             m: +44 7770 465 077
Alex Tkachman | 4 Jul 10:29

Re: [groovy-dev] Meta Object Protocol woes

Unfortunately, I don't know the history and original intention. Here
is what default implementation (MetaClassImpl) does, which is
effectlvely just casting of arguments.

    public Object invokeMethod(Object object, String methodName,
Object arguments) {
        if (arguments == null) {
            return invokeMethod(object, methodName,
MetaClassHelper.EMPTY_ARRAY);
        }
        if (arguments instanceof Tuple) {
            Tuple tuple = (Tuple) arguments;
            return invokeMethod(object, methodName, tuple.toArray());
        }
        if (arguments instanceof Object[]) {
            return invokeMethod(object, methodName, (Object[]) arguments);
        } else {
            return invokeMethod(object, methodName, new Object[]{arguments});
        }
    }

On Thu, Jul 3, 2008 at 3:38 PM, Russel Winder
<russel.winder@...> wrote:
> Clearly I really don't understand the Meta Object Protocol.  However,
> before launching into the deep and detailed, let me ask an easy
> question.
>
> MetaObjectProtocol requires there to be:
>
>        invokeMethod ( Object , String , Object[] )
(Continue reading)

Russel Winder | 4 Jul 12:16

Re: [groovy-dev] Meta Object Protocol woes

Alex,

On Fri, 2008-07-04 at 12:29 +0400, Alex Tkachman wrote:
> Unfortunately, I don't know the history and original intention. Here
> is what default implementation (MetaClassImpl) does, which is
> effectlvely just casting of arguments.
> 
>     public Object invokeMethod(Object object, String methodName,
> Object arguments) {
>         if (arguments == null) {
>             return invokeMethod(object, methodName,
> MetaClassHelper.EMPTY_ARRAY);
>         }
>         if (arguments instanceof Tuple) {
>             Tuple tuple = (Tuple) arguments;
>             return invokeMethod(object, methodName, tuple.toArray());
>         }
>         if (arguments instanceof Object[]) {
>             return invokeMethod(object, methodName, (Object[]) arguments);
>         } else {
>             return invokeMethod(object, methodName, new Object[]{arguments});
>         }
>     }

That is exactly the code I found (and copied :-) for Gant and that is
what is causing a) the errors that Gant had to go away; and b) introduce
new errors into Gant.  I was happy with a then Peter noted b cf.
GANT-49 :-(

Peter and I had a private email exchange which has shed some light on
(Continue reading)

Graeme Rocher | 4 Jul 12:36
Gravatar

Re: [groovy-dev] Meta Object Protocol woes

On Fri, Jul 4, 2008 at 11:16 AM, Russel Winder
<russel.winder@...> wrote:
> Alex,
>
> On Fri, 2008-07-04 at 12:29 +0400, Alex Tkachman wrote:
>> Unfortunately, I don't know the history and original intention. Here
>> is what default implementation (MetaClassImpl) does, which is
>> effectlvely just casting of arguments.
>>
>>     public Object invokeMethod(Object object, String methodName,
>> Object arguments) {
>>         if (arguments == null) {
>>             return invokeMethod(object, methodName,
>> MetaClassHelper.EMPTY_ARRAY);
>>         }
>>         if (arguments instanceof Tuple) {
>>             Tuple tuple = (Tuple) arguments;
>>             return invokeMethod(object, methodName, tuple.toArray());
>>         }
>>         if (arguments instanceof Object[]) {
>>             return invokeMethod(object, methodName, (Object[]) arguments);
>>         } else {
>>             return invokeMethod(object, methodName, new Object[]{arguments});
>>         }
>>     }
>
> That is exactly the code I found (and copied :-) for Gant and that is
> what is causing a) the errors that Gant had to go away; and b) introduce
> new errors into Gant.  I was happy with a then Peter noted b cf.
> GANT-49 :-(
(Continue reading)

Russel Winder | 4 Jul 12:50

Re: [groovy-dev] Meta Object Protocol woes

Graeme,

On Fri, 2008-07-04 at 11:36 +0100, Graeme Rocher wrote:

> It is due to pain like this that we don't use any custom meta classes
> in Grails. Only ExpandoMetaClass

I am not sure the problem can be laid at the door of the custom
metaclass (vs. ExpandoMetaClass).   I need an intercepting metaclass.
Initially I used DelegatingMetaClass as a superclass but now I have
switched to a more minimal specialist class that has no superclass and
implements all the requirements of MetaClass, MetaObjectProtocol and
GroovyObject directly to try and avoid any areas of doubt and
uncertainty.  OK so it is a custom class but it is just a minimal
intercepting metaclass. The problem here is the metaclass system itself
-- it is too complicated and too open to interaction with the
overloading and strong type system -- or actually lack of it, which is
where I think the non-determinism is coming in.

However this is just moaning, I need to find out what is happening and
how to fix it, so that means back to Eclipse or IntelliJ IDEA to find
out what is going on.

--

-- 
Russel.
====================================================
Dr Russel Winder                 Partner

Concertant LLP                   t: +44 20 7585 2200, +44 20 7193 9203
41 Buckmaster Road,              f: +44 8700 516 084
(Continue reading)

Graeme Rocher | 4 Jul 13:01
Gravatar

Re: [groovy-dev] Meta Object Protocol woes

On Fri, Jul 4, 2008 at 11:50 AM, Russel Winder
<russel.winder <at> concertant.com> wrote:
> Graeme,
>
> On Fri, 2008-07-04 at 11:36 +0100, Graeme Rocher wrote:
>
>> It is due to pain like this that we don't use any custom meta classes
>> in Grails. Only ExpandoMetaClass
>
> I am not sure the problem can be laid at the door of the custom
> metaclass (vs. ExpandoMetaClass).   I need an intercepting metaclass.
> Initially I used DelegatingMetaClass as a superclass but now I have
> switched to a more minimal specialist class that has no superclass and
> implements all the requirements of MetaClass, MetaObjectProtocol and
> GroovyObject directly to try and avoid any areas of doubt and
> uncertainty.  OK so it is a custom class but it is just a minimal
> intercepting metaclass. The problem here is the metaclass system itself
> -- it is too complicated and too open to interaction with the
> overloading and strong type system -- or actually lack of it, which is
> where I think the non-determinism is coming in.

My view on this is you should not be working at this level of the MOP
as its subject to constant change, you should always work with a
higher level abstraction that isn't going to change (like EMC). By
implementing your own meta class you are working directly with the
internals of Groovy can its really easy to make a hash of the dispatch
logic even without realising it (introducing subtle bugs)

Looking at GantMetaClass this is nothing you cannot do with EMC by
overriding invokeMethod:
(Continue reading)

Russel Winder | 4 Jul 13:13

Re: [groovy-dev] Meta Object Protocol woes

Graeme,

On Fri, 2008-07-04 at 12:01 +0100, Graeme Rocher wrote:

> My view on this is you should not be working at this level of the MOP
> as its subject to constant change, you should always work with a
> higher level abstraction that isn't going to change (like EMC). By
> implementing your own meta class you are working directly with the
> internals of Groovy can its really easy to make a hash of the dispatch
> logic even without realising it (introducing subtle bugs)

I agree with the sentiment regarding not working at the internals level.
On the other hand a MOP is supposed to be there to be used, it just
needs an API that is not subject to change -- at least not during 1.x
since 2.x si when the new MOP happens.

John answered this question originally by saying DelegatingMetaClass is
the superclass to use as it is a guaranteed API that will never change.
Then the API changed.  Also it is malleable and I think it best to avoid
that.

If the best advice is now use ExpandoMetaClass and it can be used as an
intercepting metaclass then it is certainly worth a try.  Fortunately I
think GantMetaClass can be changed without changing anything else in the
Gant code.

> Looking at GantMetaClass this is nothing you cannot do with EMC by
> overriding invokeMethod:
> 
> http://groovy.codehaus.org/ExpandoMetaClass+-+GroovyObject+Methods
(Continue reading)

Graeme Rocher | 4 Jul 13:18
Gravatar

Re: [groovy-dev] Meta Object Protocol woes

On Fri, Jul 4, 2008 at 12:13 PM, Russel Winder
<russel.winder@...> wrote:
> Graeme,
>
> On Fri, 2008-07-04 at 12:01 +0100, Graeme Rocher wrote:
>
>> My view on this is you should not be working at this level of the MOP
>> as its subject to constant change, you should always work with a
>> higher level abstraction that isn't going to change (like EMC). By
>> implementing your own meta class you are working directly with the
>> internals of Groovy can its really easy to make a hash of the dispatch
>> logic even without realising it (introducing subtle bugs)
>
> I agree with the sentiment regarding not working at the internals level.
> On the other hand a MOP is supposed to be there to be used, it just
> needs an API that is not subject to change -- at least not during 1.x
> since 2.x si when the new MOP happens.

The API that doesn't change == ExpandoMetaClass :-)

>
> John answered this question originally by saying DelegatingMetaClass is
> the superclass to use as it is a guaranteed API that will never change.
> Then the API changed.  Also it is malleable and I think it best to avoid
> that.

I'm not sure where John was going with this, but I can't say I agree.
All DMC does is delegate to another meta class, of course a side
effect of this is that it always implements all interface
provided/abstract methods which may have persuaded John to believe
(Continue reading)

Russel Winder | 4 Jul 13:34

Re: [groovy-dev] Meta Object Protocol woes

Graeme,

On Fri, 2008-07-04 at 12:18 +0100, Graeme Rocher wrote:

> The API that doesn't change == ExpandoMetaClass :-)

Is that a lemma, theorem or axiom ;-)

> I'm not sure where John was going with this, but I can't say I agree.
> All DMC does is delegate to another meta class, of course a side
> effect of this is that it always implements all interface
> provided/abstract methods which may have persuaded John to believe
> this, but certainly that is not the only thing that can cause
> breakage. There is also the semantics of the code and remove of
> methods all together.

It is all water under the bridge now so no real point in worrying.

> > If the best advice is now use ExpandoMetaClass and it can be used as an
> > intercepting metaclass then it is certainly worth a try.  Fortunately I
> > think GantMetaClass can be changed without changing anything else in the
> > Gant code.
> 
> That is my view yes. Also refer to Venkat's book
> (http://www.pragprog.com/titles/vslg/programming-groovy) he has lots
> of great examples of this.

The publishers have failed to deliver my copy of the book so I'll have
to go back to the proofs I had -- unless I already threw them on the
expectation of getting a copy of the final tome.
(Continue reading)

Jochen Theodorou | 15 Jul 12:36
Gravatar

Re: [groovy-dev] Meta Object Protocol woes

Russel Winder schrieb:
> Graeme,
> 
> On Fri, 2008-07-04 at 12:18 +0100, Graeme Rocher wrote:
> 
>> The API that doesn't change == ExpandoMetaClass :-)
> 
> Is that a lemma, theorem or axiom ;-)

I think the usage of ExpandoMetaClass through object.metaClass.foo = {} 
and alikes, is save till 2.0 and beyond. The direct usage of the API of 
EMC and overwriting its invokeMethod method for example is different.

>> I'm not sure where John was going with this, but I can't say I agree.
>> All DMC does is delegate to another meta class, of course a side
>> effect of this is that it always implements all interface
>> provided/abstract methods which may have persuaded John to believe
>> this, but certainly that is not the only thing that can cause
>> breakage. There is also the semantics of the code and remove of
>> methods all together.
> 
> It is all water under the bridge now so no real point in worrying.

the idea was that you use the original MetaClass and only add logic 
where you need it. I bascially think the idea is right and this is my 
model for 2.0 as well.. only with more abstraction

bye blackdrag

--

-- 
(Continue reading)

Russel Winder | 16 Jul 17:08

Re: [groovy-dev] Meta Object Protocol woes

On Tue, 2008-07-15 at 12:36 +0200, Jochen Theodorou wrote:
> Russel Winder schrieb:
> > Graeme,
> > 
> > On Fri, 2008-07-04 at 12:18 +0100, Graeme Rocher wrote:
> > 
> >> The API that doesn't change == ExpandoMetaClass :-)
> > 
> > Is that a lemma, theorem or axiom ;-)
> 
> I think the usage of ExpandoMetaClass through object.metaClass.foo = {} 
> and alikes, is save till 2.0 and beyond. The direct usage of the API of 
> EMC and overwriting its invokeMethod method for example is different.
> 
> >> I'm not sure where John was going with this, but I can't say I agree.
> >> All DMC does is delegate to another meta class, of course a side
> >> effect of this is that it always implements all interface
> >> provided/abstract methods which may have persuaded John to believe
> >> this, but certainly that is not the only thing that can cause
> >> breakage. There is also the semantics of the code and remove of
> >> methods all together.
> > 
> > It is all water under the bridge now so no real point in worrying.
> 
> the idea was that you use the original MetaClass and only add logic 
> where you need it. I bascially think the idea is right and this is my 
> model for 2.0 as well.. only with more abstraction

I have to admit until the new metaclass system starts to appear, I am
going to stick with DelegatingMetaClass.  DelegatingMetaClass really
(Continue reading)

Alex Tkachman | 4 Jul 13:50

Re: [groovy-dev] Meta Object Protocol woes

And it is what I recommend to everybody - don't use custom meta classes

On Fri, Jul 4, 2008 at 2:36 PM, Graeme Rocher <graeme@...> wrote:
> On Fri, Jul 4, 2008 at 11:16 AM, Russel Winder
> <russel.winder@...> wrote:
>> Alex,
>>
>> On Fri, 2008-07-04 at 12:29 +0400, Alex Tkachman wrote:
>>> Unfortunately, I don't know the history and original intention. Here
>>> is what default implementation (MetaClassImpl) does, which is
>>> effectlvely just casting of arguments.
>>>
>>>     public Object invokeMethod(Object object, String methodName,
>>> Object arguments) {
>>>         if (arguments == null) {
>>>             return invokeMethod(object, methodName,
>>> MetaClassHelper.EMPTY_ARRAY);
>>>         }
>>>         if (arguments instanceof Tuple) {
>>>             Tuple tuple = (Tuple) arguments;
>>>             return invokeMethod(object, methodName, tuple.toArray());
>>>         }
>>>         if (arguments instanceof Object[]) {
>>>             return invokeMethod(object, methodName, (Object[]) arguments);
>>>         } else {
>>>             return invokeMethod(object, methodName, new Object[]{arguments});
>>>         }
>>>     }
>>
>> That is exactly the code I found (and copied :-) for Gant and that is
(Continue reading)

Peter Ledbrook | 4 Jul 13:07
Gravatar

Re: [groovy-dev] Meta Object Protocol woes


Russel Winder-4 wrote:
> 
> That is exactly the code I found (and copied :-) for Gant and that is
> what is causing a) the errors that Gant had to go away; and b) introduce
> new errors into Gant.  I was happy with a then Peter noted b cf.
> GANT-49 :-(
> 

Just to add fuel, here's my take on the problem. Let's imagine we have a
Gant target like this:

  target(tgt : "Some description") {
      def bb = new BeanBuilder()
      bb.beans {
          i18nService(I18nService)
      }
  }

The outer {}'s demarcate a closure (not a method body). All invocations
inside that closure, including "i18nService(...)", go through
GantMetaClass.invokeMethod(...).

All well and good. The problem appears with that "i18nService(...)" method
call. The method doesn't exist, so when GantMetaClass tries to invoke that
method on the meta class that it's proxying, a big, fat
MissingMethodException is thrown. Since the method doesn't appear to exist,
GantMetaClass catches that exception and tries to call the method on its
AntBuilder instead. Boom! That throws an InvokerSomethingException and the
build breaks.
(Continue reading)

Russel Winder | 4 Jul 13:37

Re: [groovy-dev] Meta Object Protocol woes

Peter,

As per Graeme's message, I am going to try using an ExpandoMetaClass as
a base for GantMetaClass instead of the current implementation, but I
think these issues we are looking at will still arise.

On Fri, 2008-07-04 at 04:07 -0700, Peter Ledbrook wrote:

> Just to add fuel, here's my take on the problem. Let's imagine we have a
> Gant target like this:
> 
>   target(tgt : "Some description") {
>       def bb = new BeanBuilder()
>       bb.beans {
>           i18nService(I18nService)
>       }
>   }
> 
> The outer {}'s demarcate a closure (not a method body). All invocations
> inside that closure, including "i18nService(...)", go through
> GantMetaClass.invokeMethod(...).
> 
> All well and good. The problem appears with that "i18nService(...)" method
> call. The method doesn't exist, so when GantMetaClass tries to invoke that
> method on the meta class that it's proxying, a big, fat
> MissingMethodException is thrown. Since the method doesn't appear to exist,
> GantMetaClass catches that exception and tries to call the method on its
> AntBuilder instead. Boom! That throws an InvokerSomethingException and the
> build breaks.

(Continue reading)

Jochen Theodorou | 15 Jul 12:44
Gravatar

Re: [groovy-dev] Meta Object Protocol woes

Peter Ledbrook schrieb:
> 
> Russel Winder-4 wrote:
>> That is exactly the code I found (and copied :-) for Gant and that is
>> what is causing a) the errors that Gant had to go away; and b) introduce
>> new errors into Gant.  I was happy with a then Peter noted b cf.
>> GANT-49 :-(
>>
> 
> Just to add fuel, here's my take on the problem. Let's imagine we have a
> Gant target like this:
> 
>   target(tgt : "Some description") {
>       def bb = new BeanBuilder()
>       bb.beans {
>           i18nService(I18nService)
>       }
>   }
> 
> The outer {}'s demarcate a closure (not a method body). All invocations
> inside that closure, including "i18nService(...)", go through
> GantMetaClass.invokeMethod(...).
> 
> All well and good. The problem appears with that "i18nService(...)" method
> call. The method doesn't exist, so when GantMetaClass tries to invoke that
> method on the meta class that it's proxying, a big, fat
> MissingMethodException is thrown. Since the method doesn't appear to exist,
> GantMetaClass catches that exception and tries to call the method on its
> AntBuilder instead. Boom! That throws an InvokerSomethingException and the
> build breaks.
(Continue reading)


Gmane