I was trying to read some Rails code today and came across the definition of the link_to view helper, which looks like this:
At first glance, I thought for sure I had found a bug! The variable, href, is only initialized if html_options is specified. It seems like the “href_attr = … unless href” line would blow up otherwise, since it’s testing a variable that may not have been set. Or, so I thought. It turns out that my understanding of Ruby’s local variable semantics was wrong, as demonstrated by this simple test:
irb(main):001:0> x NameError: undefined local variable or method 'x' for main:Object from (irb):1 from :0 irb(main):002:0> if false irb(main):003:1> x = 0 irb(main):004:1> end => nil irb(main):005:0> x => nil
It seems that assigning to an uninitialized variable in code that does not execute is sufficient to create that variable and assign it a default value of nil. This is in contrast to Python, which doesn’t define new variables unless the code that sets them actually executes:
>>> x Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'x' is not defined >>> if False: ... x = 0 ... >>> x Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'x' is not defined
js> x typein:1: ReferenceError: x is not defined js> if (false) x = 0; js> x typein:3: ReferenceError: x is not defined
Is it just me, or is Ruby’s behavior completely bizarre here?