Difference between class variables and class instance variables?
Asked Answered
U

3

97

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

Unijugate answered 27/9, 2010 at 9:32 Comment(0)
I
162

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
Individuality answered 27/9, 2010 at 10:48 Comment(2)
Why return instance variables using class methods? Do you often run into this situation?Inchoation
@Inchoation 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?Individuality
P
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.

Pamper answered 27/9, 2010 at 10:54 Comment(1)
+1 Super Explanation! This is something that every programmer new to Ruby should digest.Rathskeller
H
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
Hangout answered 15/1, 2019 at 8:52 Comment(5)
-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.Waki
How can you get access to class instance variables from every instance of that class?Hangout
Have you read Wayne Conrad's answer? That literally explains it. https://mcmap.net/q/217208/-difference-between-class-variables-and-class-instance-variablesWaki
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 ?Hangout
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.Waki

© 2022 - 2024 — McMap. All rights reserved.