3

Why is it not possible to read a class's instance variable value if it was set within the class using the attr_accessor?

Is it because the the instance variable is "private?"

Setting the attribute this way works:

class Test
  attr_accessor :magic
end

bob = Test.new
bob.magic = "cat" #set 
print bob.magic #read

Setting the attribute this way fails:

class Test
  attr_accessor :magic
  @magic = "spell"
end

bob = Test.new
print bob.magic #this resolves to 'nil'

4 Answers 4

3

There is a significant difference between instance variables and class instance variables.

class Test
  @magic = "spell" # class instance var, since the scope is class 

  def initialize
    @magic = 42 # instance var, scope is instance
  end
end

Those two live together, since they are defined on different objects:

Test.instance_variable_get(:@magic) #⇒ "spell"
Test.new.instance_variable_get(:@magic) #⇒ 42

That said, attr_accessor reads the variable from the scope, it was defined for. Yours was defined in class scope, therefore it reads the instance scoped variable.

To read the class instance variable, define attr_accessor on class’ singleton class level:

class Test
  singleton_class.send :attr_accessor, :magic # reads class instance var ⇓
  @magic = "spell" # class instance var, since the scope is class 

  attr_accessor :magic # reads instance var ⇓
  def initialize
    @magic = 42 # instance var, scope is instance
  end
end

Test.magic
#⇒ "spell"
Test.new.magic
#⇒ 42
Sign up to request clarification or add additional context in comments.

2 Comments

I'm not sure I'm reading this right: "That said, attr_accessor reads the variable from the scope, it was defined for. Yours was defined in class scope, therefore it reads the instance scoped variable." Did you mean to say "class instance scoped variable?"
Well, the code talks while wording walks. See the comments in my snippets to get what reads where.
2

You can access Test's @magic by defining attr_accessor within the singleton class of Test:

class Test
  @magic = "spell"

  class << self
    attr_accessor :magic
  end
end

Test.magic #=> "spell"

Comments

2

You should move @magic declaration/assignment to the constructor, like this:

class Test
  attr_accessor :magic

  def initialize
    @magic = "spell"
  end
end

bob = Test.new
print bob.magic #spell

When you declare instance variable (@) outside any method (self), it becomes unreachable by the class instance.

1 Comment

When you declare instance variable (@) outside any method (self), it becomes unreachable by the class instance. - there is almost no unreachable things in Ruby. Having user's example with @magic = "spell": Test.new.class.instance_variable_get(:@magic) would get it :)
2

Instance variables belong to objects (aka "instances"), that's why they are called instance variables.

In your first example, you are setting the instance variable @magic on bob to 'cat' and then you are reading the instance variable @magic on bob.

In your second example, you are setting the instance variable @magic on Test (which is a completely different object than bob) and then you are reading the instance variable @magic from bob, which hasn't been set yet, and uninitialized instance variables evaluate to nil.

Remember: classes are objects just like any other object. They can have instance variables just like any other object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.