0

I have the following Ruby code that throws the same exception depending on whether a variable in the constructor is set via the @foo instance variable or via the foo= method of attr_accessor:

# Variation 1: initializing @foo, using foo
class A
  attr_accessor :foo

  def initialize
    @foo = [0,1,2] # <<-- With @
    foo += [3] # NoMethodError: undefined method `+' for nil:NilClass
  end
end

a = A.new

I presume this variation 1 is some kind of manifestation of the "assigning a non existant variable to itself is nil in Ruby". And somehow the variable declaration takes precedence over the generated method foo.

non_existant += [1] # NoMethodError: undefined method `+' for nil:NilClass

So I decided to only use the methods generated by attr_accessor. And by doing this, I suddenly seem to have introduced a local variable in the constructor:

# Variation 2: initializing with foo=, using foo
class A
  attr_accessor :foo

  def initialize
    foo = [0,1,2]  # <<-- No @
    foo += [3]
  end
end

a = A.new
puts a.foo.inspect # prints nil
a.foo += [4]       # NoMethodError: undefined method `+' for nil:NilClass

For the record: I am aware that using only the @foo instance variable in the constructor fixes the issue:

# Variation 2: Only using @foo
class A
  attr_accessor :foo

  def initialize
    @foo = [0,1,2]
    @foo += [3]
  end
end

a = A.new

puts a.foo.inspect # prints [0, 1, 2, 3]
a.foo += [4]       # works

But as soon as I use the foo= method generated by attr_accessor, the instance should be properly saved and I don't understand why I can't access it on an instance?

Marcus Riemer
  • 6,579
  • 7
  • 52
  • 70
  • If you insert the line `puts local_variables` after the line `foo += [3]` (in `initialize` in "Variation 2") `A.new` will cause `[:foo]` to be displayed, telling you that `foo = [0,1,2]` has assigned an array to a local variable, `foo`, not to the instance variable `@foo`. That makes sense. How else could you define a local variable `foo`? The link citing the earlier question for which this one is a duplicate will tell you that you need to write `@foo = [0,1,2]` or `self.foo = [0,1,2]` to reference the instance variable `@foo`. – Cary Swoveland Mar 04 '22 at 20:46

0 Answers0