ruby inheritance lexical-scope

Ruby-Alcance léxico vs herencia



inheritance lexical-scope (4)

Esta es una continuación de esta pregunta original: Usar "::" en lugar de "módulo ..." para el espacio de nombres de Ruby

En la pregunta SO original, aquí está el escenario presentado que todavía tengo problemas para entender:

FOO = 123 module Foo FOO = 555 end module Foo class Bar def baz puts FOO end end end class Foo::Bar def glorf puts FOO end end puts Foo::Bar.new.baz # -> 555 puts Foo::Bar.new.glorf # -> 123

¿Puede alguien dar alguna explicación de por qué la primera llamada está devolviendo 555 y por qué la segunda llamada está devolviendo 123?


Puedes pensar en cada aspecto del module Something , class Something o def something como una "puerta de entrada" en un nuevo ámbito. Cuando Ruby está buscando la definición de un nombre al que se ha hecho referencia, primero se ve en el alcance actual (el método, clase o módulo), y si no se encuentra allí, volverá a través de cada uno que contenga "puerta de enlace" y buscará el alcance allí.

En su ejemplo, el método baz se define como

module Foo class Bar def baz puts FOO end end end

Por lo tanto, al tratar de determinar el valor de FOO , primero se comprueba la Bar clase y, como Bar no contiene un FOO la búsqueda se mueve hacia arriba a través del "gateway de la class Bar " hacia el módulo Foo que contiene el alcance. Foo contiene un FOO constante (555) así que este es el resultado que ves.

El método glorf se define como:

class Foo::Bar def glorf puts FOO end end

Aquí la "puerta de enlace" es class Foo::Bar , así que cuando FOO no se encuentra dentro de Bar la "puerta de enlace" pasa a través del módulo Foo y directamente al nivel superior, donde hay otro FOO (123) que es lo que se muestra .

Observe cómo el uso de la class Foo::Bar crea una única "puerta de enlace", omitiendo el alcance de Foo , pero el module Foo; class Bar ... module Foo; class Bar ... abre dos "gateways" separados


glorf es un método de la clase Foo, en => [Foo, Module, Object, Kernel, BasicObject]

dentro de ese alcance (es decir, en el módulo predeterminado / principal), se asigna FOO 123

módulo Foo se define como

module Foo FOO = 555 class Bar def baz puts FOO end end end

donde el método baz pertenece a la clase Bar en el módulo Foo => [Bar, Foo, Object, Kernel, BasicObject]

y en ese alcance se asignó a FOO 555


la primera llamada:

puts Foo::Bar.new.baz # -> 555

imprime el resultado de invocar el método baz de una instancia de la clase Foo :: Bar

observe que la definición de Foo :: Bar # baz es en realidad un cierre en FOO . Siguiendo las reglas de alcance de Ruby:

  1. FOO se busca en el alcance de Foo :: Bar (la clase, no la instancia), no se encuentra,
  2. FOO se busca en el alcance adjunto Foo (porque estamos dentro de la definición del módulo) y se encuentra allí (555)

la segunda llamada:

puts Foo::Bar.new.glorf # -> 123

imprime el resultado del método de invocación glorf de una instancia de la clase Foo :: Bar

observe que la definición de Foo :: Bar # glorf esta vez también es un cierre en FOO , pero si seguimos las reglas de alcance de ruby ​​notará que el valor cerrado en este momento es :: FOO (alcance máximo del nivel FOO) de la siguiente manera :

  1. Se busca FOO en el espacio de nombres Foo :: Bar (la clase, no la instancia), no se encuentra
  2. FOO se busca en el alcance adjunto (''nivel superior'') y se encuentra allí (123)

wow, gran pregunta. La mejor respuesta que puedo encontrar es que en este caso está usando el módulo para definir un espacio de nombres.

Mira esto:

FOO = 123 module Foo FOO = 555 end module Foo class Bar def baz puts FOO end def glorf3 puts ::FOO end end end class Foo::Bar def glorf2 puts Foo::FOO end def glorf puts FOO end end puts Foo::Bar.new.baz # -> 555 puts Foo::Bar.new.glorf # -> 123 puts Foo::Bar.new.glorf2 # -> 555 puts Foo::Bar.new.glorf3 # -> 123

Entonces mi pensamiento es que cuando defines:

module Foo FOO = 555 end

estás creando FOO en el espacio de nombres de Foo . Entonces cuando lo usas aquí:

module Foo class Bar def baz puts FOO end end end

estás en el espacio de nombres de Foo . Sin embargo, cuando te refieres a ella en:

class Foo::Bar def glorf puts FOO end end

FOO proviene del espacio de nombres predeterminado (como se muestra en ::FOO ).