In Ruby, how do you set a variable to a certain value if it is not already defined, and leave the current value if it is already defined?
4 Answers
While x ||= value
is a way to say "if x contains a falsey value, including nil (which is implicit in this construct if x is not defined because it appears on the left hand side of the assignment), assign value to x", it does just that.
It is roughly equivalent to the following. (However, x ||= value
will not throw a NameError
like this code may and it will always assign a value to x
as this code does not -- the point is to see x ||= value
works the same for any falsey value in x, including the "default" nil
value):
if !x
x = value
end
To see if the variable has truly not been assigned a value, use the defined?
method:
>> defined? z
=> nil
>> z = nil
=> nil
>> defined? z
=> "local-variable"
>> defined? @z
=> nil
>> @z = nil
=> nil
>> defined? @z
=> "instance-variable"
However, in almost every case, using defined?
is code smell. Be careful with power. Do the sensible thing: give variables values before trying to use them :)
Happy coding.
-
What is it about `||=` that makes it not throw a `NameError` if the variable is not defined? Is that built into the operator? Are there other operators that work that way? – jrdioko Jul 12 '11 at 21:54
-
2@jrdioko "Magic" ;) Actually, it has to do with `x` appearing on the Left Hand Side of the assignment -- it doesn't matter if a value has not been assigned yet (it will "default" to `nil`). For instance, `z = z.nil? # => true` even when `z` was not currently defined. – Jul 12 '11 at 21:57
-
@pst I guess the "defined?" method is just a more elegant alternative than fishing out the "NameError: undefined local variable or method" So the real answer is that you will know if you haven't already defined a variable when your program errors out. – Dmitri Jul 12 '11 at 22:03
-
yeah, this is much better if you are setting variables as true/false – thenengah Jul 12 '11 at 22:06
-
@Dmitri @Codeglot Indeed. The most elegant way is to write code *that can't cause* a `NameError`! (and verified as such with good test coverage) ;-) – Jul 12 '11 at 22:07
-
Why is using `defined?` code smell? Could you please explain that part. – Hengjie Jan 25 '13 at 09:59
-
@Hengjie Because there should be no question of *if* a `variable` has been set (which implies `defined?` is truthy) in code. Of course, there are exceptions (with `@variable`, perhaps?) .. but if you're at such a special scenario then you'll know it, and why it's okay. If you don't know why it's okay, then it's not :) – Jan 25 '13 at 16:46
-
@Hengjie That is, just like `eval`, `defined?` is "usually not the right tool": when it appears the usage must be questioned. If the particular usage cannot be suitably defended then it should be removed. – Jan 25 '13 at 16:53
-
Code smell? More like removing code fragility, just because **you** don't think a situation couldn't occur doesn't mean that it could never happen. Future development may somehow accidentally make this variable undefined (mistaken spelling in the declaration, for example). Checking if a variable is defined will catch such a bug, and make it easy to find. However, without the check, the problem might not be as quick to solve. – SSH This May 10 '13 at 21:50
@variable ||= "set value if not set"
So false
variables will get overridden
> @test = true
=> true
> @test ||= "test"
=> true
> @test
=> nil
> @test ||= "test"
=> "test"
> @test = false
=> false
> @test ||= "test"
=> "test"

- 42,557
- 33
- 113
- 157
-
4It could be set to a falsey-value, however. As such, this is only approximately correct. – Jul 12 '11 at 21:42
-
-
-
TIL: This does not work with hash values like `bodyParams['owner'] ||= ''` if there is no key called `'owner'`. It will give you an `IndexError`. For that, check here https://stackoverflow.com/a/39549523/1025430 – Chris Feb 14 '22 at 12:11
As you didn't specify what kind of variable:
v = v
v ||= 1
Don't recommend doing this with local variables though.
Edit: In fact v=v is not needed

- 9,167
- 1
- 19
- 23
-
1It could be set to a falsey-value, however. As such, this is only approximately correct. – Jul 12 '11 at 21:43
-
irb(main):007:0> v = v => nil // irb(main):008:0> v.class => NilClass // so same as initializing it as v = nil – Dmitri Jul 12 '11 at 21:48
-
1@Dmitri No, it is not the same, if v has a value, it won't change. That is the point. – Victor Moroz Jul 13 '11 at 01:11
If the variable is not defined (declared?) it doesn't exist, and if it is declared then you know how you initialized it, right?
Usually, if I just need a variable whose use I don't yet know---that I know will never use as a Boolean---I initialize it by setting its value to nil. Then you can test if it has been changed later quite easily
x = nil
some code
if x do
[code that will only run if x has changed]
end
that's all.

- 2,658
- 2
- 25
- 41
-
It could be set to a falsey-value, however. As such, this is only approximately correct. – Jul 12 '11 at 21:43
-
that is quite true, @pst I don't use this technique if the expected value is a Boolean. – Dmitri Jul 12 '11 at 21:46