[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Accessing class variables in method made using define_method

Dave Baldwin

10/8/2007 3:16:00 PM

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.





5 Answers

ara.t.howard

10/8/2007 3:37:00 PM

0


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.


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://codeforp...
--
share your knowledge. it's a way to achieve immortality.
h.h. the 14th dalai lama



Rick DeNatale

10/8/2007 4:29:00 PM

0

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 @

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

Joel VanderWerf

10/8/2007 5:42:00 PM

0

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

Dave Baldwin

10/9/2007 7:40:00 AM

0


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 @

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.


Robert Dober

10/9/2007 8:53:00 AM

0

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