What ||= does

Free preview 3 min to read

One operator, two characters doing real work

x = nil
x ||= 5
x
# 5

||= looks like its own syntax, but it combines two things from earlier courses: || (short-circuit OR) and = (assignment). x ||= 5 works like this:

x || (x = 5)

Ruby evaluates x first. If x is truthy, that's the value of the whole expression, and (x = 5) never runs. If x is falsy (nil or false), Ruby falls through to (x = 5), runs the assignment, and that becomes the value. So ||= doesn't mean "assign a default". It means "assign, but only if the left side didn't already give you something usable."

It works on a new variable

defined?(x)
# nil — x doesn't exist as a variable yet
x ||= 5
x
# 5
defined?(x)
# "local-variable" — it does now

This is worth checking, because it looks like it shouldn't work. How can x || (x = 5) read x on the left of || before x has ever been assigned? Ruby's parser settles this when it reads the code, not when it runs it. Seeing x = in a statement makes x a local variable for the whole statement, including the part before the =. Reading an untouched local variable like that gives nil, which is falsy, so the right side runs, x gets 5, and the variable now exists. There's no error and no special case in the code that writes x ||= 5; it's how the expansion and Ruby's variable rules fit together.

The same works on instance variables

class Foo
  def bar
    @bar ||= 10
  end
end

f = Foo.new
f.instance_variable_defined?(:@bar)
# false
f.bar
# 10
f.instance_variable_defined?(:@bar)
# true

Before bar is called, @bar doesn't exist on f at all, not even as nil, so instance_variable_defined? returns false. Calling f.bar runs @bar ||= 10. It reads @bar, which gives nil for an undefined instance variable, as for an undefined local, with no error. It finds it falsy and assigns 10. After that one call, @bar exists on f. This behavior on instance variables is what the rest of the course builds on.

Key takeaways

  • x ||= value works like x || (x = value): the assignment only runs when x is falsy (nil or false).
  • ||= works on a variable that was never assigned: the parser treats it as a local once it sees the =, and an untouched local reads as nil.
  • The same applies to instance variables: an undefined @ivar reads as nil, so @ivar ||= value assigns it the first time it's falsy.
  • ||= means "set this, but only if it isn't already truthy", which is narrower than "set a default".
Lesson 1 of 7 · free

Keep going with lesson 2

||= for default values

Uses of ||= in this app's partials and helpers that supply default values without caching anything on an object.

A free account also gives you the quizzes, your progress and notes, and the discussion.

Type to start searching...