Object Scope and Self
Learn about the scope of an object, the scope of an instance method, and the self keyword.
We'll cover the following
Remember that when Ruby finds a method call, it deviates from the normal control flow which goes from top to bottom. Instead, it jumps into the method body.
We also learned that this method body has its own scope, like a shiny new room where local variables from other scopes are invisible. Instead, it has its own local variables, some of which might be defined through the method’s arguments.
We also learned that all instance variables inside an object and all its other methods are also visible.
Later, we’ll look at that mysterious top-level object that Ruby enters when it starts executing a program.
We’re now finally ready to put all these things together and introduce a new keyword: self
.
The object scope
In Ruby, there are even more scopes than just the local method’s scope. There’s the method’s local scope, which holds all local variables, and there’s the object’s scope, which holds all instance variables and method names.
When Ruby’s control flow jumps into a method, both scopes are visible at the same time. For any given name, Ruby first checks the local scope and then the object scope.
Most importantly, this means that we can access the following from any method in an object:
- All local variables
- All instance variables
- All of the object’s methods
It also means that we can overwrite method names with variable names, sometimes accidentally. Remember that they read just the same in Ruby. While this is a cool feature, we need to be wary of it.
Consider this code:
class Persondef initialize(name)@name = nameenddef name@nameenddef greet(other)name = other.nameputs "Hi " + name + "! My name is " + name + "."endendperson = Person.new("Anja")friend = Person.new("Carla")person.greet(friend)
Notice that this defines a new local variable, name
. The code is very similar to what we saw in the last lesson, except that in line 11, we store the other
person’s name to a local name
variable first and then use this variable on the next line when we put our string together.
This breaks our code in the sense that we don’t get the expected greeting anymore. Instead, it contains the same name twice:
Hi Carla! My name is Carla.
That’s because, in line 12 of the greet
method, when Ruby looks at the word (identifier) name
, it first checks the local scope of the method and finds a local variable defined, so it uses it. It would only check the object’s scope and find the method with the same name
and call it if there were no local variable defined.
Remember: When it finds an identifier, Ruby looks for a local variable first and then for a method.
Luckily, there’s still a way to access the object’s scope.
The self
keyword
Every object knows itself, in every method, by way of calling self
. This is a special keyword in Ruby, which means the object itself.
Let’s try that, and output self
. To do that, we need to add it somewhere inside the object. Any method would be good for that, but let’s just use the initialize
method:
class Persondef initialize(name)@name = namep selfendendperson = Person.new("Anja")p person
As we can see, we output the same object twice. Once in the initialize
method using p self
, and once in the outer scope using p person
. We can also see that the cryptic-looking object ID is the same for both instances. So, we know it’s the same object.
Remember: The object can be referred to using the keyword
self
inside any method.
So, we can fix our code from above like this:
class Persondef initialize(name)@name = nameenddef name@nameenddef greet(other)name = other.nameputs "Hi " + name + "! My name is " + self.name + "."endend
Now, we call the name
method on two different objects again. When Ruby sees self
, it knows that we’re referring to the person
object, and it calls the name
method on it.
This fixes our greeting:
Hi Carla! My name is Anja.
Keywords
Why do we keep saying that self
is a keyword? That’s because it’s not a method. It’s a special thing in Ruby. For example, this means that the following raises an error:
class Persondef initialize(name)@name = namep selfendendperson = Person.new("Anja")p person.self
It’s not a method, it’s a special thing.
Other keywords that also aren’t methods (or objects, or classes) are, for
example, def
, class
, and end
.
Remember: Keywords are words that have a special meaning in Ruby, such as
class
,def
,end
, andself
.