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.

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
"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 Oct 8, 2007, at 9:16 AM, Dave Baldwin 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
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.

--
share your knowledge. it's a way to achieve immortality.
h.h. the 14th dalai lama

> 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!"

···

On 10/8/07, ara.t.howard <ara.t.howard@gmail.com> wrote:

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

--
Rick DeNatale

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

ara.t.howard wrote:

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

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!

···

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

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.

···

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

On 10/8/07, ara.t.howard <ara.t.howard@gmail.com> wrote:

On Oct 8, 2007, at 9:16 AM, Dave Baldwin 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 @

<snip>

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 10/8/07, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/