blink_2025_08
SitePoint Premium
Stay Relevant and Grow Your Career in Tech
  • Premium Results
  • Publish articles on SitePoint
  • Daily curated jobs
  • Learning Paths
  • Discounts to dev tools
Start Free Trial

7 Day Free Trial. Cancel Anytime.

Key Takeaways

  • Class variables in Ruby are often seen as problematic due to their behavior when inheritance is involved, as changes made to a class variable in a subclass can inadvertently affect the superclass.
  • Despite this, class variables can be useful in certain scenarios, such as in web applications where they can be used for initialization data and class level configuration.
  • A common technique to avoid issues with class variables is to use class instance variables, which are not shared with subclasses and therefore changes in one class do not affect others.
  • Understanding and implementing class variables effectively requires a strong grasp of Ruby’s object-oriented nature, as well as the differences between class variables, instance variables, and constants.

Class variables in Ruby have a bad name. It’s true, they are considered harmful, borderline evil. So why the bad rap? Well, most groans are about how they behave when inheritance enters the fray. Correction: It’s all about how they behave compared to what we expect.

To paint a picture of our little problem child lets look at what we expect with PHP.


<?php

class DemoClass {

public $myvar;

public function __construct() {

$this->myvar = "hello world : ";

}

public function getMyVar() {

echo $this->myvar;

}

}

class Demo2Class extends DemoClass {

public function __construct() {

$this->myvar = "goodbye world : ";

}

}

$demo1 = new DemoClass();

$demo2 = new Demo2Class();

$demo1->getMyVar();

$demo2->getMyVar();

$demo1->getMyVar();

// Produces

// hello world : goodbye world : hello world : "

That makes sense to me. We define a class with a concrete constructor and abstract getter. When inherited we can override the constructor and set the “class variable” to something else. The base class is unaffected, the world keeps spinning.

In Ruby if we try and do something similar using class variables we end up with one or two problems.


class DemoClass
@@my_var = nil

def initialize

@@my_var = "hello world"

end

def my_var

puts @@my_var

end

end

class Demo2Class < DemoClass

def initialize

@@my_var = "goodby world"

end

end

demo1 = DemoClass.new

demo1.my_var

demo2 = Demo2Class.new

demo2.my_var

demo1.my_var

# Produces

#hello world

#goodbye world

#goodbye world

When you approach class variables in Ruby in this manner they just seem wrong. The change to my_var in Demo2Class has bubbled up to our base class. To mitigate the problem, say we subclass DemoClass again the behaviour of the class variable my_var is nothing short of unpredictable. They are global variables in disguise.

So Why Use Class Variables?

On the face of it the rumours about class variables are true. But now we know what not to do, is there a scenario where class level variables are actually useful? Well, I confess. I use them in almost every web application.

Using the methods described in our examples, depending on initialization data implemented using class level variables as a class ‘state’ is a pretty bad idea. However, I do use class variables for initialization data.

Rails applications generally have at least 4 environments, production, staging, development and test. It’s very likely that configuration changes per environment, be it email addresses to mail exceptions to or a URL of a web service sandbox. The code itself looks like:


class AppConfig
@@app_config = YAML::load(ERB.new((IO.read("#{RAILS_ROOT}/config/app_config.yml"))).result)[RAILS_ENV]

def self.method_missing(sym, *args, &block)

@@app_config[sym.to_s]

end

end

