From: David Masover Date: 2009-11-30T18:04:25+09:00 Subject: Re: Class variables, instance variables, singleton; Ruby v. C++ On Monday 30 November 2009 01:43:38 am Ralph Shnelvar wrote: > DAB> This is the so-called "class instance variable", which is really just > DAB> "an instance variable that happens to belong to a Class object". It's > DAB> common to use the phrase "class instance variable", but it's just a > DAB> way of clarifying what you mean. There's no separate "class instance > DAB> variable" language-level construct. > > So ... let's see if I get this. Sorry, I don't remember enough C++ to help you here. > It appears to me that "class" is a jumble of two kinds of very > different semantics. > > There is the notion of a class as a template for instances of the > class. Correct. > Then there is a very different notion of a sorta static class that > has it's own variables that do not propagate to instances; and may > (@@x) or may not (@x) propagate and be accessile to static subclasses > inherited from the static superclass. Well, my advice is to forget that @@x exists at all -- I've never properly understood how it propagates or how to properly manage it, and it seems to be an invitation for disaster. But you're half-right... > A lot to wrap one's head around. I assume that there are good design > reasons to jumble these two concepts together in the semantics of > "class". It's very simple, really: In Ruby, EVERYTHING is an object. You may have seen this cute example before: class Fixnum def + other 5 end end That's right, ordinary integers are just objects, and arithmetic operators are just methods, which can be overridden. And if you type the above into IRB, you can prove that 2+2==5, for very strange definitions of +. But this is the crucial concept: Numbers are objects. True and false are objects. Even null is an object -- the object is called nil, and it is an instance of NilClass. Files are objects. Sockets are objects. Constants are objects. Symbols are objects. EVERYTHING is an object. So, EVERYTHING has the semantics of an object. In addition, everything that's an object is an instance of a class. Or, to put it another way: The number 5 has the semantics of an ordinary integer, but also the semantics of an object. You can prove it to yourself: class Fixnum attr_accessor :message end That's right, numbers can have methods, even instance variables! Type that into IRB and try this: 5.message = 'Hello, world!' 4.message 5.message If you can wrap your head around this concept, it shouldn't surprise you too much that classes are objects, and modules are objects, too. Classes are instance of the class "Class", while modules are instances of the class "Module". So the idea of "static" is really unnecessary baggage in this discussion. If you're looking for something similar, I've already presented one option, but it's not really "static", just like an each loop isn't really a foreach loop. Here's a complete answer to the question "How many objects of type Foo are there?" in the traditional C++ style: class Foo class << self # These are about the Foo class itself, as an object. # Any methods here are methods on the Foo object itself, # not instances of Foo: def count @count ||= 0 end attr_writer :count def finalizer @finalizer ||= lambda do self.count -= 1 end end end # These are instance methods on the Foo class: def initialize self.class.count += 1 ObjectSpace.define_finalizer(self, self.class.finalizer) end end As you can see, finalizers are kind of cumbersome to use (so don't use them, you almost certainly don't need them), but they should work. Whenever the garbage collector finally eats those objects, the count will go down. (You can force the matter by calling GC.start, but that's for debugging purposes only!) Now, what's going on here? Probably the most confusing part is this statement: class << self What is that doing? That's opening what's called the metaclass of an object. Every object has a metaclass, which is easiest to think of like this: When you call Foo.new, you get an object which inherits from a class unique to that object, which in tern inherits from Foo. It's actually not quite like that, but that gives you an idea of what's going on. For example, try this: a = 'foo' def a.bar 5 end If you understand what that does, then this does the exact same thing: a = 'foo' class << a def bar 5 end end Now, what is self inside the Foo class? It's the Foo object itself. The simplest way to explain what all that code is doing is to remember that I was just using Foo as an object because it seemed a convenient place to store values common to all Foos. I could just as easily have done this (for the non- finalized version): class Foo Count = 0 def initialize Count += 1 end end It'll whine because I'm reassigning constants, but you see the point. I mean, I could also do this: FooCount = 0 class Foo def initialize FooCount += 1 end end It's just that the Foo object is already there, and makes sense for this purpose. Also, if you haven't seen this before, don't let it frighten you: @count ||= 0 That's providing a default value for @count. When you execute that code, it checks whether @count has a positive value -- if it doesn't, it assigns 0 to @count. Either way, the (possibly new) value of @count will be returned. So regarding your musings as to whether there's a good design reason, I'd argue yes and no. No, it really doesn't seem good design, at first glance, that numbers can have instance variables, because why would that ever, ever, be a good idea? But yes, it actually gives a nice uniform model. Again, EVERYTHING is an object, so EVERYTHING has methods, instance variables, a metaclass, and so on.