It’s a ruby quirk to allow local variables and method calls without parens to co-exist. At parse time if ruby sees any assignments that look like a local variable it creates a local var initialized to nil. That’s why if false; foo = ‘hi’; end will create a ‘foo’ local variable but set it to nil since the inside of the if false is never executed.
Trippy. I imagine you may have already come across Monday’s “Ruby’s not ready” article. The conclusions are a bit off (not ready for what?) but there is a fair amount of truth to Ruby’s quirkiness, as your wtf post further confirms.
http://glyphobet.net/blog/essay/228
Another explanation: http://blog.caboo.se/articles/2006/03/08/your-ruby-gotcha-of-the-day
ste11 Apr 03:38
I thought that every Ruby programmer knew about this trick :-)
Javascript doesn’t have it, so you are forced to pre-assign every variable which only gets assigned inside a block that might not be executed (as in your example). I see this as a clear application of the PolS: you are using “var” in your code, so why should you check if it is defined or not?
By the way, this behavior is clearly documented in the Pickaxe book (p. 314 on the beta 3d edition).
Why do people consider this a quirk? I use this behavior very often….
def do_something(param)
if param == :a
result = 1
elsif param == :b
result = 2
end
complex_thing_that_i_dont_want_to_dup(result, "x", "y", "z") if result
end
Consider the alternatives:
def do_something(param)
if param == :a || param == :b
if param == :a
result = 1
else
result = 2
end
complex_thing_that_i_dont_want_to_dup(result, "x", "y", "z")
end
end
or even [uglier?]
def do_something(param)
if param == :a
complex_thing_that_i_dont_want_to_dup(1, "x", "y", "z")
elsif param == :b
complex_thing_that_i_dont_want_to_dup(2, "x", "y", "z")
end
end
Emmanuel: that’s not really what i meant. The problem is that ruby insert’s an invisible var = nil into the method above it. If you have a method called var for example it will be overshadowed after you assign var = something in the blog. Even if the var = something is never executed.
Dr Nic 10 Apr 21:46
I guess its a scope issue; you created local var variable inside the if statement.
For example:
tobi 10 Apr 21:52
Well ok but why is the variable in existence?
Dr Nic 10 Apr 22:00
Ooh nice one.
Ezra 10 Apr 22:24
It’s a ruby quirk to allow local variables and method calls without parens to co-exist. At parse time if ruby sees any assignments that look like a local variable it creates a local var initialized to nil. That’s why if false; foo = ‘hi’; end will create a ‘foo’ local variable but set it to nil since the inside of the if false is never executed.
Pete Forde 10 Apr 22:42
This one almost had me, but setting var = nil was just a red herring.
Nathan Youngman 10 Apr 22:46
Trippy. I imagine you may have already come across Monday’s “Ruby’s not ready” article. The conclusions are a bit off (not ready for what?) but there is a fair amount of truth to Ruby’s quirkiness, as your wtf post further confirms. http://glyphobet.net/blog/essay/228
Dave Hoover 11 Apr 00:10
Ruby has variable scoping… http://redsquirrel.com/cgi-bin/dave/dynamic/variable.scoping.html
Phil 11 Apr 02:21
Another explanation: http://blog.caboo.se/articles/2006/03/08/your-ruby-gotcha-of-the-day
ste 11 Apr 03:38
I thought that every Ruby programmer knew about this trick :-) Javascript doesn’t have it, so you are forced to pre-assign every variable which only gets assigned inside a block that might not be executed (as in your example). I see this as a clear application of the PolS: you are using “var” in your code, so why should you check if it is defined or not? By the way, this behavior is clearly documented in the Pickaxe book (p. 314 on the beta 3d edition).
Dr Nic 11 Apr 07:06
@ezra – sweet, thx for the explanation.
Emmanuel Oga 11 Apr 12:53
Why do people consider this a quirk? I use this behavior very often….
def do_something(param) if param == :a result = 1 elsif param == :b result = 2 end complex_thing_that_i_dont_want_to_dup(result, "x", "y", "z") if result endConsider the alternatives:
def do_something(param) if param == :a || param == :b if param == :a result = 1 else result = 2 end complex_thing_that_i_dont_want_to_dup(result, "x", "y", "z") end endor even [uglier?]
def do_something(param) if param == :a complex_thing_that_i_dont_want_to_dup(1, "x", "y", "z") elsif param == :b complex_thing_that_i_dont_want_to_dup(2, "x", "y", "z") end endI rather the first form, using the ruby “quirk”.
tobias Lütke 11 Apr 18:06
Emmanuel: that’s not really what i meant. The problem is that ruby insert’s an invisible var = nil into the method above it. If you have a method called var for example it will be overshadowed after you assign var = something in the blog. Even if the var = something is never executed.