Accessing class variables in method made using define_method

I want to use class variables and have them accessible from class
methods that have been defined outside of the class using
define_method or something similar. When I try this the class
variable isn’t in scope. A simple test case is:

class A
@@aa = 20
end

A.class_eval {define_method(:foo){puts @aa}}

a = A.new
a.foo => nil and not 20 as expected

or using

A.send(:define_method, :foo){puts @aa}
a.foo => nil and not 20 as expected

gives the same result but

class A
def foo
puts @@aa
end
end

a.foo => 20 as expected.

How do I get the same behaviour as opening the class and defining the
method normally?

Thanks,

Dave.

On Oct 8, 2007, at 9:16 AM, Dave B. wrote:

class A
Thanks,

Dave.

cfp:~ > cat a.rb
class A; @@aa = 42;end

A.class_eval{ define_method(:foo){ A.send :class_variable_get,
‘@@aa’ } }
p A.new.foo #=> 42

A.send(:define_method, :foo){ A.send :class_variable_get, ‘@@aa’ }
p A.new.foo #=> 42

@@aa = ‘this is what is meant by closure’

A.send(:define_method, :foo){ @@aa }
p A.new.foo #=> ??

cfp:~ > ruby a.rb
42
42
“this is what is meant by closure”

blocks form closures, which is what makes them useful, when you are
defining methods via blocks you need to consider the enclosing scope
as it will be the primary namespace lookup. understanding closures
is step one to metaprogramming bliss.

kind regards.

a @ http://codeforpeople.com/

On 10/8/07, ara.t.howard [email protected] wrote:

On Oct 8, 2007, at 9:16 AM, Dave B. wrote:

I want to use class variables and have them accessible from class
methods that have been defined outside of the class using
define_method or something similar. When I try this the class
variable isn’t in scope. A simple test case is:

class A
@@aa = 20
NOTE @@
end

A.class_eval {define_method(:foo){puts @aa}}

  NOTE @

Another thing, in addition to Ara’s point about the lexical scope of
the closure, the original posting was mixing class variables with
instance variables:

class A
@@aa = 20 # This is a class variable

def aa=
puts @aa # This is a reference to an INSTANCE variable
puts @@aa # This is a reference to a CLASS variable
end
end

There’s no relationship between @aa and @aa, any more that there would
be with aa or $aa

Note that Ruby also has class instance variables:

class A
def cv_aa
@@aa
end

def cv_aa=(val)
@@aa = val
end

def iv_aa=(val)
@aa = val
end

def iv_aa
@aa
end

def self.civ_aa
@aa
end

def self.civ_aa=(val)
@aa = val
end

end

class B < A
def set_cv_aa=(val)
@@aa = val
end
end

a = A.new
a2 = A.new
b = B.new

Instance variable belong to the instance

a.iv_aa = “Hello”
a.iv_aa # => “Hello”
a2.iv_aa # => nil
a2.iv_aa = “Ciao!”
a2.iv_aa # => “Ciao!”
a.iv_aa # => “Hello”
a2.cv_aa = 30
a2.cv_aa # => 30

Class variables are shared

a.cv_aa = 20
a.cv_aa # => 20
a2.cv_aa # => 20
#and with subclasses
b.cv_aa # => 20
b.cv_aa = 30
b.cv_aa # => 30
a.cv_aa # => 30

Class instance variables are instance variables of classes

A.civ_aa = “Classy!”
A.civ_aa # => “Classy!”
B.civ_aa = “Chic!”
B.civ_aa # => “Chic!”
A.civ_aa # => “Classy!”


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

ara.t.howard wrote:

blocks form closures, which is what makes them useful, when you are
defining methods via blocks you need to consider the enclosing scope as
it will be the primary namespace lookup. understanding closures is
step one to metaprogramming bliss.

Careful. Putting @@aa at the top level makes it into a kind of global,
so there’s no need for a closure to access it:

class A; end

@@aa = ‘this is sorta global’
A.class_eval{ define_method(:foo){
A.send :class_variable_get, ‘@@aa’ } }
p A.new.foo # ==> “this is sorta global”
p Object.send(:class_variable_get, “@@aa”)
# ==> “this is sorta global”

It’s global in the sense that @@aa is defined at the root of the class
tree (Object), and class var lookup wanders along this tree towards the
root, until it finds a class with @@aa defined.

An example that works only because class vars are affected by
closures:

class A; @@bb = 3 end
class B
@@bb = “belongs to B, yet visible in closure”
A.send(:define_method, :bar){ @@bb }
end
p A.new.bar
# ==> “belongs to B, yet visible in closure”

begin
p Object.send(:class_variable_get, “@@bb”)
rescue => ex
puts ex
# ==> uninitialized class variable @@bb in Object
end

p A.send(:class_variable_get, “@@bb”) # ==> 3

(Note that the @bb=3 is hidden when inside the scope of class B…end.)

But note that the behavior of instance vars in closures is different:
the lookup rules for @foo are dynamic, based on which object is the self
when the code is executed.

class A; end

@@aa = ‘this is what is meant by closure’
@a = “bar”

A.send(:define_method, :foo){ @@aa }
A.send(:define_method, :bar){ @a }

p A.new.foo # ==> “this is what is meant by closure”
p A.new.bar # ==> nil

It is a good idea to avoid class vars, for the following reason:

class A
@@one_by_this_name = 42
end

class B < A
@@one_by_this_name = 43
@@two_by_this_name = “zap”
end

class A
@@two_by_this_name = “pow”
end

class A
p @@one_by_this_name # == > 43 <-- surprise!
p @@two_by_this_name # == > “pow”
end

class B
p @@one_by_this_name # == > 43
p @@two_by_this_name # == > “zap”
end

The order of assignment determines whether a class and subclass share
the class variable!

On 10/8/07, Joel VanderWerf [email protected] wrote:

The order of assignment determines whether a class and subclass share
the class variable!


vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Yeah I really think one should stay away from @@ brrrr.
However one could use closures after all :wink:
---------------- 8< ----------------
class A
a = 46
(singlton = class << self; self end).
send :define_method, :a do a end
singlton.send :define_method, :a= do |v| a=v end
end

p A.a
A.a -= 4
p A.a

B= Class::new A
p B.a
B.a -= 3
p [A.a, B.a]
----------------------->8 -------------------
But this makes the “variable” shared between class and subclass, that is
not
always what one wants, if we want Smalltalk behavior we might use class
instance
variables
---------------- 8< --------------
class C
@a = 42
class << self
attr_accessor :a
end
end

D = Class::new C

p C.a
p D.a
D.a = “fourtytwo”
p [C.a, D.a]
---------------------- >8 ---------------------
IIRC however there is a subtle difference between ST & Ruby here,
ST seems to copy the value of the superclasses class ivar into the
subclass class ivar or am I wrong, Rick?

HTH
Robert

On 8 Oct 2007, at 17:28, Rick DeNatale wrote:

  @@aa = 20
         NOTE @@

end

A.class_eval {define_method(:foo){puts @aa}}

  NOTE @

Yeah, a typo however the problem I want to solve still exists in that
a method added to a class using define_method doesn’t have the same
scope as a method added using def…end. Both can call other methods
in the class and access instance variables but define_method is
prevented from accessing class variables. This was a surprise to me.

<snipped examples of instance, class and class instance varialbes>

Dave.