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.