-1

I would like to understand why this wouldn't work. I know the notion of attr_accessor.

class MyClass
  attr_accessor :num

  def initialize(num = 0)
    @num = num
  end

  def calulate
    while num < 100
      num = num + 1
    end

    puts num
  end

end

c = MyClass.new
c.calulate

This gives me error.

my_class.rb:11:in `calulate': undefined method `+' for nil:NilClass (NoMethodError)

however, If I change num to @num . it works. Would any one can explain this?

Update

Also if I run this line of code, it will return all same id.

puts num.object_id
puts @num.object_id
puts self.num.object_id

result

1
1
1
Jin Lim
  • 1,759
  • 20
  • 24

1 Answers1

4

The problem comes from the line num = num + 1

Accessing works, but for assigning to an accessor from inside a class you would need to do

self.num = num + 1

What you are doing the first time you run num = num + 1 is to create a new variable num and shadowing the method.

So in the while loop every access to num would refer to your new variable, making an explicit assignment to self.num= makes ruby know that you are not creating a new variable.

pjs
  • 18,696
  • 4
  • 27
  • 56
javiyu
  • 1,336
  • 6
  • 9
  • Ok I get it. but, how come same character `num` in while loop. (num = num + 1) is pointing to different memory? in other word, why it creates new variable `num` ? as it has access to @num. using attr_accessor. – Jin Lim Jan 15 '22 at 06:22
  • 1
    I know is kind of confusing, here is a nice post explaining https://www.paulfioravanti.com/blog/curious-incident-shadow-run-time/ in more detail what is happening, basically when you have variable= ruby assumes that the left side is creating a new local variable to that block, in other case you would have no way to create a local variable. – javiyu Jan 15 '22 at 06:35
  • 1
    Please do not answer duplicate questions; this question has already been asked 51 times on Stack Overflow and answered 78 times. Answering duplicate questions leads to fragmentation of knowledge, and it makes it impossible to judge the relative merit of all answers by their votes. Instead, vote to close the question as a duplicate, and if you *really* feel that your answer is better than the existing 78 answers, then add your answer to the duplicate target. – Jörg W Mittag Jan 15 '22 at 07:31