Scope of Variables Redux
In this chapter, you will learn about the visibility of local variables in the context of dynamic language constructs such as define_method, Class.new and Module.new.
Scope
How does dynamically defining methods, classes and modules affect the local variable visibility?
At the Top Level
Visibility of Local Variable
x = 1
p "At top level x : #{x}"
define_method(:test) do
p "Inside top level method x : #{x}"
end
test
This prints:
At top level x : 1
Inside top level method x : 1
The local variable is visible inside the dynamically defined method.
We can verify it by checking the local variables.
x = 1
p "At top level local_variables is : #{local_variables}"
define_method(:test) do
p "Local variable inside the method : #{local_variables}"
end
test
p "Back at the top level local_variables is : #{local_variables}"
This prints:
At top level local_variables is : [:x]
Local variable inside the method : [:x]
Back at the top level local_variables is : [:x]
The local variable defined at the top level is visible inside the dynamically defined method.
The Value of Self
Does the value of self change? Let's check:
x = 1
p "At top level self : #{self}"
define_method(:test) do
p "Inside top level method self : #{self}"
end
test
This prints:
At top level self : main
Inside top level method self : main
The value of self remains the same.
Inside the Top Level Method
x = 1
p "At top level x is : #{x}"
define_method(:test) do
x = 2
p "Inside the top level method x is : #{x}"
end
test
p "Back at the top level x is : #{x}"
This prints:
At top level x is : 1
Inside the top level method x is : 2
Back at the top level x is : 2
The scope did not change. Thus, the x at the top level and inside the method is the same.
At the Top Level
Inside a Class
Let's check if we can see the local variable declared at the top level from inside a dynamically defined class.
x = 1
p "At top level x : #{x}"
Car = Class.new do
p "Inside the Car class x : #{x}"
end
This prints:
At top level x : 1
Inside the Car class x : 1
The local variables defined at the top level is visible inside the Car class.
We can print the local variables to verify that the variable x is the same.
x = 1
p "At top level : #{local_variables}"
Car = Class.new do
p "Inside the Car class : #{local_variables}"
end
This prints:
At top level : [:x]
Inside the Car class : [:x]
Value of Self
Does the value of self change? Let's check:
x = 1
p "At top level, self : #{self}"
Car = Class.new do
p "Inside the Car class, self : #{self}"
end
This prints:
At top level, self : main
Inside the Car class, self : #<Class:0x007fff331c45f0>
The self changes from main to an instance of Class.
Variable with Same Name Inside a Class
What happens when you have a variable with the same name inside the class?
x = 1
p "At top level x : #{x}"
Car = Class.new do
x = 2
p "Inside the Car class x : #{x}"
end
p "Back at the top level : #{x}"
This prints:
At top level x : 1
Inside the Car class x : 2
Back at the top level : 2
This changes the value of the same local variable defined at the top level.
At the Top Level
Inside a Module
Let's check if we can see the local variable declared at the top level from inside a dynamically defined module.
x = 1
p "At top level x : #{x}"
Driveable = Module.new do
p "Inside the Driveable module x : #{x}"
end
This prints:
At top level x : 1
Inside the Driveable module x : 1
The local variables defined at the top level is visible inside the do-end block of creating a module.
We can print the local variables to verify it.
x = 1
p "At top level : #{local_variables}"
Driveable = Module.new do
p "Inside the Driveable module : #{local_variables}"
end
This prints:
At top level : [:x]
Inside the Driveable module : [:x]
Value of Self
Does the value of self change inside the do-end block? Let's check:
x = 1
p "At top level, self : #{self}"
Driveable = Module.new do
p "Inside the Driveable module, self : #{self}"
end
This prints:
At top level, self : main
Inside the Driveable module, self : #<Module:0x007f840>
The self changes from main to an instance of Module.
Variable with Same Name Inside a Module
What happens when you have a variable with the same name inside the do-end block of creating a Module?
x = 1
p "At the top level, x : #{x}"
Driveable = Module.new do
x = 2
p "Inside the Driveable module, x : #{x}"
end
p "Back at the top level, x : #{x}"
This prints:
At the top level, x : 1
Inside the Driveable module, x : 2
Back at the top level, x : 2
This changes value of the same local variable defined at the top level.
- The local variable defined at the top level is visible inside the dynamically defined method.
- The scope does not change. Thus, the x at the top level and inside the method is the same.
- The local variables defined at the top level is visible inside the do-end block of creating the Car class.
- The scope does not change. Thus, the x at the top level and inside the do-end block of creating a new instance of Class is the same.
- The self changes from main to an instance of the Class.
- The local variables defined at the top level is visible inside the do-end block of creating the Driveable module.
- The scope does not change. Thus, the x at the top level and inside the module is the same.
- The self changes from main to an instance of Module.
Here is a summary of what happens to self and scope when we use dynamic language constructs of Ruby.
Self | Scope | Where |
---|---|---|
No Change | No Change | Top Level and Top Level Method |
Changes | No Change | Top Level and Inside Class |
Changes | No Change | Top Level and Inside Module |
Summary
In this chapter, you learned that when we dynamically define a method, class or module, the scope does not change. The dynamic creation of a method does not change the value of self, it remains main. For dynamic creation of class and module, the self changes as summarized in the table.
Dynamic Construct | Self |
---|---|
Class.new | Instance of Class |
Module.new | Instance of Module |