Object Scope and Self
Remember how we said that when Ruby finds a method call she then deviates from the normal control flow which goes from top to bottom? Instead she jumps into the method body.
We also said that this method body has its own scope, like a shiny, new room where local variables from other scopes are not visible. Instead it has its own local variables, some of which might be defined via the method’s arguments.
And we also said that inside any object’s method all instance variables of this object, and all other methods of this object are also visible.
We also may have a look at that mysterious top-level object that Ruby enters when she starts executing a program, or IRB.
We are now finally ready to put all these things together a little more, and
introduce a new keyword:
The Object Scope
In fact, 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 then both of these scopes are visible at the same time. For any given name Ruby will first check the local scope, and then the object scope.
In reality this most importantly means that from any method on an object, you can access:
- all local variables
- all instance variables
- all of the object’s methods
It also means that one can overwrite, sometimes accidentally, method names with variable names. Remember they read just the same in Ruby? While this is a really cool feature, it also means we need to be aware of it.
Consider this code:
class Person # ... def name @name end def greet(other) name = other.name puts "Hi " + name + "! My name is " + name + "." end end
As you can see this defines a new local variable
name. The code is very
similar to what we had before, except
that we store the
other person’s name to a local variable
and then use this variable on the next line when we put together our String.
This breaks our code, of course, in the sense that we don’t get the expected greeting any more. Instead it contains the same name twice:
Hi Carla! My name is Carla.
That is because, on the last line of the method
greet, when Ruby looks at the
name she first checks the local scope of the method, and
finds a local variable defined, so she uses it. Only if there was no local
variable defined she would check the object’s scope, and find the method with
the same name
name, and call it.
When she finds an identifier, Ruby looks for a local variable first, and then for a method.
Luckily, there’s a way to still access the object’s scope:
Every object knows itself, in every method, by the way of calling
This is a special keyword in Ruby, that means just that: The object itself.
Let’s try that, and output
self. In order 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
class Person def initialize(name) @name = name p self end end person = Person.new("Anja") p person
This should output something like this:
#<Person:0x007f9994972428 @name="Anja"> #<Person:0x007f9994972428 @name="Anja">
As you can see we output the same object twice. Once in the
p self, and once in the outer scope using
p person. You can also see
that the cryptic looking object id is the same for both instances. So we can
know it’s indeed the very same object.
Inside any method the object can be referred to using the keyword
So we can fix our code from above like this:
class Person def name @name end def greet(other) name = other.name puts "Hi " + name + "! My name is " + self.name + "." end end
Now we call the method
name on two different objects again. When Ruby sees
self she knows that we’re referring to the person object, and she calls the
name on it.
This fixes our greeting:
Hi Carla! My name is Anja.
Why do we keep saying that
self is a keyword? Well, because is not a method.
It’s a “special thing” in Ruby. For example this means that the following will
raise an error:
person = Person.new("Anja") p person.self
This raises the error:
NoMethodError: undefined method `self' for #<Person:0x007f9994972428 @name="Anja">
It’s not a method, it’s a special thing.
Other keywords that also aren’t methods (or objects, or classes) are, for
end. You’ll also learn about
else a little later.
Keywords are words that have a special meaning in Ruby, such as