191

What are Ruby variables preceded with double at signs (@@)? My understanding of a variable preceded with an at sign is that it is an instance variable, like this in PHP:

PHP version

class Person {

    public $name;

    public function setName($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

Ruby equivalent

class Person

    def set_name(name)
        @name = name
    end

    def get_name()
        @name
    end
end

What does the double at sign @@ mean, and how does it differ from a single at sign?

random
  • 9,774
  • 10
  • 66
  • 83
Andrew
  • 227,796
  • 193
  • 515
  • 708
  • 115
    I don't know, but I get the feeling it's staring at me. I'm a little scared to code in Ruby now... – corsiKa May 04 '11 at 21:34
  • 4
    TL;DR for the public: 99 times out of 100, I would use "class instance" variables (`@` inside `self` methods) not class variables (`@@`). See the litany of reasons why in the answers below. – WattsInABox Apr 24 '17 at 15:52

5 Answers5

268

A variable prefixed with @ is an instance variable, while one prefixed with @@ is a class variable. Check out the following example; its output is in the comments at the end of the puts lines:

class Test
  @@shared = 1

  def value
    @@shared
  end

  def value=(value)
    @@shared = value
  end
end

class AnotherTest < Test; end

t = Test.new
puts "t.value is #{t.value}" # 1
t.value = 2
puts "t.value is #{t.value}" # 2

x = Test.new
puts "x.value is #{x.value}" # 2

a = AnotherTest.new
puts "a.value is #{a.value}" # 2
a.value = 3
puts "a.value is #{a.value}" # 3
puts "t.value is #{t.value}" # 3
puts "x.value is #{x.value}" # 3

You can see that @@shared is shared between the classes; setting the value in an instance of one changes the value for all other instances of that class and even child classes, where a variable named @shared, with one @, would not be.

[Update]

As Phrogz mentions in the comments, it's a common idiom in Ruby to track class-level data with an instance variable on the class itself. This can be a tricky subject to wrap your mind around, and there is plenty of additional reading on the subject, but think about it as modifying the Class class, but only the instance of the Class class you're working with. An example:

class Polygon
  class << self
    attr_accessor :sides
  end
end

class Triangle < Polygon
  @sides = 3
end

class Rectangle < Polygon
  @sides = 4
end

class Square < Rectangle
end

class Hexagon < Polygon
  @sides = 6
end

puts "Triangle.sides:  #{Triangle.sides.inspect}"  # 3
puts "Rectangle.sides: #{Rectangle.sides.inspect}" # 4
puts "Square.sides:    #{Square.sides.inspect}"    # nil
puts "Hexagon.sides:   #{Hexagon.sides.inspect}"   # 6

I included the Square example (which outputs nil) to demonstrate that this may not behave 100% as you expect; the article I linked above has plenty of additional information on the subject.

Also keep in mind that, as with most data, you should be extremely careful with class variables in a multithreaded environment, as per dmarkow's comment.

Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • 2
    This answer would be perfect IMHO if you included code showing how you can use an instance variable at the class level to track class-level data without the 'weird' behavior of sharing data between subclasses. – Phrogz May 04 '11 at 22:05
  • 3
    I'd also point out that class variables can be dangerous/unreliable in a multi-threaded environment (e.g. Rails) – Dylan Markow May 04 '11 at 22:06
  • Hmm...in a way it sounds like static variables in PHP, but the inheritance part is different. I don't think PHP has something exactly like this. – Andrew May 04 '11 at 23:17
  • Even if you aren't multi-threading, you're basically assuming that there's only going to be one of something, and that assumption may not be valid forever. – Andrew Grimm May 05 '11 at 00:07
  • 5
    I don't understand what the ```ruby class << self end``` block does, specifically the << operator. – davidtingsu Jun 04 '13 at 17:55
  • 1
    for others that are confused about `class << self` see [this](https://stackoverflow.com/questions/2505067/class-self-idiom-in-ruby) – kapad Jul 05 '18 at 19:47
47

@ - Instance variable of a class
@@ - Class variable, also called as static variable in some cases

A class variable is a variable that is shared amongst all instances of a class. This means that only one variable value exists for all objects instantiated from this class. If one object instance changes the value of the variable, that new value will essentially change for all other object instances.

Another way of thinking of thinking of class variables is as global variables within the context of a single class. Class variables are declared by prefixing the variable name with two @ characters (@@). Class variables must be initialized at creation time

Shaunak
  • 17,377
  • 5
  • 53
  • 84
13

@@ denotes a class variable, i.e. it can be inherited.

This means that if you create a subclass of that class, it will inherit the variable. So if you have a class Vehicle with the class variable @@number_of_wheels then if you create a class Car < Vehicle then it too will have the class variable @@number_of_wheels

random
  • 9,774
  • 10
  • 66
  • 83
Fareesh Vijayarangam
  • 5,037
  • 4
  • 23
  • 18
  • This means that if you create a subclass of that class, it will inherit the variable. So if you have a class `Vehicle` with the class variable `@@number_of_wheels` then if you create a `class Car < Vehicle` then it too will have the class variable `@@number_of_wheels` – Fareesh Vijayarangam May 04 '11 at 21:56
  • 14
    If I have a `class Vehicle` with `@number_of_wheels`, then `class Car < Vehicle` will also have an instance variable called `@number_of_wheels`. The key difference with class variables is that the classes have *the same* variable, e.g. changing one changes the others. – Michelle Tilley May 04 '11 at 22:02
2

The answers are partially correct because @@ is actually a class variable which is per class hierarchy meaning it is shared by a class, its instances and its descendant classes and their instances.

class Person
  @@people = []

  def initialize
    @@people << self
  end

  def self.people
    @@people
  end
end

class Student < Person
end

class Graduate < Student
end

Person.new
Student.new

puts Graduate.people

This will output

#<Person:0x007fa70fa24870>
#<Student:0x007fa70fa24848>

So there is only one same @@variable for Person, Student and Graduate classes and all class and instance methods of these classes refer to the same variable.

There is another way of defining a class variable which is defined on a class object (Remember that each class is actually an instance of something which is actually the Class class but it is another story). You use @ notation instead of @@ but you can't access these variables from instance methods. You need to have class method wrappers.

class Person

  def initialize
    self.class.add_person self
  end

  def self.people
    @people
  end

  def self.add_person instance
    @people ||= []
    @people << instance
  end
end

class Student < Person
end

class Graduate < Student
end

Person.new
Person.new
Student.new
Student.new
Graduate.new
Graduate.new

puts Student.people.join(",")
puts Person.people.join(",")
puts Graduate.people.join(",")

Here, @people is single per class instead of class hierarchy because it is actually a variable stored on each class instance. This is the output:

#<Student:0x007f8e9d2267e8>,#<Student:0x007f8e9d21ff38>
#<Person:0x007f8e9d226158>,#<Person:0x007f8e9d226608>
#<Graduate:0x007f8e9d21fec0>,#<Graduate:0x007f8e9d21fdf8> 

One important difference is that, you cannot access these class variables (or class instance variables you can say) directly from instance methods because @people in an instance method would refer to an instance variable of that specific instance of the Person or Student or Graduate classes.

So while other answers correctly state that @myvariable (with single @ notation) is always an instance variable, it doesn't necessarily mean that it is not a single shared variable for all instances of that class.

Cagatay Kalan
  • 4,066
  • 1
  • 30
  • 23
  • Not really correct. @myvariable is never a "single shared variable for all instances of that class". It is an instance variable of exactly one object with the scope of only that object. If that object does not provide an accessor for that variable, then other objects, even if they are instances of the class that declared the variable, will not have access to it. The situation is effectively no different from the ability to access an instance variable belonging to any other object. – Huliax Feb 24 '21 at 00:59
1

@ and @@ in modules also work differently when a class extends or includes that module.

So given

module A
    @a = 'module'
    @@a = 'module'

    def get1
        @a          
    end     

    def get2
        @@a         
    end     

    def set1(a) 
        @a = a      
    end     

    def set2(a) 
        @@a = a     
    end     

    def self.set1(a)
        @a = a      
    end     

    def self.set2(a)
        @@a = a     
    end     
end 

Then you get the outputs below shown as comments

class X
    extend A

    puts get1.inspect # nil
    puts get2.inspect # "module"

    @a = 'class' 
    @@a = 'class' 

    puts get1.inspect # "class"
    puts get2.inspect # "module"

    set1('set')
    set2('set')

    puts get1.inspect # "set" 
    puts get2.inspect # "set" 

    A.set1('sset')
    A.set2('sset')

    puts get1.inspect # "set" 
    puts get2.inspect # "sset"
end 

class Y
    include A

    def doit
        puts get1.inspect # nil
        puts get2.inspect # "module"

        @a = 'class'
        @@a = 'class'

        puts get1.inspect # "class"
        puts get2.inspect # "class"

        set1('set')
        set2('set')

        puts get1.inspect # "set"
        puts get2.inspect # "set"

        A.set1('sset')
        A.set2('sset')

        puts get1.inspect # "set"
        puts get2.inspect # "sset"
    end
end

Y.new.doit

So use @@ in modules for variables you want common to all their uses, and use @ in modules for variables you want separate for every use context.

Tantallion
  • 91
  • 5