Modules setting values to nil in unprocessed conditional blocks?

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

Nate wrote:

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.

···

--
Posted via http://www.ruby-forum.com/.

7stud -- wrote:

However, when ruby parses this line:

      riddle = 'solved!'

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.

···

--
Posted via http://www.ruby-forum.com/.

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 -

···

On Aug 24, 9:14 am, 7stud -- <bbxx789_0...@yahoo.com> wrote:

7stud -- wrote:

> However, when ruby parses this line:

>> riddle = 'solved!'

> 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.
--
Posted viahttp://www.ruby-forum.com/.