Understanding the “NameError: undefined local variable or method” Error Message

Olúwaségun Adéléye
3 min readApr 27, 2019

--

Photo by Bruce Mars on Unsplash

During my days as a Junior Developer when I just started learning Ruby, I never paid attention to the structure of this error message until I was asked a question during one of my review sessions with my trainer. She asked what the error message means and what it has to do with how Ruby does local variable and method lookup. This article answers the question.

In Ruby, before you reference a local variable, you are expected to define it. The way you define a local variable is by assignment.

a = 1
puts a
=> 1

However, if you reference an undefined local variable, Ruby complains.

At the top-level (file or REPL);

> puts b
NameError: undefined local variable or method `b' for main:Object

And within an instance method;

class Cat  def speak
puts sound
end
end> Cat.new.speak
NameError: undefined local variable or method `sound' for #<Cat:0x007fc0a113f358>

If you take a good look at the error messages, you will see that local variables b and sound were also looked up as methods.

Now that’s interesting. The intention was to reference a local variable, but Ruby also checks if the variable is available as methods. This has to do with how Ruby performs a variable lookup.

Every time you reference a local variable, Ruby first checks if it was defined. If it’s not, it looks up the reference as a method on self within the current context.

What is self?

In Ruby, self is a special variable that points to the current object. The value of self changes based on the current context of execution.

You can read more about it here.

Like the examples above, at the top-level, Ruby checks if the method b is available on the current object main. And within an instance method, it checks if the method sound is available on the current object #<Cat:0x007fc0a113f358> which is the instance of the Cat class.

This is why it is possible to call a method on the current object within a specific context without explicitly calling it on self

class Cat  def speak
puts sound
end
def sound
'Meow'
end
end> Cat.new.speak
=> Meow

Note that self.sound would also give the same result. The main difference is that Ruby will not look it up as a local variable. This can also be seen in the error message.

> puts self.b
NoMethodError: undefined method `b' for main:Object

A NoMethodError is raised this time around

class Cat  def speak
puts self.sound
end
end> Cat.new.speak
NoMethodError: undefined method `sound' for #<Class:0x007ffd88025110>

Conclusion

The way Ruby does variable lookup is what makes it possible to implicitly call a method on the current object. It saves you from littering your code base with self., thus keeping it clean and beautiful.

Ruby is a very interesting language. A lot of people who come from other programming languages find a lot of things strange about it. But as you begin to dig deeper into it, you’d come to love and appreciate it.

--

--

Olúwaségun Adéléye

Software Architecture. So much love for Ruby, JavaScript, Rails, and Node.js. Building the habit of reading and writing.