Skip to content

Instantly share code, notes, and snippets.

@mtolly
Created July 31, 2014 00:11
Show Gist options
  • Save mtolly/594f0d08a0bf2e46c001 to your computer and use it in GitHub Desktop.
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
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