Travis Travis - 7 months ago 15
Ruby Question

Undefined local variable coerced to nil when being passed as argument and assigned to return value

I mistakenly wrote a method that assigned a variable to the return value of a method that was passed the same variable that I was trying to assign, and it returned some unexpected behavior and I'm curious to know if this is a bug in Ruby, or actually intended behavior?

RUBY_VERSION
#=> "2.2.4"

def red(arg)
arg
end

# this is expected since blue is not defined
blue
NameError: undefined local variable or method 'blue' for main:Object
from (pry):8:in '__pry__'

red(blue)
NameError: undefined local variable or method 'blue' for main:Object
from (pry):4:in '__pry__'

# here's the weird part
blue = red(blue)
#=> nil

def green(arg)
'green'
end

yellow
NameError: undefined local variable or method 'yellow' for main:Object
from (pry):13:in '__pry__'

yellow = green(yellow)
#=> "green"

Answer

From "The Ruby Programming Language" by David Flanagan:

Ruby treats an identifier as a local variable if it has seen any previous assignment to the variable. It does this even if that assignment was never executed.

This means that variables are implicitly declared by the Ruby parser, even before any code gets executed. As soon as ruby sees the = operator, it immediately makes a new variable called yellow with a default value of nil. Then when that statement is executed, every reference to that variable share it's default value.

The book goes on to show an example of similar, perhaps surprising, behavior of variable declaration in ruby that is similar to this:

>> x               # NameError: undefined local variable or method `x'
>> x = 0 if false  # parsed, but never executed
>> p x             # displays nil

The significance of this code is that is shows that variables are declared as soon as code is parsed, and since your two references to yellow happen on the same line, the assignment of yellow must be parsed, and therefore declared, before it's passed as an argument to green

Comments