What does the "||=" operand stand for in ruby [duplicate] - ruby

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
What does ||= mean in Ruby?
I tested like this:
>> a||=3
=> 3
>> a
=> 3
>> a||=b
=> 3
>> b
NameError: undefined local variable or method `b' for main:Object
from (irb):11

It is the shorthand for a logical OR operation. It is equivalent to:
a || a = b
Note: The above code sample has been corrected to reflect the true (if unintuitive) behavior if expanding a ||= b. Thanks to the people who pointed that out for me. Here is the source
if a evaluates to true it will remain as is, otherwise b will be assigned to a. In ruby nil evaluates to false, so you can see how this is useful for lazy loading and default value assignment.

Related

Why reference to variable inside not run if body does not raise NoMethodError? [duplicate]

This question already has answers here:
Why can I refer to a variable outside of an if/unless/case statement that never ran?
(3 answers)
Closed 2 years ago.
Hi I got a variable inside an if block that the condition of if is false.
if false
a = 1
end
a => nil
However the a does not raise an NoMethodError instead returns nil?
Why a = 1 Isn't Evaluated
Your code is logically equivalent to both of the following:
a = 1 if false; a
false.eql?(true) && a=(1)
In all three cases, since false is not true, variable a is never assigned. However, the reason it's nil rather than raising NameError is a little non-intuitive.
Why Unassigned Variables Return nil Instead of Raising NameError
In Ruby, non-constant variables are defined when encountered by the parser, rather then when executed by the code path. If the parser encounters a non-constant variable that is not an assignment, it creates the variable and assigns nil to it.
You can still expect to see NameError when the interpreter uses an unassigned variable. For example, in a fresh irb session:
# variable not in scope
puts a
#=> NameError (undefined local variable or method `a' for main:Object)
# variable auto-vivified by parser
a = 1 if false; a
#=> nil
a = 1; a
#=> 1
Related
Why are constants not initialized like local variables when the file is parsed by Ruby?
The Ruby parser keeps track of which names are local variables (vs method calls). Ruby parser doesn’t know if the conditionals will be true/false, so it already got an reference to a.

How does Ruby handle variable assignment in dead code? [duplicate]

This question already has answers here:
Why can I refer to a variable outside of an if/unless/case statement that never ran?
(3 answers)
Closed 5 years ago.
We define a function foo:
def foo(s)
case s
when'foo'
x = 3
puts x.inspect
when 'bar'
y = 4
puts y.inspect
end
puts x.inspect
puts y.inspect
end
We then call it as follows:
1.9.3p194 :017 > foo('foo')
in foo scope
3
in outer scope
3
nil
=> nil
1.9.3p194 :018 > foo('bar')
in bar scope
3
in outer scope
nil
3
=> nil
Why does the function not throw an error about an unregistered local variable in either case? In the first case, the variable y seems like it should not exist, so you can't call inspect on it in the outer scope; the same for x in the second case.
Here's another similar example:
def test1
x = 5 if false
puts x.inspect
end
def test2
puts x.inspect
end
And then:
1.9.3p194 :028 > test1
nil
=> nil
1.9.3p194 :029 > test2
NameError: undefined local variable or method `x' for main:Object
What's going on here? It seems like Ruby is hoisting the variable declaration into the outer scope, but I wasn't aware that this is something Ruby does. (Searching for "ruby hoisting" only turns up results about JavaScript hoisting.)
When the Ruby parser sees the sequence identifier, equal-sign, value,
as in this expression
x = 1
it allocates space for a local variable called x. The creation of the
variable—not the assignment of a value to it, but the internal
creation of a variable—always takes place as a result of this kind of
expression, even if the code isn’t executed! Consider this example:
if false
x = 1
end
p x # Output: nil
p y # Fatal Error: y is unknown
The assignment to x isn’t executed, because it’s wrapped in a failing
conditional test. But the Ruby parser sees the sequence x = 1, from
which it deduces that the program involves a local variable x. The
parser doesn’t care whether x is ever assigned a value. Its job is
just to scour the code for local variables for which space needs to
be allocated. The result is that x inhabits a strange kind of variable limbo.
It has been brought into being and initialized to nil.
In that respect, it differs from a variable that has no existence at
all; as you can see in the example, examining x gives you the value
nil, whereas trying to inspect the non-existent variable y results
in a fatal error. But although x exists, it has not played any role in
the program. It exists only as an artifact of the parsing process.
Well-Grounded Rubyist chapter 6.1.2
The ruby parser goes through every lines and set to nil all variable =. The code being actually executed or not does not matter.
See Why can I refer to a variable outside of an if/unless/case statement that never ran?

How is a local variable created even when IF condition evaluates to false in Ruby? [duplicate]

This question already has answers here:
Confusion with the assignment operation inside a falsy `if` block [duplicate]
(3 answers)
Closed 5 years ago.
Try the following in irb: (I'm using Ruby 2.0.0-p247)
blah
#=> NameError: undefined local variable or method `blah' for main:Object
if false
blah = 'blah'
end
#=> nil
blah
#=> nil
I'm surprised that blah is assigned nil even when the if condition evaluates to false.
I thought the code within if is skipped as the condition evaluates to false.
Could someone with Ruby internals knowledge kindly explain how this happened?
Thank you
Local variables in ruby are created during parsing/compilation of code (not execution). They are lexically scoped, so a local variable is not visible before the line where it's assigned to.
defined?(foo) # => nil
if false
defined?(foo) # =>
foo = 'blah'
defined?(foo) # =>
end
defined?(foo) # => "local-variable"
foo # => nil
defined?(foo) lines inside of if return nothing, because they didn't run. The assignment wasn't executed as well. However, the compiler saw the assignment to local variable and created one (with default value of nil).
This behaviour explains the trick from WAT talk:
a = a # => nil
Even though variable a doesn't exist, it is created (and set to nil) right before this line, simply because there is an assignment expression in the code (target of which is yet unknown local variable). So by the time the right hand side of this expression is evaluated, a exists.

