96

Can anyone tell me about the difference between class variables and class instance variables?

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
cmd
  • 1,013
  • 1
  • 8
  • 8

3 Answers3

161

A class variable (@@) is shared among the class and all of its descendants. A class instance variable (@) is not shared by the class's descendants.


Class variable (@@)

Let's have a class Foo with a class variable @@i, and accessors for reading and writing @@i:

class Foo

  @@i = 1

  def self.i
    @@i
  end

  def self.i=(value)
    @@i = value
  end

end

And a derived class:

class Bar < Foo
end

We see that Foo and Bar have the same value for @@i:

p Foo.i    # => 1
p Bar.i    # => 1

And changing @@i in one changes it in both:

Bar.i = 2
p Foo.i    # => 2
p Bar.i    # => 2

Class instance variable (@)

Let's make a simple class with a class instance variable @i and accessors for reading and writing @i:

class Foo

  @i = 1

  def self.i
    @i
  end

  def self.i=(value)
    @i = value
  end

end

And a derived class:

class Bar < Foo
end

We see that although Bar inherits the accessors for @i, it does not inherit @i itself:

p Foo.i    # => 1
p Bar.i    # => nil

We can set Bar's @i without affecting Foo's @i:

Bar.i = 2
p Foo.i    # => 1
p Bar.i    # => 2
onebree
  • 1,853
  • 1
  • 17
  • 44
Wayne Conrad
  • 103,207
  • 26
  • 155
  • 191
  • 2
    Why return instance variables using class methods? Do you often run into this situation? – sekmo May 13 '17 at 10:25
  • 1
    @sekmo The accessors in these examples return either _class instance variables_, which belong to the class, or _class variables_, which belong to the class hierarchy. They do not return plain _instance variables_ which belong to instances of the class. The terms "instance variable," "class instance varaible," and "class variable" are quite confusing, aren't they? – Wayne Conrad May 13 '17 at 16:03
74

First you must understand that classes are instances too -- instances of the Class class.

Once you understand that, you can understand that a class can have instance variables associated with it just as a regular (read: non-class) object can.

Hello = Class.new

# setting an instance variable on the Hello class
Hello.instance_variable_set(:@var, "good morning!")

# getting an instance variable on the Hello class
Hello.instance_variable_get(:@var) #=> "good morning!"

Note that an instance variable on Hello is completely unrelated to and distinct from an instance variable on an instance of Hello

hello = Hello.new

# setting an instance variable on an instance of Hello
hello.instance_variable_set(:@var, :"bad evening!")

# getting an instance variable on an instance of Hello
hello.instance_variable_get(:@var) #=> "bad evening!")

# see that it's distinct from @var on Hello
Hello.instance_variable_get(:@var) #=> "good morning!"

A class variable on the other hand is a kind of combination of the above two, as it accessible on Hello itself and its instances, as well as on subclasses of Hello and their instances:

HelloChild = Class.new(Hello)
Hello.class_variable_set(:@@class_var, "strange day!")
hello = Hello.new
hello_child = HelloChild.new

Hello.class_variable_get(:@@class_var) #=> "strange day!"
HelloChild.class_variable_get(:@@class_var) #=> "strange day!"
hello.singleton_class.class_variable_get(:@@class_var) #=> "strange day!"
hello_child.singleton_class.class_variable_get(:@@class_Var) #=> "strange day!"

Many people say to avoid class variables because of the strange behaviour above, and recommend the use of class instance variables instead.

horseyguy
  • 29,455
  • 20
  • 103
  • 145
  • 2
    +1 Super Explanation! This is something that every programmer new to Ruby should digest. – TomZ Nov 11 '11 at 15:08
0

Also I want to add that you can get access to the class variable (@@) from any instance of the class

class Foo
  def set_name
    @@name = 'Nik'
  end

  def get_name
    @@name
  end
end


a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => Nik

But you can't do the same for the class instance variable(@)

class Foo
  def set_name
    @name = 'Nik'
  end

  def get_name
    @name
  end
end


a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => nil
Vlad Hilko
  • 1,104
  • 12
  • 17
  • -1: This is incorrect: class instance variables can be accessed from every instance of that class (provided that the accessors are present). Besides, your example shows regular instance variables, not class instance variables. Class instance variables are declared outside of methods, and are fundamentally different from both regular instance variables and class variables. – Pelle Mar 04 '19 at 19:54
  • How can you get access to class instance variables from every instance of that class? – Vlad Hilko Mar 05 '19 at 12:38
  • Have you read Wayne Conrad's answer? That literally explains it. https://stackoverflow.com/a/3803089/439592 – Pelle Mar 08 '19 at 18:47
  • I know you can get access from class methods like `Foo.i`, but how can you do the same for every instance of this class like `Foo.new.i` ? – Vlad Hilko Mar 11 '19 at 09:31
  • By using `#class`. I personally think `#class` usages when called on anything but `self` are code smells though. You can even go a step further and implement instance accessors `i` and `i=` that delegate to their `#class` equivalents, in which case you can do `Foo.new.i`. I don't recommend doing that as it creates a confusing interface, suggesting that you're modifying an object member. – Pelle Mar 21 '19 at 12:14