Peter V. wrote in post #977488:
To understand this better, I used the method ‘defined?’.
Would ‘defined?’ be a correct way to determine if a name was
already ‘initialized as a local variable’ in this case?
$ rvm use 1.9.2 # (same behavior in 1.8.7)
Using /home/peterv/.rvm/gems/ruby-1.9.2-p136
$ irb
001:0> defined?(x) #=> nil
002:0> if false
003:1> x = 10
004:1> end #=> nil
005:0> defined?(x) #=> “local-variable”
006:0> x #=> nil
Yes, but you should rarely if ever need this in practice.
Ruby is in general a highly dynamic language, but one thing which is
static is the decision as to whether a bare name is a local variable or
a method call. This is done at parse time, before code is even
executed (whereas definition of classes and methods are done at run
time, by executing the code containing ‘class’ and ‘def’ statements)
Hence even if you dynamically create a local variable using ‘eval’, a
subsequent non-eval reference to that variable won’t pick it up. Run the
following as a .rb script (not in irb):
def x
“yay”
end
eval “x=1”
puts x # yay
puts defined?(x) # method
puts eval(“x”) # 1
You can see that x was chosen to be a method call, because no assignment
to x was seen previously (the eval isn’t executed until runtime). This
is even clearer if you use something like ParseTree to show the parsed
code.
You can, however, force a bare name to be a method call instead of a
local variable - again, decided at parse time:
def x
“yay”
end
x = 1
puts x # 1
puts x() # yay
puts self.x # private method ‘x’ called
puts y # undefined local variable or method ‘y’
puts y() # undefined method ‘y’
I think the reasons for this approach are:
-
Language design - you don’t need to declare variables, and you don’t
need to use () after every method call
-
Decidability - you can tell just by scanning source code whether ‘x’
is a local variable or a method call. (You only need to scan from the
previous ‘def’ or ‘class’ statement, since these start a new scope)
-
Efficiency - you don’t want to have to search at run time to
determine whether ‘x’ is a local variable or a method call at that point
in the code every time it executes