Does the || operator evaluate the second argument even if the first argument is true?
Asked Answered
D

4

10

I'm trying to evaluate the expression (a=10) || (rr=20) while the rr variable is not defined

so typing rr in the ruby console before evaluating the previous expression returns

rr
NameError: undefined local variable or method `rr' for main:Object
from (irb):1
from :0

When I write the expression (a=10) || (rr=20) it returns 10, and when I write rr afterwards it says nil

(a=10) || (rr=20)
rr  # => nil

so, why is this happening? Shouldn't rr be defined only if the second argument of the || operator is evaluated, which should be never based on the documentation?

Disused answered 6/2, 2012 at 17:0 Comment(2)
There is a difference between short-circuited conditional operations (not evaluating the second condition if the first is false) and not declaring a variable. Your problem relates to the second problem.Asparagine
Knowing when a local variable is in your scope is tricky in Ruby. Try running a+1 if a = 5. You might expect that it will set a to 5 and then return 6, but actually it will set a and THEN complain about a being undefined.Sarraceniaceous
P
12

This happens because the ruby interpreter defines a variable when it sees an assignment to it (but before it executes the actual line of code). You can read more about it in this answer.

Boolean OR (||) expression will evaluate to the value of left hand expression if it is not nil and not false, else || will evaluate to the value of right hand expression.

In your example the ruby interpreter sees an assignment to a and rr (but it doesn't execute this line yet), and initializes (defines, creates) a and rr with nil. Then it executes the || expression. In this || expression, a is assigned to 10 and 10 is returned. r=20 is not evaluated, and rr is not changed (it is still nil). This is why in the next line rr is nil.

Posterior answered 6/2, 2012 at 17:4 Comment(2)
The variable is not initialized, it is just defined. That's why it evaluates to nil: because uninitialized variables evaluate to nil in Ruby. If it were initialized, it would evaluate to 20, not nil.Eventual
@JörgWMittag, tnx for correct wording. initialized in my answer really should be definedPosterior
H
5

As @DOC said, && and || are known as short circuited conditional operators.

In case of ||, if the left part of || expression returns true, the right part won't be executed. That means the right part will be executed only if the left part of || expression returns false.

In case of &&, right part of the&&expression will be executed only if left part of && returns true.

In the given scenario (a=10) || (rr=20), rr=20 won't be executed since the ruby expression a=10 returns true. Note that in ruby assignment expression returns true except nil and false.

Hymenopterous answered 6/2, 2012 at 17:38 Comment(0)
D
3

I think variable definement happens at the parsing stage, not the execution moment. So when it evaluates the line, it parses the whole thing and the variable is defined, but unassigned.

Dogmatist answered 6/2, 2012 at 17:3 Comment(1)
Exactly. This is the right answer. The variable is defined, because variables are defined when there is an assignment in the code. But it is not initialized or assigned, because the assignment never gets executed. Therefore, it evaluates to nil because that's what uninitialized variables evaluate to in Ruby.Eventual
M
2

When the parser discovers a variable it is automatically valid within the context it's defined in. Evaluating rr on its own is not valid. Evaluating rr=20 is sufficient to cause a definition even if the value assignment never occurs.

This is a quirk of how Ruby tries to discern between variables and method calls. It's imperfect but usually works out for the best.

Maxantia answered 6/2, 2012 at 17:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.