Mixins and class variables

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

Many thanks in advance.

Brubix

On Dec 16, 9:25 am, Brubix [email protected] wrote:

    def setClassVar(value)
    extend MyModule

@@classVar=class1
self is Class2
@@classVar=class2
classVar for Class1 is class2 # Shouldn’t be class1 ?!
classVar for Class2 is class2

Many thanks in advance.

Brubix

Use Module#class_variable_get/set for this kind of thing.

module MyModule
def self.extended(base)
base.setClassVar(base.name.downcase)
end
def setClassVar(value)
puts “self is #{self.name}”
puts “@@classVar=#{value}”
class_variable_set(:@@classVar, value)
end
def getClassVar
class_variable_get(:@@classVar)
end
end

HTH,
Jordan

On Dec 16, 9:33 am, Brubix [email protected] wrote:

HTH,

Indeed !

No trace of them in my copy of the Pickaxe, so I feel my ignorance
partially excused.

Thanks.

Yeah, the pickaxe is only really a jumping off point. It definitely
is slim on some of the more advanced topics, such as the full power of
mixins and dynamic code.

HTH,

Indeed !

No trace of them in my copy of the Pickaxe, so I feel my ignorance
partially excused.

Thanks.

On Dec 16, 2007, at 10:25 AM, Brubix wrote:

def setClassVar(value)
extend MyModule
@@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 W.

On Dec 16, 2:07 pm, Gary W. [email protected] wrote:

module MyModule
end
puts "classVar for Class2 is " + Class2.getClassVar
to figure out the scoping rules for class variables.

puts A.class_eval { @@cvar } # => NameError, @@cvar undefined

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 W.

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

On Sunday 16 December 2007, Brubix wrote:

I can’t figure out how to set class variables from class methods
inherited from a module ?

Consider if class variables are really what you want.

$ irb

module M
def set(x)
@x = x
end
def get
@x
end
end
=> nil

class C
extend M
end
=> C

C.get
=> nil

C.set(‘bla’)
=> “bla”

C.get
=> “bla”

class D < C; end
=> nil

D.get
=> nil

@x in this case is not a class variable, it is an instance variable of
the singleton class of class C. You’ll find some information on that in
the Pickaxe.

The notable difference compared to class variables proper is that class
variables are shared in the inheritance hierarchy, whereas singleton
class instance variables are not.

$ irb

class C
def self.set(x)
@@x = x
end
def self.get
@@x
end
end
=> nil

C.get
NameError: uninitialized class variable @@x in C
from (irb):6:in `get’
from (irb):9

C.set(‘bla’)
=> “bla”

C.get
=> “bla”

class D < C; end
=> nil

C.get
=> “bla”

D.set(‘foo’)
=> “foo”

C.get
=> “foo”

Michael

On Dec 16, 9:14 pm, Michael S. [email protected] wrote:

Consider if class variables are really what you want.

You are totally right !
It seems that what I wanted was just “instance variables of the
singleton class”.

Nevertheless I found confusing the fact that they have the same sigil
of “true” instance variables (single at) and, even worse (or
better ;-), they don’t get mixed with instance variables with the same
name.

Is there a place where this subject is fully explained (hopefully in
simple terms) ?

Many thanks to all !

Brubix