On Saturday 28 November 2009 08:43:30 am Ralph Shnelvar wrote:

> >> But see (3), below.
> >>
> >>
> >>
> >> (3)
> >>     class F
> >>       def sub1
> >>         @@x = 1
> >>       end
> >>     end
> >>
> >>     class G
> >>       self.sub1
> >>         @@x=2
> >>       end
> >>     end
> >>
> >>     # Why?  Didn't the interpreter "see" @@x in class F?
> >>     F.class_variables  # []
> 
> MLK> Probably not, since you haven't called the function yet!
> 
> Didn't the interpreter parse it?
> 
> If I do
>   class X
>     def y
>       xyzzy = 3++
>     end
>   end
> 
> then the interpreter/parser will complain immediately that there was a
> syntax error even though the function method y was not executed.

Yes, syntax errors are caught immediately by parsing. But think of instance 
variables as a hash associated with the object and it might be more clear. For 
example, if you did this:

SomeHash = {}
def foo
  SomeHash[:x] = :y
end

Would you expect SomeHash[:x] to exist just because you defined that method?

Now, I don't know whether instance variables are _actually_ implemented as a 
hash. It might well be something much more efficient, but it behaves like a 
hash, so that makes sense.

Also, consider: The method in question may _never_ be called. Why should Ruby 
bother to create a variable that may never be used? That would be just as 
foolish as implying that SomeHash[:x] exists before foo is called in my 
example above. Sure, you could create it and set it to nil, but that'd be 
pointless.

> In C++, instances have access to the static variables and functions of
> the class.
> 
> They don't inherit it ... but merely have access to it as if they
> inherited it.

Instances indeed get access to class variables associated with that instance, 
but again, class variables behave weirdly. But here's a quick example to help 
clarify things:

SomeClass.new

Would you expect an object created that way to have a 'new' method of its own? 
That is, would this make any sense:

SomeClass.new.new

Similarly, do the methods available at class creation time make any sense in 
an object? For example, when creating a class:

class Foo
  attr_accessor :bar
end

You might think attr_accessor is a keyword. It isn't, it's just a method on 
Class, so it's a class method on Foo.

There is no proper analog to "static functions" in C++, by the way -- they're 
just methods on the class. But again, they aren't included into the instance 
-- you access them on the class, just like you would with any other object.

So let me return to some simple examples that I hope make sense. Let's create 
a counter for the number of instances that have been created.

class Foo
  def self.count
    @count
  end
  def self.increment_count
    @count ||= 0
    @count += 1
  end
end

This should be easy to understand. (If it's not, pretend I defined them 
without self, and see if they make sense.)

Now, go define them, and play with them in irb. You wouldn't create any 
instances of Foo yet, but you can do things like this:

Foo.count
Foo.increment_count
Foo.count
Foo.increment_count
Foo.increment_count
Foo.count

Go try that in irb, and see if the result makes sense.

Now let's move on. Keep the same class above, but add this -- if you're in the 
same irb session, you can just re-open the class:

class Foo
  def initialize
    Foo.increment_count
  end
end

Now our counter should work as expected:

Foo.count
f = Foo.new
Foo.count

It won't tell you how many Foo objects actually exist. It's more a count of 
how many have ever been created.

Also, if you understand this so far, go back to my earlier example that was 
"way over your head" -- see if it makes sense. I'll give you an example -- if 
you have a variable f, which is an instance of class Foo, what is f.class?

And if you're inside the initialize method of f, what is self? And what is 
self.class?

> MLK> (There is a way to call private methods from outside, but I will leave
> MLK> you to find it out on your own.  It's not generally a good thing, and
> MLK> I'm not going to hand you a dangerous tool until you understand when
>  not MLK> to use it.)
> 
> So ... when _can_ I use class_variable_get  ???

You can use it whenever you want. When _should_ you use it?

Like instance_variable_get, it's designed for metaprogramming -- that is, when 
you're trying to access a variable, but its name is dynamic.

I'll give you an example of when instance_variable_get might be used. Remember 
attr_reader? (If not, look it up...)  Now, for speed, attr_reader is defined 
in C, but it can be defined in Ruby. Here's the obvious 'eval' solution:

class Module
  def attr_reader *names
    names.each do |name|
      eval "def #{name}; @#{name}; end"
    end
  end
end

But there are many reasons I dislike eval. Here's the solution I'd prefer:

class Module
  def attr_reader *names
    names.each do |name|
      var_name = :"@#{name}"
      define_method name do
        instance_variable_get var_name
      end
    end
  end
end

I don't expect you to follow every detail here. The use of define_method is an 
advanced topic already. Hopefully, though, the fact that you already know how 
to use attr_reader should give you an idea of how that works.

Also, I don't really expect you to need any of this yet -- attr_reader, 
attr_writer, and attr_accessor should already do everything you need.