1

Please help me to understand Class Level Instance Variables.

@@ is a class variable and is an equivalent to instance variable (@) in a class instance.

But what is an instance variable (@) when used on class level? If it puts a definition to class instance then why not to define it in an initializer?

class MyClass
  cattr_reader :class_variable

  def self.new_instance(cv, cliv, iv)
    @@class_variable = cv
    @class_level_instance_variable = cliv
    self.new(iv)
  end

  def initialize(iv)
    @instance_variable = iv
  end

  def use
    puts "class_var=#{self.class.class_variable.inspect}\ninst_var=#{@instance_variable.inspect}\ncliv=#{@class_level_instance_variable.inspect}"
  end
end

c = []
c << MyClass.new_instance(1,2,3)
c[0].use
c << MyClass.new_instance(4,5,6)
c[1].use
c << MyClass.new_instance(7,8,9)
c[2].use

c[0].use
c[1].use
c[2].use
4
  • 2
    When you set instance variable on class level, it becomes class instance variable, which is something slightly different (and not really equivalent) to class variable. More info here: railstips.org/blog/archives/2006/11/18/… Commented Aug 29, 2014 at 9:54
  • @Marek Lipka: so, if I understood right, class level instance variables are fully equivalent to pre-initialized instance level instance variables and if I make multiple class instances in a class method each of these instances becomes initialized with this variable. Commented Aug 29, 2014 at 10:02
  • No, there is no such behavior at all. I only mean class level instance variable is regular instance variable, but bound to the class object (remember in Ruby classes are also objects). Commented Aug 29, 2014 at 10:09
  • @Paul: Why don't you throw in some code to illustrate what you mean? Commented Aug 29, 2014 at 10:17

2 Answers 2

3

Hopefully this example will explain the difference between @ (instance) and @@ (class) variables.

class Animal
  @@total_count = 0

  def self.total_count
    @@total_count
  end

  def initialize
    @@total_count += 1
  end
end

class Cat < Animal
end

Animal.new
Animal.new
Cat.new

Animal.total_count # => 3
Cat.total_count # => 3

As you can see the @@ variable is shared between class and its children. If I really want to count the number of instances of the classes I have to use the following code.

class Animal
  class << self
    attr_accessor :total_count
  end

  @total_count = 0

  def self.total_count
    @total_count
  end

  def initialize
    self.class.total_count += 1
  end
end

class Cat < Animal
  @total_count = 0
end

Animal.new
Animal.new
Cat.new

Animal.total_count # => 2
Cat.total_count # => 1
Sign up to request clarification or add additional context in comments.

Comments

2

In your answer you don't output the class level instance variable. Besides the usual syntax (@foo), an instance variable can be accessed via a method (instance_variable_get(:@foo)). You can use this method to read instance variables of other objects, not only self.

Here's a modified version of your code

require 'active_support/core_ext'

class MyClass
  cattr_reader :class_variable

  def self.new_instance(cv, cliv, iv)
    @@class_variable = cv
    @class_level_instance_variable = cliv
    self.new(iv)
  end

  def initialize(iv)
    @instance_variable = iv
  end

  def use
    puts "class_var=#{self.class.class_variable.inspect}"
    puts "class inst var: #{self.class.instance_variable_get(:@class_level_instance_variable)}"
    puts "inst_var=#{@instance_variable.inspect}"
  end
end

c = []
c << MyClass.new_instance(1,2,3)
c << MyClass.new_instance(4,5,6)
c << MyClass.new_instance(7,8,9)

c[0].use
c[1].use
c[2].use
# >> class_var=7
# >> class inst var: 8
# >> inst_var=3
# >> class_var=7
# >> class inst var: 8
# >> inst_var=6
# >> class_var=7
# >> class inst var: 8
# >> inst_var=9

See, class inst var is always 8 (just as class var is always 7). This is because you output values after all your modifications are made. And since class level variables are shared, the last modification wins.

c << MyClass.new_instance(7,8,9)

If you were to output from initializer (as was in your first version of code), you'd see different results.

# >> class_var=1
# >> class inst var: 2
# >> inst_var=3
# >> class_var=4
# >> class inst var: 5
# >> inst_var=6
# >> class_var=7
# >> class inst var: 8
# >> inst_var=9

2 Comments

So, a class level instance variable gives a way to communicate between children because is passed by reference to each instance. Right?
Yep, it's shared between all instances of the class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.