Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Ruby, for an undefined variable "foo", why doesn't "foo = foo" raise an error?

Tags:

ruby

When foo is an undefined variable, attempting to access it raises a NameError:

foo
#=> NameError: undefined local variable or method `foo'

a = foo
#=> NameError: undefined local variable or method `foo'

Why doesn't foo = foo raise a NameError?

foo = foo
#=> nil

Yesterday, it took me hours to track down this line as the bug in a program...

capture = capture.to_i

What I had intended to do was convert capture_str to an Integer. What I had done instead was introduce a nil by saying capture = capture, and then turning that nil into a 0. So I was doing this...

capture = capture.to_i
#=> 0

But I had been incorrectly assuming that a variable NameError would have been thrown, like this...

capture = capture_str.to_i
#=> NameError: undefined local variable or method `capture_str'
like image 209
popedotninja Avatar asked Jul 10 '19 13:07

popedotninja


1 Answers

Ruby has this weird feature that it hoists variables when they're declared:

This means that when the parser sees x=1, it will actually declare the variable, by assigning it to nil and let the interpreter then figure out if the x = 1 line will ever get executed.

source

So when you write

a = a.to_i

it first declare a = nil then calls to_i on it and the assigns:

a = nil
a = a.to_i

EDIT:

It also works like that in other cases, e.g. with if:

pry> b
NameError: undefined local variable or method `b' for main:Object
from (pry):30:in `__pry__'
pry> b if b.nil?
NameError: undefined local variable or method `b' for main:Object
from (pry):31:in `__pry__'
pry> b = 1 if b.nil?
#=> 1
pry> b
#=> 1

and (example from the linked blogpost):

if false
  x = 1
end
puts x.class
# NilClass
like image 185
mrzasa Avatar answered Nov 14 '22 19:11

mrzasa