2012-03-01 15 views
9

Estaba intentando depurar algún código que usa mixins y pude reducir mi problema a este ejemplo. Tengo una clase para padres que recibe métodos a través de mixin y una clase hija que hereda del padre. Si trato de reemplazar un método en una instancia de la clase hija funciona A MENOS QUE se invocó el método que estoy reemplazando en una instancia de la clase padre antes de que se sustituya. Si se le ha llamado, entonces no puedo reemplazarlo¿Qué está haciendo Groovy aquí?

lo que este código:

class M { 
    protected foo() { println 'foo' } 
} 

@Mixin(M) class A { 
def bar() { foo() } 
} 

class B extends A {} 

def b = new B() 
def a = new A() 
a.bar() //<-- comment out this line and see the difference 
b.metaClass.foo = {println 'winning'} 
b.bar() 

cederá:

foo

foo

Pero si Si comentas la línea 13 (la que tiene el comentario que dice que debes comentarla) obtendrás:

ganar

¿Por qué sucede esto? Espero que esto tenga sentido en el contexto del modelo de metaclase de Groovy, pero no lo entiendo.

Esto es maravilloso 1.8.6

+1

I también puede reproducir esto en Groovy 1.8.4. Huele como un error para mí; pero no estoy demasiado metido en la metaprogramación de Groovy, así que no sé. – epidemian

+0

Gracias por la nota, me aseguraré de incluir eso si termino archivando un error en él. – mfollett

+0

Preguntaría esto en la lista de correo de usuarios maravillosos, huele como un error para mí ... –

Respuesta

3

La metaclase es visto en una llamada de método y mixins tener su propio controlador. Ambos están cargados de forma perezosa, y estáticos, si no llamas a un método, la carga estática no se produce.
Mixins tiene prioridad sobre las invalidaciones de metaClass por lo que muestra foo y no gana si inicializa A.
Se define una meta en el objeto al que se aplica, para que se resuelva por cada clase que necesite Object.class .metaClass (es decir, aquí B.metaClass). Es interesante que esta rendimientos:

groovy.lang.MissingMethodException: No signature of method: B.foo() is applicable for argument types:() values: [] 
Possible solutions: foo(), foo(java.lang.Object), bar(), any(), use([Ljava.lang.Object;), find(groovy.lang.Closure) 

Definición foo en B solucionar el error:

class B extends A { 
    def foo() { println 'not winning' } 
} 

Su respuesta es que el Mixin afecta a la meta almacén de clases y métodos de la clase tienen prioridad sobre los métodos de meta almacén de objetos.

prueba:

@Mixin(M) 
class B extends A { 

} 

a.bar() //<-- comment out this line and see the difference 
B.metaClass.foo = {println 'class winning'} 
b.metaClass.foo = {println 'object winning'} 
b.bar() 

Rendimiento:

foo 
class winning 

Un enfoque diferente

class M { 
    protected foo() { println 'foo' } 
} 

@Mixin(M) class A { 
def bar() { foo() } 
} 

class B extends A { 
    def bar() { foo() } 
} 

class C extends B { 
    def foo() { println 'wat' } 
} 

@Mixin(M) 
class D extends C { } 

def b = new B() 
def a = new A() 
def c = new C() 
def d = new D() 


a.bar() //<-- comment out this line and see the difference 
b.metaClass.foo = {println 'winning'} 
b.bar() 

c.metaClass.foo = {println 'losing'} 
c.bar() 

d.metaClass.foo = {println 'draw'} 
d.bar() 

rendimientos

foo 
winning 
wat 
wat 
+0

¿tiene alguna fuente que pueda citar para esta información? No sigo totalmente tu respuesta y no puedo encontrar ninguna información sobre el metastore de Groovy. – mfollett

+0

Todo esto es tomado de la documentación y jugando con la consola yo mismo. Su pregunta es muy interesante y merece una publicación de blog en mi opinión. Las páginas Dynamic Groovy del documento ya proporcionan algunas respuestas http://groovy.codehaus.org/Per-Instance+MetaClass – Gepsens

Cuestiones relacionadas