1. Computing

Instance Variables

By

Instance variables begin with an at sign (@) and can be referenced only within class methods. They differ from local variables in that they don't exist within any particular scope. Instead, a similar variable table is stored for each instance of a class. Instance variables live within a class instance, so as long as that instance stays alive, so will the instance variables.

Instance variables can be referenced in any method of that class. All methods of a class use the same instance variable table, as opposed to local variables where each method will have a different variable table. It is possible to access instance variables without first defining them, however. This will not raise an exception, but the variable's value will be nil and a warning will be issued if you've run Ruby with the -w switch.

This example demonstrates the use of instance variables. Note that the shebang contains the -w switch, which will print warnings should they occur. Also note the incorrect usage outside of a method in the class scope. This is incorrect, and discussed below.


#!/usr/bin/env ruby -w

class TestClass
 # Incorrect!
 @test = "monkey"

 def initialize
   @value = 1337
 end

 def print_value
   # OK
   puts @value
 end

 def uninitialized
   # Technically OK, generates warning
   puts @monkey
 end
end

t = TestClass.new
t.print_value
t.uninitialized

Why is the @test variable incorrect? This has to do with scope and how Ruby implements things. Within a method, the instance variable scope refers to the particular instance of that class. However, in the class scope (inside the class, but outside of any methods), the scope is the class instance scope. Ruby implements the class hierarchy by instantiating Class objects, so there is a second instance at play here. The first instance is an instance of the Class class, and this is where @test will go. The second instance is the instantiation of TestClass, and this is where @value will go. This gets a bit confusing, but just remember to never use @instance_variables outside of methods. If you need class-wide storage, use @@class_variables, which can be used anywhere in the class scope (inside or outside of methods) and will behave the same.

Accessors

You normally cannot access instance variables from outside of the an object. For instance, in the above example, you cannot simply call t.value or t.@value to access the instance variable @value. This would break the rules of encapsulation. This also applies to instances of child classes, they cannot access instance variables belonging to the parent class even though they're technically the same type. So, in order to provide access to instance variables, accessor methods must be declared.

The following example demonstrates how accessor methods can be written. However, note that Ruby provides a shortcut, and that this example only exists to show you how the accessor methods work. It's generally not common to see accessor methods written in this way unless some sort of additional logic is needed for the accessor.


#!/usr/bin/env ruby

class Student
 def initialize(name,age)
   @name, @age = name, age
 end

 # Name reader, assume name can't change
 def name
   @name
 end

 # Age reader and writer
 def age
   @age
 end

 def age=(age)
   @age = age
 end
end

alice = Student.new("Alice", 17)

# It's Alice's birthday
alice.age += 1

puts "Happy birthday #{alice.name}, \
you're now #{alice.age} years old!"

The shortcuts make things a bit easier and more compact. There are three of these helper methods. They must be run in the class scope (inside the class but outside of any methods), and will dynamically define methods much like the methods defined in the above example. There's no magic going on here, and they look like language keywords, but they really are just dynamically defining methods. Also, these accessors typically go at the top of the class. That gives the reader an instant overview of which member variables will be available outside the class or to child classes.

There are three of these accessor methods. They each take a list of symbols describing the instance variables to be accessed.

  • attr_reader - Define "reader" methods, such as the name method in the above example.
  • attr_writer - Define "writer" methods such as the age= method in the above example.
  • attr_accessor - Define both "reader" and "writer" methods.


#!/usr/bin/env ruby

class Student
  attr_reader :name
  attr_accessor :age

  def initialize(name,age)
    @name, @age = name, age
  end
end

alice = Student.new("Alice", 17)

# It's Alice's birthday
alice.age += 1

puts "Happy birthday #{alice.name}, \
you're now #{alice.age} years old!"

When to use Instance Variables

Now that you know what instance variables are, when do you use them? Instance variables should be used when they represent the state of the object. A student's name and age, their grades, etc. They shouldn't be used for temporary storage, that's what local variables are for. However, they could possibly be used for temporary storage between method calls for multi-stage computations. However if you're doing this, you may want to rethink your method composition and make these variables into method parameters instead.

  1. About.com
  2. Computing
  3. Ruby
  4. Beginning Ruby
  5. Variables
  6. Instance Variables

©2014 About.com. All rights reserved.