Coming from a Java background, I was in for a surprise when I realized that in Ruby, local variables do not have ’scope inheritance’.

Let me explain what I mean. In Java, you can do something like this.

class VariableScopeTest {
  int i = 1;
  public void print_i() {
    System.out.println(i);
  }
  public static void main(String[] args) {
    VariableScopeTest vst = new VariableScopeTest();
    vst.print_i();
  }
} 

When you execute this code the result is “1″. A new instance of VariableScopeTest is created and assigned to the variable vst. When the print_i method is called, the local variable ‘i’ is not defined in the method, so the runtime goes one level up and sees that the variable ‘i’ is defined at the class level, and that value is used.

Let’s rewrite the print_i method.

public void print_i() {
  i = 2;
  System.out.println(i);
}

If I replace the print_i method with this one and executed it, and the result is ‘2′. Since the runtime found that the variable ‘i’ defined in the method, it uses that variable. The first ‘i’ is rendered invisible to the print_i method.

In Ruby the scoping is much more restricted. There are 3 scopes: top level (or main), class (or module), and method. Here is the main difference. Scopes are not nested. Let me rewrite the above Java code in Ruby and see what happens.

class Foo
  i = 1
  def print_i
    puts i
  end
end

foo = Foo.new
foo.print_i

The result is:

NameError: undefined local variable or method 'i'

It obviously didn’t work. This is because the Ruby runtime will not search for the local variable ‘i’ in other scope if it is not found in the local scope.

If you refer to variable ‘i’, then ‘i’ must have been defined in that same scope. I would have to modify my print_i method to initialize the variable ‘i’ and set it to a value. So from inside the method print_i, the outer variable ‘i’ which is assigned the value of 1 is invisible.

There is actually more to this than meets the eye (i.e. Ruby instance variables versus Java instance variables), but this is something that has tripped me up more than once. I have been bitten several times because I assumed that the runtime would search for my variable if it wasn’t defined in the local scope.