Created
July 31, 2014 00:11
-
-
Save mtolly/594f0d08a0bf2e46c001 to your computer and use it in GitHub Desktop.
While hunting for bugs in http://opalrb.org/ I discovered this mind-boggling behavior in standard Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def x | |
2 | |
end | |
p x # prints 2 | |
x = 1 | |
p x # prints 1 | |
p x() # prints 2 | |
# The above is... annoying, but makes sense. Here's the real WTF though: | |
if false | |
y = 1 | |
else | |
def y | |
2 | |
end | |
end | |
p y | |
# prints... nil !!! | |
p z | |
# undefined local variable or method `z' for main:Object (NameError) | |
# What happened? | |
# Even though 'y = 1' was never evaluated, *it still declared variable y*. | |
# Ruby's grammar conflates local variables and methods, and so the parser | |
# maintains a list of which identifiers are the names of local variables. | |
# When it comes across a bare identifier expression, if it's in that list, | |
# it becomes a variable reference (which cannot fail -- it returns nil | |
# if the variable hasn't been assigned to). Otherwise it is a | |
# method call, and if there is no such method then a NameError is thrown. | |
# Problem is, the parser obviously can't tell whether an assignment | |
# statement inside an if branch is going to be taken at parse time. | |
# So it *assumes that they all will be taken*. | |
# On the bright side, Opal managed to replicate this bizarre behavior, | |
# so good on them :D |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment