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?
This question is related to
ruby
syntax
instance-variables
class-variables
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.
@@
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
@ 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.
@
- 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
Source: Stackoverflow.com