1

class variable works like this:

class Hello
  @@x = 0

  def self.counter
   @@x
  end

  def initialize
    @@x += 1
  end  
end

Hello.new
Hello.new
Hello.new
p Hello.counter
#=> 3

but class instance variable doesn't:

class Goodbye
  @x = 0

  def self.counter
   @x
  end

  def initialize
    @x += 1
  end  
end

Goodbye.new
Goodbye.new
Goodbye.new
Goodbye.new
p Goodbye.counter
#=> Error

What am I doing wrong ? I was under impression that class instance variables are same as class variables, just without inheritance problem ... but how do you use them (for example, to count instances of specific class like in code I posted here) ?

OldBoy
  • 110
  • 1
  • 8
  • possible duplicate of [Difference between class variables and class instance variables?](http://stackoverflow.com/questions/3802540/difference-between-class-variables-and-class-instance-variables) – Roman Kiselenko Sep 28 '14 at 09:51
  • there is no explanation why code with @@x work, and same code with @x doesn't (which is why I asked this question) – OldBoy Sep 28 '14 at 09:56
  • question about `why isn't this code working` off-topic on SO. – Roman Kiselenko Sep 28 '14 at 09:58
  • that's why I put in my title "proper usage" ... I know what class instance variables are, but I don't know how to use them properly. Code is just example – OldBoy Sep 28 '14 at 10:03
  • you should read documentation or find some blog post or find questions in SO about it, SO help people solve problem with code, any expanation already exists in documentation and web. – Roman Kiselenko Sep 28 '14 at 10:06
  • 1
    Hint: what is `self` inside initialize? I.e. what instance is `@x` an instance variable of inside `initialize`? – Jörg W Mittag Sep 28 '14 at 11:02
  • ah, I see ... program thinks @x belongs to instances of the class Goodbye. That makes sense. I changed "@x+=1" to "Goodbye.x+=1" and added appropriate attribute accessor and it works. It looks ugly, and there is more code than I wanted, but it works. Thank you ! – OldBoy Sep 28 '14 at 11:22

1 Answers1

1

Instance variables belong to objects (instances), that's why they are called that. In lines 2 and 5, @x belongs to the object Goodbye, but in line 9, @x belongs to an instance of Goodbye. You never initialize this instance variable, and uninitialized instance variables evaluate to nil, nil doesn't have a + method, ergo you get a NoMethodError.

Note that Goodbye.counter does not raise an error like you claim, it simply returns 0. The error is raised inside initialize.

Here's the trivial fix:

class Goodbye
  @x = 0

  def self.counter
   @x
  end

  def self.new
    @x += 1
    super
  end  
end

Goodbye.new
Goodbye.new
Goodbye.new
Goodbye.new
p Goodbye.counter
#=> 4
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • Also, it works with simple changes to my original faulty example, you need to add: "class << self attr_accessor :x; end" at the beginnig of a class, and change "def initialize Goodbye.x += 1; end". Thank you for your explanations! – OldBoy Sep 28 '14 at 11:35