MonkeeSage
12/16/2007 8:56:00 PM
On Dec 16, 2:07 pm, Gary Wright <gwtm...@mac.com> wrote:
> On Dec 16, 2007, at 10:25 AM, Brubix wrote:
>
>
>
> > I can't figure out how to set class variables from class methods
> > inherited from a module ?
>
> > The following doesn't work as I expected (I spare you my others
> > pathetic attempts):
>
> > module MyModule
> > def self.extended(base)
> > base.setClassVar(base.name.downcase)
> > end
> > def setClassVar(value)
> > puts "self is #{self.name}"
> > puts "@@classVar=#{value}"
> > @@classVar = value
> > end
> > def getClassVar
> > @@classVar
> > end
> > end
>
> > class Class1
> > extend MyModule
> > end
> > class Class2
> > extend MyModule
> > end
>
> > puts "classVar for Class1 is " + Class1.getClassVar
> > puts "classVar for Class2 is " + Class2.getClassVar
>
> > It gives:
> > self is Class1
> > @@classVar=class1
> > self is Class2
> > @@classVar=class2
> > classVar for Class1 is class2 # Shouldn't be class1 ?!
> > classVar for Class2 is class2
>
> The New Haven Ruby Brigade spent an hour or so one night trying
> to figure out the scoping rules for class variables.
>
> The key to understanding them is to realize that instance variables
> are dynamical scoped relative to self while class variables
> are *lexically* scoped (i.e. the scoping is defined by the
> syntactic structure of the code).
>
> In your example, '@@classvar' is lexically located within MyModule.
> That means it will *always* be associated with MyModule regardless
> of the value of self at the time setClassVar or getClassVar are
> executed.
>
> Here is another situation that illustrates this difference:
>
> class A
> @@cvar = 'class A'
> def cvar
> @@cvar
> end
> end
>
> puts A.new.cvar # => class A
> puts A.class_eval { @@cvar } # => NameError, @@cvar undefined
>
> The class_eval version fails because @@cvar in the block is
> not lexically within the class A/end block. It is *dynamically*
> in the scope of class A, but not lexically within the scope of
> class A. In this case, @@cvar is resolved to the top-level
> scope which is associated with Object.
>
> MonkeeSage's suggestion to use Module#class_variable_get/set
> forces the variables to be resolved relative to the receiver
> and thus bypasses the lexical scoping rules for class variables.
>
> This is another situation where the syntactic similarity of the
> instance variable sigil ("@") and the class variable sigil ("@@")
> causes people to think they behave in the same manner. They don't.
>
> Gary Wright
From the standpoint of intuitiveness, one would also expect that
whatever scoping rules class variables follow, the same would be true
of class methods; but that isn't right either. Of course, class
methods *have to* be dynamically scoped or you couldn't actually call
them (doh!)...but it's still strange to have class methods and class
variables follow different scoping rules.
Regards,
Jordan