Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange meaning of || and ||= in Ruby (2.0, 1.9.3, jruby 1.7.4)

Tags:

ruby

jruby

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
like image 308
door_number_three Avatar asked Oct 25 '13 16:10

door_number_three


1 Answers

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.

like image 129
sawa Avatar answered Sep 21 '22 16:09

sawa