3

An example will explain the question:

Val = Struct.new(:value) do
  def inc 
    p value
    value = value + 1 
  end
end

v = Val.new(1)
v.inc

The output will be:

1
undefined method `+' for nil:NilClass (NoMethodError)

Why do I get this error when value is clearly not nil? Is there a way to make this work?

Jonah
  • 15,806
  • 22
  • 87
  • 161

2 Answers2

5
Val = Struct.new(:value) do
  def inc 
    p value # here it still prints 1

    # but here you REDEFINED what value is. It is now a local variable!
    # Also its initial value is nil, hence the error you're getting.
    value = value + 1 

    # should have used this instead, to reference the method
    self.value = value + 1
  end
end
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
4

Clarification on Sergio's answer.

Within inc's definition, there is initially no variable value, and what is called by p value is the method value, which returns 1.

Then in line value = value + 1, at the point when value = has been parsed, a local variable value is created and is initialized to nil. Even though value + 1 is evaluated prior to assignment of its value into the newly created value, the initialization of value takes place first. So, when value + 1 is to be evaluated, there already is a local variable value, which has priority to be called over the method value. And this value is nil.

sawa
  • 165,429
  • 45
  • 277
  • 381
  • my only remaining confusion is: why is "self." not implied as it normally is? is that rule inapplicable to assignment statements in general? – Jonah Dec 23 '15 at 07:34
  • 1
    If a method call (with implicit `self` receiver) had priority over a local variable, then there would be no way to call that variable. – sawa Dec 23 '15 at 07:37
  • well, it could work if you disallowed shadowing method names with local vars, right? but i get your point – Jonah Dec 23 '15 at 07:39