It should be pretty self explanatory. A YAML file is parsed into the class variableapp_config. Then usingmethod_missingat class level I can retrieve values easily withAppConfig.exception_email_addresses`.

Class Level Configuration

So now hopefully we can agree that class variables are not completely evil. Sometimes we do want to share traits at a class level down class hierarchy. A common technique to achieve this without incurring the problems described previously is to use class instance variables.

Although a bit of a mouthful, class instance variables are pretty straightforward, (coming from PHP they did not make sense at first) we just have to adjust our thinking slightly. I always find the best way to discover first is irb.


ruby-1.9.2-p290 :001 > class Demo
ruby-1.9.2-p290 :002?> @my_instance_variable = "whaaa?"
ruby-1.9.2-p290 :003?> end
=> "whaaa?"
ruby-1.9.2-p290 :004 > Demo.class
=> Class
ruby-1.9.2-p290 :005 > Demo.superclass
=> Object
ruby-1.9.2-p290 :006 > Demo.instance_variables
=> [:my_instance_variable]

There it is, unlike more classical languages Ruby classes (like everything else) are just objects with instance variables. So how does this knowledge help us? Returning to the previous example and employing a little accessors trick.


class DemoClass
class << self
attr_accessor :my_var
end

@my_var = nil

def initialize

self.class.my_var = "hello world"

end

def my_var

puts self.class.my_var

end

end

class Demo2Class < DemoClass

def initialize

self.class.my_var = "goodby world"

end

end

demo1 = DemoClass.new

demo1.my_var

demo2 = Demo2Class.new

demo2.my_var

demo1.my_var

# Produces

# hello world

# goodbye world

# hello world

The example is looking pretty horrible now, before any explanation lets clean it up so it offends our eyes no longer.


class DemoClass
class << self
attr_accessor :my_var
end

@my_var = "hello world"

end

class Demo2Class < DemoClass

@my_var = "goodby world"

end

puts DemoClass.my_var

puts Demo2Class.my_var

puts DemoClass.my_var

If you are unsure about eigenclasses ( a.k.a singleton classes, but I’m originally a PHP guy and a singleton class meant something totally different at first) in this demonstration we are simply using it to create a attr_accessor as we normally would, only doing it this way creates it for our class instance variable.

Wrapping up

Remember when I said class variables are not always bad and showed an example when they are perfectly acceptable (well in my book anyway). I did come across a problem with that AppConfig snippet.

I had to duplicate an application for two different clients. Obviously the configuration data was different, but the codebase was to be the same. I wanted to maintain the codebase in a single SCM repository (bug fixes or updates would apply to both versions) and I didn’t want to hit git merge mashes, in fact I didn’t want the SCM to take on a new role in my workflow, it’s there to do SCM only, not manage configuration across clients.

Obviously, we would look to persist the configuration in a database, which is simple to achieve in Rails using an ActiveRecord model like so:


# app/models/application_config.rb

class ApplicationConfig < ActiveRecord::Base

serialize :config_value

after_save :reset_config

def reset_config

AppConfig.reset_configs

end

end

# lib/app_config.rb

class AppConfig

class << self

attr_accessor :configs

end

@configs = {}

def self.method_missing(sym, *args, &block)

@configs[sym.to_s] ||= ""

end

def self.reset_configs

self.configs = {}

configs = ApplicationConfig.all

configs.each do |setting|

self.configs = {setting.config_key => setting.config_value}.merge self.configs

end

end

end

Using the code above I could drop in a persisted configuration for the application without refactoring any code where the configuration data was being accessed (this was a big win as it was a pretty large app). I could also use a simple scaffold to update and edit configuration on the fly. The use of class instance variables allowed me to cache the config data without hitting the database for every method_missing message the class received.

Hopefully, that has dispelled the class variables are useless/evil myth. Like most things, a lack of understanding and naive implementations gives class variales a bad name. It certainly took me a while (and plenty of naive implementations) to get a grasp of what’s going on with them. As for the eigenclass stuff, check out Nathan Kleyns article on metaprogramming for more detail.

Frequently Asked Questions about Ruby Class Variables

What is the difference between class variables and instance variables in Ruby?

In Ruby, class variables and instance variables serve different purposes. A class variable, denoted by @@, is shared among all instances of a class and the class itself. It means if you change the value of a class variable, it will be changed for all instances of that class. On the other hand, an instance variable, denoted by @, is unique to each instance of a class. Each object or instance of the class has its own copy of the instance variable. Therefore, changing the value of an instance variable only affects that specific instance, not all instances of the class.

How can I access a class variable in Ruby?

In Ruby, class variables are accessed within the class by using the @@ prefix followed by the variable name. However, they are not directly accessible outside the class. To access a class variable outside the class, you need to define a class method that returns the value of the class variable.

Can I use class variables in subclasses in Ruby?

Yes, class variables in Ruby are shared with subclasses. This means that if you define a class variable in a superclass, it will be accessible in any subclasses. However, any changes made to the class variable in the subclass will also affect the superclass, because they both reference the same memory location.

What is the scope of class variables in Ruby?

The scope of class variables in Ruby is within the class and its instances, as well as any subclasses. This means that class variables can be accessed and modified anywhere within the class, its instances, and any subclasses. However, they cannot be accessed directly outside the class.

How do class variables behave in Ruby compared to other languages?

In Ruby, class variables are shared among all instances of a class and the class itself, which is different from some other languages. For example, in Java, class variables (also known as static variables) are shared among all instances of a class, but not with the class itself.

What are the potential pitfalls of using class variables in Ruby?

One potential pitfall of using class variables in Ruby is that they are shared with subclasses. This means that changes to a class variable in a subclass can unintentionally affect the superclass and other subclasses. This can lead to unexpected behavior and bugs that are difficult to track down.

How can I avoid problems with class variables in Ruby?

To avoid problems with class variables in Ruby, you can use class instance variables or constants instead. Class instance variables are not shared with subclasses, so changes in one class do not affect others. Constants are also not shared with subclasses, and they have the added benefit of being immutable, meaning their values cannot be changed once set.

Can I use class variables in modules in Ruby?

Yes, you can use class variables in modules in Ruby. However, just like with classes, class variables in modules are shared among all instances of the module and the module itself. This means that changes to a class variable in one instance of the module will affect all other instances.

How do I define a class variable in Ruby?

In Ruby, you define a class variable by using the @@ prefix followed by the variable name. You can then assign a value to the class variable using the assignment operator (=). For example, @@my_variable = 10 defines a class variable named my_variable and assigns it the value 10.

Can I change the value of a class variable in Ruby?

Yes, you can change the value of a class variable in Ruby. To do this, you simply assign a new value to the class variable using the assignment operator (=). However, keep in mind that changing the value of a class variable will affect all instances of the class and the class itself, as well as any subclasses.

© 2000 – 2025 SitePoint Pty. Ltd.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.