Modules setting values to nil in unprocessed conditional blocks?

N

Nate

Hi everyone. We're noticing some strange behavior when including
modules in classes. It seems that even if a conditional block is
forced to evaluate as false (and presumably not execute), assignments
in the conditional block are executed and set to nil. Here is an
example:

==========================
module Conundrum
def riddle
@riddle ||= 'mystery'
end

def riddle=(new_val)
puts "Called riddle="
@riddle = new_val
end
end

class Test
include Conundrum

def test
puts "Before: #{riddle}"
if true == false
riddle = 'solved!'
end
puts "After: #{riddle}"
puts "After class: #{riddle.class}"
end
end

Test.new.test
==========================

Note that this prints out:

Before: mystery
After:
After class: NilClass

So it would seem that riddle= is not getting called, but yet the
riddle function now returns nil. Interestingly, this fixes the
problem:

==========================
module Conundrum
def riddle
@riddle ||= 'mystery'
end

def riddle=(new_val)
puts "Called riddle="
@riddle = new_val
end
end

class Test
include Conundrum

def test
puts "Before: #{riddle}"
if true == false
@riddle = 'solved!'
end
puts "After: #{riddle}"
puts "After class: #{riddle.class}"
end
end

Test.new.test
==========================

Outputs:

Before: mystery
After: mystery
After class: String

Any insights are much appreciated!

-n8
 
7

7stud --

Nate said:
Hi everyone. We're noticing some strange behavior when including
modules in classes. It seems that even if a conditional block is
forced to evaluate as false (and presumably not execute), assignments
in the conditional block are executed and set to nil. Here is an
example:

==========================
module Conundrum
def riddle
@riddle ||= 'mystery'
end

def riddle=(new_val)
puts "Called riddle="
@riddle = new_val
end
end

class Test
include Conundrum

def test
puts "Before: #{riddle}"
if true == false


Inside test, self is equal to the Test instance you created here:
Test.new.test

And this line:
puts "Before: #{riddle}"

is equivalent to:
puts "Before: #{self.riddle}"

However, when ruby parses this line:
riddle = 'solved!'

ruby creates a local variable named riddle. As a result, when you get
to this statement:
puts "After: #{riddle}"

riddle is no longer equivalent to self.riddle. Instead riddle is just
riddle; and riddle is a local variable that hasn't been assigned a
value. For local variables that exist but have not been assigned a
value, ruby returns nil for the value of the variable. Then the string
interpolation calls nil.to_s which returns a blank string.
 
7

7stud --

7stud said:
However, when ruby parses this line:


ruby creates a local variable named riddle.

Just to clarify: "parse" is different than "execute". That line will
never execute, but ruby still parses the code; and it's when ruby parses
the code that the local variable riddle is created.
 
N

n8agrin

Just to clarify: "parse" is different than "execute".  That line will
never execute, but ruby still parses the code; and it's when ruby parses
the code that the local variable riddle is created.

Clicked "Reply to Author" accidently earlier but meant to give some
public thanks for your response. So, thanks, appreciate the response
and the precision you provided in your answer.

- n8 -
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top