On Sep 21, 2007, at 6:53 PM, Got Ascii wrote:

> I spent some time trying to find an answer to this but haven't  
> found an
> explanation I understand.  Could someone tell me what is going on  
> here:
>
> module Mod
>   def self.append_features(base)
>     base.extend ClassMethods
>     super
>   end
>   module ClassMethods
>     def growl
>       puts @@donkey
>     end
>   end
> end
>
> class Animal
>   include Mod
>   @@donkey = "heyhaw"
>
>   def self.working_growl
>     puts @@donkey
>   end
> end
>
> # uninitialized class variable @@donkey in Mod::ClassMethods
> Animal.growl
>
> # works fine
> Animal.working_growl
>
> Now, in my limited understanding calling Animal.extend (or base in  
> this
> case) ClassMethods should have added growl as a class method to  
> Animal,
> equivalent to working_growl in scope (as it turns out self in both
> methods is Animal which confuses me even more).  Clearly this is  
> not the
> case.  Any help would be appreciated.  Thanks!

Class variables are lexically scoped--not dynamically scoped.  This
means that @@donkey as it appears in Mod::ClassMethods#growl is  
associated
with Mod::ClassMethods and not with Animal even after you have
extended Animal and are executing Animal.growl.  Since you have never
assigned a value to Mod::ClassMethods/@@donkey, Ruby complains.

This is very different from instance variables which are dynamically
scoped (i.e. resolved relative to 'self' at the time of execution).

So despite the fact that class variables and instance variables both
use a similar syntactical sigil (@@ vs @), they are scoped in vastly
different ways.

   class variables:  resolved at parse time relative to lexical scope
   instance variables: resolved at execution time relative to 'self'

My advice is to just stay away from class variables entirely.  Simply  
use
class instance variables instead.

Gary Wright