LaunchKit
All quizzes
Ruby 27 views

&& binds tighter than ||

Question

What's the return value of the following Ruby 3 code?

x = nil
y = "Ruby"

x || y && "Rails" # => ???

The correct answer is

Explanation

TL;DR

&& has higher precedence than ||, so the expression parses as x || (y && "Rails"). x is nil, so || moves on to its right operand. y is truthy, so y && "Rails" returns "Rails", and that is the value of the whole expression.

Step by step

x = nil
y = "Ruby"

x || y && "Rails"   # => "Rails"
x || (y && "Rails") # => "Rails"  (same parse, made explicit)
(x || y) && "Rails" # => "Rails"  (different parse, same result here)
  1. Ruby parses the expression as x || (y && "Rails") because && binds tighter than ||.
  2. || evaluates its left operand first: x is nil, which is falsy, so the result comes from the right operand.
  3. y && "Rails": y is "Ruby", truthy, so && evaluates and returns its second operand, "Rails".

Note that || and && return operands, not booleans. a || b returns a if a is truthy, otherwise b; a && b returns a if a is falsy, otherwise b. That is what makes idioms like name = input || "default" work.

The left-to-right misreading, (x || y) && "Rails", happens to give "Rails" here too, which makes this trap easy to miss. Change the data and the parses diverge:

x = "Ruby"

x || nil && "Rails"   # => "Ruby"   (nil && "Rails" is never evaluated)
(x || nil) && "Rails" # => "Rails"

Edge cases

The word forms and and or have much lower precedence than &&, ||, and even assignment. Mixing them with = is a classic bug:

a = false || "value"
a # => "value"

b = false or "value"  # parses as (b = false) or "value"
b # => false

Reserve and/or for control flow (do_thing or raise "failed") and use &&/|| inside expressions.

Share this quiz

Comments

No comments yet. Be the first.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.