What Does @@variable Mean in Ruby?

Learn what the double at-sign (@@) before a variable name means in Ruby

In Ruby, the double at-sign (@@) before a variable name (e.g. @@variable_name) is used to create a class variable. These variables are:

  • Static — i.e. only a single copy of the variable exists, regardless of however many instances of the class you create;
  • Globally scoped within the context of inheritance hierarchy — i.e. they're shared between a class and all its subclasses.

For example, consider the following class where a counter is incremented each time a new object is instantiated:

class Entity
  @@counter = 0

  def initialize
    @@counter += 1
    puts "There are #{@@counter} entities"
  end
end

a = Entity.new
b = Entity.new
c = Entity.new

# output:
# "There are 1 entities"
# "There are 2 entities"
# "There are 3 entities"

Class variables can be problematic though; for example, a class variable might (accidentally) be reassigned by any of its subclasses, affecting all other classes:

class Parent
  @@counter = 0

  def initialize
    @@counter += 1
  end

  def self.counter
    @@counter
  end
end

class Child < Parent
  @@counter = 100
end

a = Parent.new
b = Parent.new
c = Parent.new

d = Child.new

puts Parent.counter # output: 104

The output here is 104 because the Child class sets the initial value of @@counter to 100. After that there are a total of four object instances that are created. This results in @@counter being incremented four times, updating the @@counter value to 104. If that sounds confusing, then perhaps the following example will give you a clearer understanding of this:

class Parent
  @@name = "parent"

  def self.name
    @@name
  end
end

puts Parent.name # output: "parent"

class Child < Parent
  @@name = "child"
end

puts Parent.name # output: "child"

Similarly, when/if an ancestor class changes the value of the class variable, you would run into the same issue:

class Parent
  @@name = "parent"

  def self.name
    @@name
  end
end

puts Parent.name # output: "parent"

class Object
  @@name = "object"
end

puts Parent.name # output: "object"

As you can see, basically any sub-class or ancestor class that is defined after the parent could potentially reassign a class variable leading to unexpected behavior:

class Parent
  @@name = "parent"

  def self.name
    @@name
  end
end

puts Parent.name # output: "parent"

class Child < Parent
  @@name = "child"
end

puts Parent.name # output: "child"

class Object
  @@name = "object"
end

puts Parent.name # output: "object"

Therefore, you should generally avoid class variables, and use instance variables instead.


Hope you found this post useful. It was published . Please show your love and support by sharing this post.