This is a continuation this original SO question: Using "::" instead of "module ..." for Ruby namespacing
In the original SO question, here is the scenario presented which I'm still having trouble understanding:
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
Can someone provide some explanation behind why the first call is returning 555 and why the second call is returning 123?
Ruby, like most modern programming languages, uses a static scope, often called lexical scope (as opposed to dynamic scope). The current scope is based on the structure of the code and determines the variables available at specific parts of the code.
If two lines are lexically scoped, it simply means that they occur within the same code block — regardless of what that code block may evaluate to.
Smalltalk, Objective-C, Modula-3, Python, and Ruby use dynamic method binding for all methods.
You can think of each appearance of module Something
, class Something
or def something
as a “gateway” into a new scope. When Ruby is searching for the definition of a name that has been referenced it first looks in the current scope (the method, class or module), and if it isn’t found there it will go back through each containing “gateway” and search the scope there.
In your example the method baz
is defined as
module Foo
class Bar
def baz
puts FOO
end
end
end
So when trying to determine the value of FOO
, first the class Bar
is checked, and since Bar
doesn’t contain a FOO
the search moves up through the “class Bar
gateway” into the Foo
module which is the containing scope. Foo
does contain a constant FOO
(555) so this is the result you see.
The method glorf
is defined as:
class Foo::Bar
def glorf
puts FOO
end
end
Here the “gateway” is class Foo::Bar
, so when FOO
isn’t found inside Bar
the “gateway” passes through the Foo
module and straight into the top level, where there is another FOO
(123) which is what is displayed.
Note how using class Foo::Bar
creates a single “gateway”, skipping over the scope of Foo
, but module Foo; class Bar ...
opens two separate “gateways”
wow, great question. The best answer I can come up with is in this case you're using the module to define a namespace.
Check this out:
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
So my thought is that when you define:
module Foo
FOO = 555
end
you are creating FOO
in the namespace of Foo
. So when you use it here:
module Foo
class Bar
def baz
puts FOO
end
end
end
you are in the Foo
namespace. However, when you refer to it in:
class Foo::Bar
def glorf
puts FOO
end
end
FOO
is coming from the default namespace (as illustrated by ::FOO
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With