Don't Use Class variables.... Really

January 11, 2012

Image 1

I recently read on stack overflow that you shouldn't use class variables but instead use class instance variables. I wasn’t satisfied in the reason given, and hence the short blog piece below.

The Confusion

The problem with class variables, in Ruby, is that the scope is not what you expect. This is especially true if you come from other languages such as Java.

In Java class variables belongs to the class, which is different to Ruby where they belong to the class hierarchy.

This was the source of my confusion it would have been better if they were called class hierarchy variable.

Here is how class variables bites:

#------------------------------------------------------#
# The class variable starts as "happy" but ends        #
#  very "sad"                                          #
#------------------------------------------------------#

class MyParent
  def MyParent.get_happy_value
    @@happy_variable
  end
  @@happy_variable="this make's me happy"
end

MyParent.get_happy_variable #=> "this make's me happy"

class MyChild <MyParent
  @@happy_variable="this make's me sad"
end

MyParent.get_happy_variable #=> "this make's me sad"

Let's take a look at what is going on

Incorrect example

The class variables @@happy_variable does not belong to either the class or object but rather the class hierarchy, so it can be changed by a child class with dire results. The @@happy_variable refers to the same variable across both classes. This wouldn't be the case, if you wrote the same class method in another language like Java.

So how do I create a class variable (like in Java)

To get the same behaviour use class instance variables. It is essentially just an instance variable but at the class level ie it belongs to the class .

#------------------------------------------------------#
# The class instance variable starts as "happy" stays  #
#  very "happy"                                        #
#------------------------------------------------------#

class MyParent
  @happy_variable="this make's me happy"     #lives in the class not the instance
  def get_happy_value
  self.class.instance_eval{@happy_variable}  #changes self from the instance to the class
  end
end

MyParent.new().get_happy_value  #=> "this make's me happy"

class MyChild <MyParent
  @happy_variable="this make's me sad"
end

MyParent.new().get_happy_value  #=> "this make's me happy"

Since the instance class variables belongs to the class each class can have a different value for @happy_variable This is different to class variables where the variable belongs to the class hierarchy. Here any changes to @@happy_variable will be for all of the classes in the hierarchy.