Different variables behave differently in Ruby, but none of them need explicit declaration.
The most interesting behavior is for local variables: Ruby allows you to leave off the receiver for a message send to self
(self
is the implicit receiver), so foo()
is the same thing as self.foo()
, and it also allows you to leave off the argument list if there are no arguments, so foo.bar
is the same thing as foo.bar()
; putting the two together, we get that foo
is the same thing as self.foo()
, i.e. a message send without arguments to the implicit receiver self
. It could, however, also be a reference to the local variable foo
. This ambiguity is resolved the following way: foo
is interpreted as a message send, unless an assignment to foo
has been parsed (but not necessarily executed) before, then from that point on it is interpreted as a local variable.
This is the closest thing Ruby has to variable declaration:
foo
# NameError: undefined local variable or method `foo'
defined?(foo)
# => nil
def foo; 23 end
foo
# => 23
defined?(foo)
# => 'method'
methods
# => [:foo, …]
if false then foo = 42 end
foo
# => nil
defined?(foo)
# => 'local-variable'
local_variables
# => [:foo]
Note that the NameError
is not raised because the local variable is undefined, but because Ruby doesn't know what to make of the expression: is it a local variable or a method call?
Instance variables and global variables behave similarly, they evaluate to nil
even if they are not defined:
@foo
# => nil
defined?(@foo)
# => nil
@foo = 42
@foo
# => 42
defined?(@foo)
# => 'instance-variable'
instance_variables
# => [:@foo]
$foo
# => nil
defined?($foo)
# => nil
$foo = 42
$foo
# => 42
defined?($foo)
# => 'global-variable'
global_variables
# => [:$foo, …]
Class hierarchy variables and constants behave differently, they raise NameError
if they are not defined:
@@foo
# NameError
defined?(@@foo)
# => nil
@@foo = 42
@@foo
# => 42
defined?(@@foo)
# => 'class-variable'
self.class.class_variables
# => [:@@foo]
FOO
# NameError
defined?(FOO)
# => nil
FOO = 42
FOO
# => 42
defined?(FOO)
# => 'constant'
self.class.constants
# => [:FOO]
NameError
if they are not defined, instance variables and global variables evaluate tonil
, and local variables also evaluate tonil
but need to be disambiguated from a method call by being lexically defined first, otherwise they will raise aNameError
but for being ambiguous, not undefined. – Jörg W Mittag Jan 12 '15 at 23:17