Robert G. wrote in post #1008764:
Javier 12 wrote in post #1008467:
But if you use “@other” in my example, “defined?(@other)” will return
nil, and not “instance-variable”, while “defined?(other)” returns
“local-variable”.
Why?
You’ve got a good point.
The behavior is confusing and inconsistent with other variables.
But absolutely essential, because this is how ruby solves the local
variable / method call ambiguity.
By this I mean: because ruby doesn’t require parentheses on a method
call, a bare word like “foo” could either be a method call with no
arguments, or a local variable access.
puts foo
^
what's this?
The distinction is made at parse time. If, when the syntax tree is being
built, there’s an expression of the form “foo = xxx” earlier in this
scope, then from that point onwards a bareword “foo” is considered a
local variable. Its slot on the stack frame is initialised to nil.
If necessary, you can force it the other way: self.foo or foo() are both
method calls, even if there is a foo local variable in this scope.
If this were not done at parse time, even a simple statement like
a = a + 1
would be horrendously expensive to execute. You would have to test
whether the ‘a’ on the right-hand side existed as a local variable at
that instant, and if not, try to call a() instead.
So the upshot is:
def foo
“Function”
end
def bar
“Another function”
end
if false
foo = 123
end
puts foo # nil
puts foo() # “Function”
puts self.foo # “Function”
puts bar # “Another function”
bar = 456
puts bar # 456
puts baz # undefined local variable or method baz' puts baz() # undefined method
baz’
Note the error message in the penultimate line. The error might be that
you forgot to assign to variable baz earlier in the method, or you
forgot to define a method baz(). Ruby doesn’t know which you intended.