Scopes

Let's learn about local variables and the scope of a variable.

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:

Press + to interact
def add_two(number)
number + 2
end
puts 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:

Press + to interact
number = 2
puts number

The number variable is the name of a method. It can be used (called) in the exact same way: puts number.

Press + to interact
def number
2
end
puts 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:

Press + to interact
number = 1
def add_to(number)
number + 2
end
puts 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.