From: MonkeeSage Date: 2007-12-17T06:00:09+09:00 Subject: Re: Mixins and class variables On Dec 16, 2:07 pm, Gary Wright 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