Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between @instance_variable and attr_accessor

Tags:

ruby

I Just started learning ruby and I don't see the difference between an @instace_variable and an attribute declared using attr_accessor.

What is the difference between the following two classes:

class MyClass     @variable1  end 

and

class MyClass   attr_accessor :variable1 end 

I searched lot of tutorials online and everybody uses different notation, Does it have to do anything with the ruby version? I also searched few old threads in StackOverflow

What is attr_accessor in Ruby?
What's the Difference Between These Two Ruby Class Initialization Definitions?

But still I am not able to figure out what is the best way to use.

like image 619
Rajesh Pantula Avatar asked Oct 16 '12 21:10

Rajesh Pantula


People also ask

What is Attr_accessor?

attr_accessor is a shortcut method when you need both attr_reader and attr_writer . Since both reading and writing data are common, the idiomatic method attr_accessor is quite useful.

What is ATTR reader?

An attribute reader returns the value of an instance variable. Another way of looking at this is that an attribute reader is a method that “exposes” an instance variable. It makes it accessible for others.

What is attribute in Ruby?

Attributes are specific properties of an object. Methods are capabilities of an object. In Ruby all instance variables (attributes) are private by default. It means you don't have access to them outside the scope of the instance itself. The only way to access the attribute is using an accessor method.


2 Answers

An instance variable is not visible outside the object it is in; but when you create an attr_accessor, it creates an instance variable and also makes it visible (and editable) outside the object.

Example with instance variable (not attr_accessor)

class MyClass   def initialize     @greeting = "hello"   end end  m = MyClass.new m.greeting #results in the following error:   #NoMethodError: undefined method `greeting' for #<MyClass:0x007f9e5109c058 @greeting="hello"> 

Example using attr_accessor:

class MyClass   attr_accessor :greeting    def initialize     @greeting = "hello"   end end  m2 = MyClass.new m2.greeting = "bonjour" # <-- set the @greeting variable from outside the object m2.greeting #=> "bonjour"   <-- didn't blow up as attr_accessor makes the variable accessible from outside the object 

Hope that makes it clear.

like image 64
Nat Ritmeyer Avatar answered Sep 19 '22 18:09

Nat Ritmeyer


Instance variables are not directly visible outside of the class.

class MyClass   def initialize     @message = "Hello"   end end  msg = MyClass.new @message #==> nil   # This @message belongs to the global object, not msg msg.message #==> NoMethodError: undefined method `message' msg.@message #==> SyntaxError: syntax error, unexpected tIVAR 

Now, you can always do this:

msg.instance_eval { @message } 

or ask for the variable directly like this:

msg.instance_variable_get :@message 

But that's awkward and sort of cheating. Poking around someone else's class may be educational, but your client code shouldn't be required to do it to get reliable results. So if you want clients to be able to see those values, don't make them use the above techniques; instead, define a method to expose the value explicitly:

class MyClass   def message      return @message   end end msg.message # ==> "Hello" 

Because you so often want to do that, Ruby provides a shortcut to make it easier. The code below has exactly the same result as the code above:

class MyClass   attr_reader :message end 

That's not a new type of variable; it's just a shorthand way to define the method. You can look at msg.methods and see that it now has a message method.

Now, what if you want to allow outsiders to not only see the value of an instance variable, but change it, too? For that, you have to define a different method for assignment, with a = in the name:

class MyClass   def message=(new_value)     @message = new_value   end end msg.message = "Good-bye" msg.message # ==> "Good-bye" 

Note that the assignment operators are semi-magical here; even though there's a space between msg.message and =, Ruby still knows to call the message= method. Combination operators like += and so on will trigger calls to the method as well.

Again, this is a common design, so Ruby provides a shortcut for it, too:

class MyClass   attr_writer :message end 

Now, if you use attr_writer by itself, you get an attribute that can be modified, but not seen. There are some odd use cases where that's what you want, but most of the time, if you are going to let outsiders modify the variable, you want them to be able to read it, too. Rather than having to declare both an attr_reader and an attr_writer, you can declare both at once like so:

class MyClass   attr_accessor :message end 

Again, this is just a shortcut for defining methods that let you get at the instance variable from outside of the class.

like image 43
Mark Reed Avatar answered Sep 17 '22 18:09

Mark Reed