Destroy a variable in ruby [duplicate]

This question already has answers here:
Undefine variable in Ruby
(5 answers)
Closed 9 years ago.
I want to destroy a variable in ruby as if it had never existed. Here is an example:
> defined? a
=> "nil"
> a = 1
> defined? a
=> "local-variable"
Now I need to set variable a to "nil" when I do defined?.
I tried some things like:
> a = nil #Not working
=> nil
> defined? a
=> "local-variable"
But nothing seems to work.
As of now (MRI 2.2 and before), there's no way to do this.

Why does Ruby seem to hoist variable declarations from inside a case statement even if that code path is not executed? [duplicate]

This question already has answers here:
Why can I refer to a variable outside of an if/unless/case statement that never ran?
(3 answers)
Closed 5 years ago.
We define a function foo:
def foo(s)
case s
when'foo'
x = 3
puts x.inspect
when 'bar'
y = 4
puts y.inspect
end
puts x.inspect
puts y.inspect
end
We then call it as follows:
1.9.3p194 :017 > foo('foo')
in foo scope
3
in outer scope
3
nil
=> nil
1.9.3p194 :018 > foo('bar')
in bar scope
3
in outer scope
nil
3
=> nil
Why does the function not throw an error about an unregistered local variable in either case? In the first case, the variable y seems like it should not exist, so you can't call inspect on it in the outer scope; the same for x in the second case.
Here's another similar example:
def test1
x = 5 if false
puts x.inspect
end
def test2
puts x.inspect
end
And then:
1.9.3p194 :028 > test1
nil
=> nil
1.9.3p194 :029 > test2
NameError: undefined local variable or method `x' for main:Object
What's going on here? It seems like Ruby is hoisting the variable declaration into the outer scope, but I wasn't aware that this is something Ruby does. (Searching for "ruby hoisting" only turns up results about JavaScript hoisting.)
When the Ruby parser sees the sequence identifier, equal-sign, value,
as in this expression
x = 1
it allocates space for a local variable called x. The creation of the
variable—not the assignment of a value to it, but the internal
creation of a variable—always takes place as a result of this kind of
expression, even if the code isn’t executed! Consider this example:
if false
x = 1
end
p x # Output: nil
p y # Fatal Error: y is unknown
The assignment to x isn’t executed, because it’s wrapped in a failing
conditional test. But the Ruby parser sees the sequence x = 1, from
which it deduces that the program involves a local variable x. The
parser doesn’t care whether x is ever assigned a value. Its job is
just to scour the code for local variables for which space needs to
be allocated. The result is that x inhabits a strange kind of variable limbo.
It has been brought into being and initialized to nil.
In that respect, it differs from a variable that has no existence at
all; as you can see in the example, examining x gives you the value
nil, whereas trying to inspect the non-existent variable y results
in a fatal error. But although x exists, it has not played any role in
the program. It exists only as an artifact of the parsing process.
Well-Grounded Rubyist chapter 6.1.2
The ruby parser goes through every lines and set to nil all variable =. The code being actually executed or not does not matter.
See Why can I refer to a variable outside of an if/unless/case statement that never ran?

Resources