Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use groovy's AS keyword

This may be a duplicate but "as" is an INCREDABLY hard keyword to google, even S.O. ignores "as" as part of query.

So I'm wondering how to implement a class that supports "as" reflexively. For an example class:

class X {
    private val
    public X(def v) {
        val=v
    }
    public asType(Class c) {
        if (c == Integer.class)
            return val as Integer
        if(c == String.class)
            return val as String
    }
}

This allows something like:

new X(3) as String

to work, but doesn't help with:

3 as X

I probably have to attach/modify the "asType" on String and Integer somehow, but I feel any changes like this should be confined to the "X" class... Can the X class either implement a method like:

X fromObject(object)

or somehow modify the String/Integer class from within X. This seems tough since it won't execute any code in X until X is actually used... what if my first usage of X is "3 as X", will X get a chance to override Integer's asType before Groovy tries to call is?

like image 823
Bill K Avatar asked Nov 16 '12 18:11

Bill K


2 Answers

As you say, it's not going to be easy to change the asType method for Integer to accept X as a new type of transformation (especially without destroying the existing functionality).

The best I can think of is to do:

Integer.metaClass.toX = { -> new X( delegate ) }

And then you can call:

3.toX()

I can't think how 3 as X could be done -- as you say, the other way; new X('3') as Integer is relatively easy.


Actually, you can do this:

// Get a handle on the old `asType` method for Integer
def oldAsType = Integer.metaClass.getMetaMethod( "asType", [Class] as Class[] )

// Then write our own
Integer.metaClass.asType = { Class c ->
  if( c == X ) {
    new X( delegate )
  }
  else {
    // if it's not an X, call the original
    oldAsType.invoke( delegate, c )
  }
}

3 as X
like image 161
tim_yates Avatar answered Sep 30 '22 01:09

tim_yates


This keeps the functionality out of the Integer type, and minimizes scope of the effect (which is good or bad depending on what you're looking for).

This category will apply asType from the Integer side.

class IntegerCategory {
    static Object asType(Integer inty, Class c) {
        if(c == X) return new X(inty)
        else return inty.asType(c)
    }
}

use (IntegerCategory) { 
    (3 as X) instanceof X
}
like image 31
Brian Henry Avatar answered Sep 29 '22 23:09

Brian Henry