Karthick S
Karthick S

Reputation: 3304

Initialized Class member variable loses value in ruby

This is my third day doing ruby and I am stuck with this problem:

2.0.0-p0 :001 > class SomeClass
2.0.0-p0 :002?>   attr_accessor:a_var
2.0.0-p0 :003?>   def initialize
2.0.0-p0 :004?>     a_var = Hash.new
2.0.0-p0 :005?>     puts "Initialized #{a_var.class}"
2.0.0-p0 :006?>     end
2.0.0-p0 :007?>   def a_fun
2.0.0-p0 :008?>     puts "Initialized #{a_var.class}"
2.0.0-p0 :009?>     end
2.0.0-p0 :010?>   end
 => nil 
2.0.0-p0 :011 > some_obj = SomeClass.new
Initialized Hash
 => #<SomeClass:0x007f9d1d809118> 
2.0.0-p0 :012 > some_obj.a_fun
Initialized NilClass
 => nil 
2.0.0-p0 :013 > 

As you can see, the member variable a_var gets initialized inside in the initialize method but the value is lost when a_fun method is called.

I could not find anyone else facing this issue online.

Can someone please point me to my mistake please?

Upvotes: 0

Views: 389

Answers (3)

user2864740
user2864740

Reputation: 61935

In a_var = x, a_var is treated as a local variable because it lacks the appropriate @ sigil and it appears on the left-hand side in an assignment. As such, the assignment has no effect outside the scope of the initialize method.

Let's look at some different, but similar cases:

a_var = x        # assign to local/lexical variable
self.a_var = x   # invoke a_var= method ("setter")
a_var            # access local variable if it exists in scope
                 # OR invoke self.a_var method ("getter")
@a_var = x       # assign to instance variable

Because attr_accessor is used, I suspect that the following is desired ..

def initialize
  self.a_var = Hash.new
  .. 
end

.. and leave every other a_var access the same (see the rule table above).

Now, as a "well-known" implementation detail, attr_accessor :x uses the instance variable @x internally, so using @a_var directly (i.e. for the assignment) would also work.

Upvotes: 3

boulder_ruby
boulder_ruby

Reputation: 39733

You can only carry instance (have @ before them) variables around from method to method inside of an instance. local variables (have no symbols before them) are limited to their methods or other anonymous enclosures (blocks, etc)

attr_accessor accesses instance variables only. Not local variables.

And your ruby variable naming needs some work. Try to make your variable names match what you're doing. i.e. in this instance you're just trying to discover abstract properties of ruby's structure. Try using @x & @y so the rest of us won't get thrown by your inscrutable naming schemes

Upvotes: 1

Arup Rakshit
Arup Rakshit

Reputation: 118289

change this a_var = Hash.new to @a_var = Hash.new in your #initialize method.

Corrected code:

class SomeClass
  attr_accessor:a_var
  def initialize
    @a_var = Hash.new
    puts "Initialized #{a_var.class}"
  end
  def a_fun
    puts "Initialized #{a_var.class}"
  end
end
some_obj = SomeClass.new
some_obj.a_fun
# >> Initialized Hash
# >> Initialized Hash

Upvotes: 1

Related Questions