What ||= does
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 ||= valueworks likex || (x = value): the assignment only runs whenxis falsy (nilorfalse).||=works on a variable that was never assigned: the parser treats it as a local once it sees the=, and an untouched local reads asnil.- The same applies to instance variables: an undefined
@ivarreads asnil, so@ivar ||= valueassigns 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".
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.