99

If an instance variable belongs to a class, can I access the instance variable (e.g. @hello) directly using the class instance?

class Hello
  def method1
    @hello = "pavan"
  end
end

h = Hello.new
puts h.method1
Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
Pawan
  • 31,545
  • 102
  • 256
  • 434

3 Answers3

176

Yes, you can use instance_variable_get like this:

class Hello
  def method1
    @hello = "pavan"
  end
end

h = Hello.new
p h.instance_variable_get(:@hello) #nil
p h.method1                        #"pavan" - initialization of @hello
p h.instance_variable_get(:@hello) #"pavan"

If the variable is undefined (first call of instance_variable_get in my example) you get nil.


As Andrew mention in his comment:

You should not make this the default way you access instance variables as it violates encapsulation.

A better way is to define an accessor:

class Hello
  def method1
    @hello = "pavan"
  end
  attr_reader :hello  
end

h = Hello.new
p h.hello #nil
p h.method1                        #"pavan" - initialization of @hello
p h.hello #"pavan"

If you want another method name, you could alias the accessor: alias :my_hello :hello.

And if the class is not defined in your code, but in a gem: You can modify classes in your code and insert new functions to classes.

mabu
  • 286
  • 8
  • 26
knut
  • 27,320
  • 6
  • 84
  • 112
  • 6
    You should *not* make this the default way you access instance variables as it violates encapsulation. – Andrew Marshall Aug 25 '12 at 15:25
  • @knut can't we just do this like `h = Hello.new` and `h.method1` and `h.hello` ? – nik7 Aug 25 '12 at 18:50
  • 3
    @nlingutla You can define an accessor with `attr_reader :hello` – knut Aug 25 '12 at 19:01
  • Wouldn't it be `alias my_hello hello`, not `alias :my_hello :hello`? – Nic Jun 02 '15 at 01:59
  • @QPaysTaxes I learned alias needs symbols as parameter, so no, my version is correct and wanted as is. But I tested your code and it works also - I'm surprised about that. The documentations also use the symbols, e.g. http://ruby.about.com/od/rubyfeatures/a/aliasing.htm – knut Jun 02 '15 at 07:41
  • 1
    For me, this is great for specs, where you don't want to make something public. – baash05 May 24 '18 at 04:50
26

You can also accomplish this by calling attr_reader or attr_accessor like this:

class Hello
  attr_reader :hello

  def initialize
    @hello = "pavan"
  end
end

or

class Hello
  attr_accessor :hello

  def initialize
    @hello = "pavan"
  end
end

Calling attr_reader will create a getter for the given variable:

h = Hello.new
p h.hello        #"pavan"

Calling attr_accessor will create a getter AND a setter for the given variable:

h = Hello.new
p h.hello        #"pavan"
h.hello = "John"
p h.hello        #"John"

As you might understand, use attr_reader and attr_accessor accordingly. Only use attr_accessor when you need a getter AND a setter and use attr_reader when you only need a getter

Kevinvhengst
  • 1,672
  • 4
  • 27
  • 40
1

In case anyone wants to access the variable to set, here how they can do it:

puts h.instance_variable_get(:@hello) # nil
h.instance_variable_set(:@hello, "StackOverflow") # <- set the value
puts h.instance_variable_get(:@hello) # StackOverflow
Rafik Farhad
  • 1,182
  • 2
  • 12
  • 21