Consider the following irb snippet from a freshly-started session:
irb:01> baz # => NameError, baz is not defined
irb:02> baz || baz = 0 # => NameError, baz is not defined
irb:03> baz # => nil
baz
was an undefined variable and trying to evaluate it produced a NameError
. Yet, somehow, after this operation, baz
was defined, and has a value of nil
. Seemingly, the value nil
was assigned to the variable baz
even though no one (explicitly) asked for it to be. Is there an underlying language reason why this behavior is desirable?
What is the rule that explains this behavior and other similarly confusing constructs, such as these:
irb:04> true if foo # => NameError
irb:05> foo # => NameError; name still undefined
irb:06> foo = (true if foo) # => nil
irb:07> foo # => nil; name defined as nil
irb:08> true || i = 0 || j = 2 # => i and j are nil; || appears nonlazy
irb:09> raise || quux = 1 # => RuntimeError, quux is nil
I don't know if it is desirable, but it comes from how Ruby parses the code. Whenever you have a piece of code that assigns a local variable, that local variable is assigned nil
even if that piece of code is not evaluated. In your code line 2:
baz || baz = 0
the first baz
returned an error because no such variable was assigned. Hence the assignment baz = 0
that follows it was not evaluated, but nevertheless it was parsed, so in the context to follow, a local variable baz
was created, and is initialized to nil
.
With your second code chunk, foo
is not assigned during true if foo
and foo
. After that, foo = (true if foo)
has an assignment to foo
, so even though (true if foo)
is evaluated before assigment of foo
, an error is not raised in that line.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With