21 Apr 2009, 02:57
Generic-user-small

Shih-gian Lee (5 posts)

Hi Venkat,

First, thank you for the concise and easy to read book. Good work on the Metaprogramming section.

I bought your book last year but only got the time to read it recently. When I run the following code sample from your book using Groovy 1.6.1, the new method is not cached at MetaClass level (ExpandoMetaClass):

class Person
{
  def work() { "working..." }

  def plays = ['Tennis', 'VolleyBall', 'BasketBall']
  
  def methodMissing(String name, args)
  {
    System.out.println "methodMissing called for $name"
    def methodInList = plays.find { it == name.split('play')[1]}
    
    if (methodInList)
    {
      def impl = { Object[] vargs ->
          return "playing ${name.split('play')[1]}..."
        }
        
      Person.metaClass."$name" = impl //future calls will use this
      
      return impl(args)
    }
    else
    {
      throw new MissingMethodException(name, Person.class, args)
    }    
  }

  static { Person.metaClass }
}

jack = new Person()
println jack.playTennis()
println jack.playTennis()

However, when I ran it against Groovy 1.5.6, the new method was cached. I tried to search the Web for enhancements in ExpandoMetaClass but to no avail. Could you help to shed some light on why it is not caching in Grovy 1.6.1? Has the ExpandoMetaClass implementation changed since 1.5.6?

Thank you in advance for your help!

Regards, Lee

21 Apr 2009, 11:32
Venkatsubramaniam_pragsmall

Venkat Subramaniam (84 posts)

Hi Lee,

Thank you for the generous words.

The example relies on the class using ExpandoMetaClass (EMC) as its metaclass (as you know). EMC is the not default metaclass used by classes in Groovy. However, when the metaClass property was requested, the default metaClass was replaced by EMC in earlier version (in the example, this happens within the static initializer). Apparently, that trick is not working in Groovy 1.6.1. Here is a fix. If you call ExpandoMetaClass.enableGlobally() at the top before the code, you will get the expected result in Groovy 1.6.1 also. I am hoping some of these issues with how metaclass is handled will be resolved and made consistent soon in Groovy.

Venkat

21 Apr 2009, 13:00
Generic-user-small

Shih-gian Lee (5 posts)

Hi Venkat,

Thank you for taking some time out of your busy schedule to answer my question. It is really unfortunate that the trick does not work anymore. The Groovy team fixed some of the issues mentioned in your book such as return is optional for if/else but broke the ExpandoMetaClass. The ExpandoMetaClass.enableGlobally did work for me yesterday. However, in your book, you mentioned we need to keep a check on memory consumption when enabling ExapandoMetaClass globally. Do you have any advice on when the memory consumption will be an issue for the application? I don’t mean to optimize the application prematurely but would like to have the information so that I can make a conscious choice when coding in Groovy.

Thanks again.

Lee

P/S: I am looking forward to your Scala book!

21 Apr 2009, 14:15
Venkatsubramaniam_pragsmall

Venkat Subramaniam (84 posts)

Lee, it should be one of several design considerations in using metaprogramming. Evaluate other techniques if that becomes a huge concern.

08 Oct 2009, 17:02
Generic-user-small

Remi Pelletier (1 post)

Can you explain how expando methods are made avaialble to many classes or scripts.

I added some useful metaClass methods to class String but cannot figure out how to re-use them.

They don’t belong inside of class definitions and import doesn’t seem to work.

10 Oct 2009, 09:54
Venkatsubramaniam_pragsmall

Venkat Subramaniam (84 posts)

Hi Remi, these methods that you add are placed in the metaClass and are available at runtime. They are not visible at compile time, so you can’t import them or see them at compile time. However, you can use them at runtime.

Venkat

  You must be logged in to comment