Scopes
Let's learn about local variables and the scope of a variable.
We'll cover the following
Spheres of visibility
When we discussed variables, we mentioned that the most common type is the local variable. Now, we’ll explore these in detail.
Because we’ve discussed methods, we can look at another important concept: scopes.
According to Wikipedia, in programming, the scope of a name (such as a variable) is the part of a program where the name is valid: where the name can be used to refer to something else. (We’ve slightly modified this to match our own terminology.)
Remember: Names are known (defined) in a certain scope, and unknown (undefined) outside of this scope.
Every time there’s a method call, and the flow of execution enters the method’s body, it enters a new scope or room. Things local to this method’s scope (inside of the room) are only visible in this scope. Outside of it, they’re unknown.
Undefined local variable or method
This is also a good opportunity to talk about an error message that we might see often, especially when we make a typo and misspell a variable or method name.
Consider this code:
def add_two(number)number + 2endputs add_two(3)puts number
The line puts add_two(3)
outputs 5
, but puts number
will then raise an error.
This is because the number
variable assigned the number 3
when we call the method is a local variable. It’s local to the method’s scope and is created when the flow of execution enters the method.
Outside of this scope, when the flow of execution has returned from the method, the method’s scope is destroyed, and all local variables are gone. The local variable number
is therefore unknown, and Ruby raises an error, saying undefined local variable or method 'number'
.
We’ve skipped over the fact that in Ruby, both local variable names and method names are written the same way: they’re just plain words. For example, here:
number = 2puts number
The number
variable is the name of a method. It can be used (called) in the exact same way: puts number
.
def number2endputs number
number
is the name of a method. And it can be used (called) in the exact same
way: puts number
This is because Ruby evaluates one statement after another upon execution. When it encounters a plain word like number
, it first checks if it knows a local variable with the same name within the current scope… If so, it uses the value associated with this variable. If there’s no local variable with this name, then it looks for a method. If there’s also no method with this name, it then raises the error message undefined local variable or method 'number'
.
The error message is precise but also sounds convoluted. It indicates that it recognized the use of the word number
, but it doesn’t know it in this scope. It then asks if we meant to use a local variable or a method instead.
Let’s look at another scope example:
number = 1def add_to(number)number + 2endputs add_to(3)
If we run the code, we’ll see that it’s 5
.
The reason for that is that we assign the number 1
in the outer scope to a number
variable, but this variable is then never used. The only other line in the outer scope is the last line, puts add_to(3)
, and this line doesn’t use the number
variable.
Instead, when the control flow enters the add_to
method, Ruby creates a new local scope, and it defines a new local number
variable that’s assigned the number 3
that was passed to the method. This new number
variable is local to the method’s scope, and therefore, this is a different variable than the one on the very first line, in the outer scope.
A good metaphor for scopes
When Ruby enters a method, it’s like it enters a shiny new room in a house. With it, it brings the objects that are passed as arguments to the method call. In the example above, it brings a number 3
object.
Now, as soon as Ruby enters the method, it sticks Post-it notes on the objects (in reference to our earlier example) according to the argument list from the method definition. In our example, that’s the name number
. From now on, in this room, there’s a known local variable that has a value assigned. This is the object (number) 3
with the number
Post-it note on it.
In our example, the outer scope and the scope of the add_two
method are two different rooms, and there are two different Post-it notes stuck on two different numbers, which just happen to have the same name on them.