¿Cómo funciona la herencia en Ruby?

Según Dave Thomas en su charla sobre el modelo de objetos de Ruby , no hay “métodos de clase” en Ruby. Solo hay una diferencia entre si el receptor del método es un “objeto de clase” o un “objeto de instancia”.

class Dave def InstaceMethod ### will be stored in the current class (Dave) puts "Hi" end class << self ### Creates an eigenclass, if not created before def say_hello puts "Hello" end end end 

Por defecto, el método de los ancestors no muestra la metaclase:

 class Dave class << self def metaclass ### A way to show the hidden eigenclass class < [Dave, Object, Kernel, BasicObject] p Dave.metaclass.ancestors # => [Class, Module, Object, Kernel, BasicObject] 

Sin embargo, asumo que el verdadero sería algo como:

 # => [, Class, Module, Object, Kernel, BasicObject] p Dave.class.instance_method(false) # => [:allocate, :new, :superclass] p Dave.metaclass.instance_method(false) # => [:say_hello, :metaclass] 

Ahora la herencia.

 class B  "Hello" p B.ancestors # => [B, Dave, Object, Kernel, BasicObject] p B.class.instance_methods(false) # => [:allocate, :new, :superclass] 

Lo siguiente crearía un nuevo eigenclass para B :

 p B.metaclass.ancestors # => [Class, Module, Object, Kernel, BasicObject] p B.metaclass.instance_method(false) # => [] 
  1. ¿Cómo se verían los B.ancestors y B.metaclass.ancestors cuando también se incluyen las clases de eigenclas? El método say_hello se almacena en una eigenclass, (que supongo que B.class hereda de) pero ¿dónde está eso?

  2. Puesto que hay dos cadenas de antepasados ​​( B.ancestors y B.class.ancestors o B.metaclass.ancestors ), ¿cómo se produce realmente la herencia?

Eigenclass es una oculta astuta. Lo has revelado exitosamente abriendo clase. Pero no existe en los antepasados ​​de la clase normal. Y como está oculto , no puede verlo enviando el método de los ancestors a una eigenclass. El árbol de herencia es como el siguiente:

 B ---S--> Dave ---S---> Object ---S---> BasicObject | | | | EEEE | | | | #B --S--> #Dave ---S---> #Object ---S---> #BasicObject --S---> Class,,Object,BasicObject 

S significa superclase, mientras que E para eigenclass.

Un objeto (y también una clase que es un objeto, instancia de Clase) tiene un campo de clase que apunta a su clase. La creación de una clase singleton (eigenclass / metaclass) crea una clase anónima y cambia este puntero para que apunte a la clase anónima, cuyo puntero de clase apunta a la clase original. El método de class no muestra la clase anónima, solo la clase original. Lo mismo para mixins. Una clase tiene un campo de superclase. El método include crea un proxy anónimo, el puntero de superclase se cambia para que apunte a la clase de proxy anónimo y, desde allí, a la superclase. El método ancestors no muestra la clase anónima, sino el nombre del módulo incluido. El método de superclass no muestra la clase de proxy anónimo, solo la superclase original.

Puedes leer esto: ¿Por qué los símbolos en Ruby no se consideran un tipo de variable?

En un comentario a esta respuesta, hay un enlace a un interesante artículo sobre la clase de singleton que se puede encontrar en un blog de Devalot.

Se necesita algo de tiempo para asimilar estas cadenas de herencia. Como una buena imagen vale una explicación larga, recomiendo el capítulo 24 Metaprogtwigción en Pickaxe http://pragprog.com/book/ruby3/programming-ruby-1-9 que tiene varias imágenes sobre todas estas cadenas.

Por defecto, el método de los antepasados ​​no muestra la metaclase:
y 1. ¿Cómo se verían los B. cancestores … cuando también se incluyen las eigenclasses?

ancestors conciernen a la cadena de superclase El eigenclass no pertenece a la cadena de superclase.

p Dave.metaclass.ancestors
=> [Clase, Módulo, Objeto, Kernel, BasicObject]
Sin embargo, asumo que el verdadero sería algo como:
=> [ “eigenclass” , Clase, Módulo, Objeto, Kernel, BasicObject]

Correcto.

Puedes simplificar tu clase de Dave:

 class Dave def self.say_hello # another way to create an eigenclass, if not created before puts "Hello" end def self.metaclass # A way to show the hidden eigenclass class << self self end end end Dave.say_hello # => Hello Dave.new.class.say_hello # => Hello p Dave.metaclass.instance_methods(false) # => [:say_hello, :metaclass] p Dave.singleton_methods # => [:say_hello, :metaclass] 

def self.metaclass es superfluo desde Ruby 1.9.2, que introdujo el Object#singleton_class .

    Intereting Posts