4
class Counter
   def self.counted_new
      @count = 0 if @count.nil?
      @count += 1
      new
   end

   def self.count
      @count
   end
end

In format, @count looks like a instance variable, but when I load this in "irb"(interface ruby) and type four command code

Counter.counted_new
Counter.count
Counter.counted_new
Counter.count

@count finally became 2! Acting like a class variable

Peter Zhu
  • 1,154
  • 3
  • 15
  • 27

2 Answers2

9

@count is always an instance variable, but it can be an instance variable on a class if it is declared in that context.

In this case, @count is a class instance variable. In other words, by writing @count inside of a class level method you are assigning a variable to that class.

By writing @count inside of a instance method, you are assigning an instance variable that is available in that particular instance only.

If you declare a variable with @@count you get a class variable.

THe main difference between class variables and class instance variables is that class variables are retained in inheritance.

class Foo
  @@klass = "class level variable"
  @klass_instance = "class instance level variable"
end

class Bar < Foo
end


puts Foo.instance_variables.inspect # => [:@klass_instance]
puts Foo.class_variables.inspect  # => [:@@klass]

puts Foo.instance_variable_get(:@klass_instance)
# => "klass instance level variable"
puts Foo.class_variable_get(:@@klass)
# => "class level variable"

# The class variable is inherited, but the class instance variable is not

puts Bar.instance_variables.inspect # => []
puts Bar.class_variables.inspect  # => [:@@klass]

# The @@klass variable is shared between all classes in the downward inheritance chain
# So for example:
Foo.class_variable_set(:@@klass, "foo")
puts Bar.class_variable_get(:@@klass) # => "foo"
Jesper
  • 4,535
  • 2
  • 22
  • 34
  • Can you explain more specific? and can you teach me how to recognize these cases quickly? because it is well know that `@blah` is a instance variable – Peter Zhu Feb 26 '15 at 15:39
  • instance variables are for instances. since you did Counter.count_new you made it on the class not on the instance. So @count is an instance, but in the class. If you would have instantiated an instace like Counter.new.count_new it would be on the instance and not on the class – Nick Ginanto Feb 26 '15 at 15:41
  • nice explanation by Jesper on explaining the difference between *class variables* and *class instance variables* – codingbunny Feb 26 '15 at 15:43
  • 1
    The one other difference between class instance variables and class variables is that class variables are also accessible in instance methods, not just class methods. – Linuxios Feb 26 '15 at 16:19
  • @NickGinanto I find that if I declear a new instance of Counter called `Foo`, then the `@count` instance in `Foo` doesn't share the same data field with the `@count` instance in class. Is it right? – Peter Zhu Feb 26 '15 at 16:27
  • @PeterZhu If you create a new instance of Counter by running `Counter.new`, that counter doesn't have an instance variable `@counter`. That variable is part of the class instance. On the other hand, if you create a class `Foo` that *inherits* from `Counter`, it will share the methods you defined but it won't share the same `@counter` class instance variable, instead it will have its own. – Jesper Feb 27 '15 at 07:26
4

The reason why this works, is because Classes themselves are instances. So the reason your variable behaves like a class variable, is because it's an instance variable of your class.

This is rather confusing for people new to Ruby, and it's also a question whether this is the right behaviour you're programming there. Normally class instances should be declared with double @.

The person here gives a good detailed explanation: Using Instance Variables in Class Methods - Ruby

Community
  • 1
  • 1
codingbunny
  • 3,989
  • 6
  • 29
  • 54