You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by Sean LeBlanc <se...@icd-tech.com> on 2015/07/17 19:23:59 UTC

Metaclass programming and Groovy (2.3.7) traits

I'm trying to figure out the recommended way to write unit tests for 
classes that have methods implemented as traits that need to be 
overwritten with metaclass programming.


What I've noticed is that using an instance of the class doesn't seem to 
work, nor does using the class itself. (Commented out below)

It seems that setting is on the trait itself does work, however, this 
must be done before the first time the implementing class is created, or 
else setting the metaClass to null on the implementing class is required 
(also commented out below)?


Is there a better way to do this?


trait T {
   def speak() {
      println "trait version"
   }
}

class C implements T {
}

def c = new C()
//c.metaClass.speak = { -> println "meta" }
//C.metaClass.speak = { -> println "meta" }

c.speak()
//C.metaClass = null

T.metaClass.speak = { println "meta class version" }
def c2 = new C()
c2.speak()

Re: Metaclass programming and Groovy (2.3.7) traits

Posted by Dinko Srkoč <di...@gmail.com>.
On 21 July 2015 at 21:11, Sean LeBlanc <se...@icd-tech.com> wrote:
> Thanks. I should have mentioned that I would have used that approach, except
> that I wasn't able to figure out how to then set that resulting object to
> the object I want (which is strongly typed in prod code).

It is true that when using `withTraits()` your new object is no longer
of the original type. But I was under the impression that this is for
tests, not production. Also, even though the object's class is not C
any more, it still implements T, so instead of:

  C c = new C().withTraits T2

you could use

  T c = new C().withTraits T2

to see the type checker happy.

>
> Is there any chance this metaclass behavior is related to this bug? We also
> just ran into this one recently, as we started to use more interfaces to
> enforce some behaviors we want concrete classes to have.
>
> https://issues.apache.org/jira/browse/GROOVY-3493
>

There are certainly similarities, and traits are implemented as
interfaces + helper classes, so I guess there is a chance.

Cheers,
Dinko

>
>
> On 7/20/15 2:30 AM, Dinko Srkoč wrote:
>
>> On 17 July 2015 at 19:23, Sean LeBlanc <se...@icd-tech.com> wrote:
>>>
>>> I'm trying to figure out the recommended way to write unit tests for
>>> classes
>>> that have methods implemented as traits that need to be overwritten with
>>> metaclass programming.
>>
>> If what you needed is just overriding trait's methods, you could do it
>> with another trait, without resorting to metaclass fiddling:
>>
>>    trait T {
>>        def speak() {
>>            println "trait version"
>>        }
>>    }
>>
>>    class C implements T {}
>>
>>    trait T2 {
>>        def speak() {
>>            println "another trait"
>>        }
>>    }
>>
>>    def c = new C().withTraits T2
>>    c.speak() // prints "another trait"
>>
>> Cheers,
>> Dinko
>>
>>>
>>> What I've noticed is that using an instance of the class doesn't seem to
>>> work, nor does using the class itself. (Commented out below)
>>>
>>> It seems that setting is on the trait itself does work, however, this
>>> must
>>> be done before the first time the implementing class is created, or else
>>> setting the metaClass to null on the implementing class is required (also
>>> commented out below)?
>>>
>>>
>>> Is there a better way to do this?
>>>
>>>
>>> trait T {
>>>    def speak() {
>>>       println "trait version"
>>>    }
>>> }
>>>
>>> class C implements T {
>>> }
>>>
>>> def c = new C()
>>> //c.metaClass.speak = { -> println "meta" }
>>> //C.metaClass.speak = { -> println "meta" }
>>>
>>> c.speak()
>>> //C.metaClass = null
>>>
>>> T.metaClass.speak = { println "meta class version" }
>>> def c2 = new C()
>>> c2.speak()
>
>

Re: Metaclass programming and Groovy (2.3.7) traits

Posted by Sean LeBlanc <se...@icd-tech.com>.
Thanks. I should have mentioned that I would have used that approach, 
except that I wasn't able to figure out how to then set that resulting 
object to the object I want (which is strongly typed in prod code).

Is there any chance this metaclass behavior is related to this bug? We 
also just ran into this one recently, as we started to use more 
interfaces to enforce some behaviors we want concrete classes to have.

https://issues.apache.org/jira/browse/GROOVY-3493



On 7/20/15 2:30 AM, Dinko Srkoč wrote:
> On 17 July 2015 at 19:23, Sean LeBlanc <se...@icd-tech.com> wrote:
>> I'm trying to figure out the recommended way to write unit tests for classes
>> that have methods implemented as traits that need to be overwritten with
>> metaclass programming.
> If what you needed is just overriding trait's methods, you could do it
> with another trait, without resorting to metaclass fiddling:
>
>    trait T {
>        def speak() {
>            println "trait version"
>        }
>    }
>
>    class C implements T {}
>
>    trait T2 {
>        def speak() {
>            println "another trait"
>        }
>    }
>
>    def c = new C().withTraits T2
>    c.speak() // prints "another trait"
>
> Cheers,
> Dinko
>
>>
>> What I've noticed is that using an instance of the class doesn't seem to
>> work, nor does using the class itself. (Commented out below)
>>
>> It seems that setting is on the trait itself does work, however, this must
>> be done before the first time the implementing class is created, or else
>> setting the metaClass to null on the implementing class is required (also
>> commented out below)?
>>
>>
>> Is there a better way to do this?
>>
>>
>> trait T {
>>    def speak() {
>>       println "trait version"
>>    }
>> }
>>
>> class C implements T {
>> }
>>
>> def c = new C()
>> //c.metaClass.speak = { -> println "meta" }
>> //C.metaClass.speak = { -> println "meta" }
>>
>> c.speak()
>> //C.metaClass = null
>>
>> T.metaClass.speak = { println "meta class version" }
>> def c2 = new C()
>> c2.speak()


Re: Metaclass programming and Groovy (2.3.7) traits

Posted by Dinko Srkoč <di...@gmail.com>.
On 17 July 2015 at 19:23, Sean LeBlanc <se...@icd-tech.com> wrote:
> I'm trying to figure out the recommended way to write unit tests for classes
> that have methods implemented as traits that need to be overwritten with
> metaclass programming.

If what you needed is just overriding trait's methods, you could do it
with another trait, without resorting to metaclass fiddling:

  trait T {
      def speak() {
          println "trait version"
      }
  }

  class C implements T {}

  trait T2 {
      def speak() {
          println "another trait"
      }
  }

  def c = new C().withTraits T2
  c.speak() // prints "another trait"

Cheers,
Dinko

>
>
> What I've noticed is that using an instance of the class doesn't seem to
> work, nor does using the class itself. (Commented out below)
>
> It seems that setting is on the trait itself does work, however, this must
> be done before the first time the implementing class is created, or else
> setting the metaClass to null on the implementing class is required (also
> commented out below)?
>
>
> Is there a better way to do this?
>
>
> trait T {
>   def speak() {
>      println "trait version"
>   }
> }
>
> class C implements T {
> }
>
> def c = new C()
> //c.metaClass.speak = { -> println "meta" }
> //C.metaClass.speak = { -> println "meta" }
>
> c.speak()
> //C.metaClass = null
>
> T.metaClass.speak = { println "meta class version" }
> def c2 = new C()
> c2.speak()