Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Class Variables in EigenClass

Reply
Thread Tools

Class Variables in EigenClass

 
 
JP Billaud
Guest
Posts: n/a
 
      03-07-2011
I am using Ruby 1.8.7 and I bumped into a weird behavior regarding
eigenclass of Class object.

Below, I am declaring a class variable inside the eigenclass of Class A.
However for some reasons when I print out the class variables of A and
B, it seems the class variable @@test is accessible for both.

===

def eigen
class << self
self
end
end

class A
end

class B
end

egA = A.send :eigen
puts egA.object_id

egB = B.send :eigen
puts egB.object_id

egA.class_eval do
@@test = 5
end

puts "A Class Variables"
puts A.class_variables

puts "B Class Variables"
puts B.class_variables

===


>-607970628
>-607970668
>A Class Variables
>@@test
>B Class Variables
>@@test


Any idea?

Thanks,

--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
JP Billaud
Guest
Posts: n/a
 
      03-07-2011
Actually it seems that for some reasons the @@test class variables ended
up in the Object class:

puts Object.class_variables
> @@test


Anyway I am still confused about this... Help would very appreciated.

Thanks,

--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
Gary Wright
Guest
Posts: n/a
 
      03-07-2011

On Mar 6, 2011, at 7:55 PM, JP Billaud wrote:

> Actually it seems that for some reasons the @@test class variables =

ended=20
> up in the Object class:
>=20
> puts Object.class_variables
>> @@test

>=20
> Anyway I am still confused about this... Help would very appreciated.


The snarky answer is: "Don't use class variables". They really are hard =
to understand and generally don't have the semantics you expect or need.

The non-snarky answer is that when you do:

egA.class_eval do
@@test =3D 5
end

Ruby does *not* evaluate '@@test' relative to self, which would be egA, =
but instead evaluates it relative to the lexical scope that is in =
effect, which in your code is the top level scope. Class variables =
evaluated at the top level scope are instantiated within Object.

Most people expect class variables to only be visible to the class they =
are instantiated in but they are actually visible to their 'home' class =
as well as all subclasses. Since every class is a subclass of Object, =
in your example, @@test becomes visible in every class and in every =
instance.

Gary Wright=

 
Reply With Quote
 
JP Billaud
Guest
Posts: n/a
 
      03-07-2011
Thanks Gary for the explanation. I was hoping the self logic would have
applied in this case since I feel this is the intuitive way to think
about it...

Another question about class variables actually. My understanding of
class variables lookup is that it is not different from the methods
lookup. Indeed, an instance object look at its class's class variables
and then go through superclass and module all the way up to BasicObject.

Now why does not it apply to Classes object:

===
class Class
@@test = "test"
end

class B
def self.print
puts @@test
end
end

B.print
===

In this case B.print fails with:

module.rb:7:in `print': uninitialized class variable @@test in B
(NameError)
from module.rb:11

Since B's class is Class that should be fine. Obviously I must be
missing something here.

Thanks,
Jean-Pascal Billaud

--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Gary Wright
Guest
Posts: n/a
 
      03-07-2011

On Mar 6, 2011, at 11:04 PM, JP Billaud wrote:
> Another question about class variables actually. My understanding of=20=


> class variables lookup is that it is not different from the methods=20
> lookup.


They are not the same and are closer to the way constants are looked up =
but not quite the same as that either...

> Indeed, an instance object look at its class's class variables=20
> and then go through superclass and module all the way up to =

BasicObject.

Not really, the lookup is more accurately associated with the lexical =
context of the reference than the dynamic context. In your B.print =
method, the lexical scope is actually the class B and so that is the =
starting point for the class variable resolution. This is distinctly =
different than the way instance variables are resolved.

> Now why does not it apply to Classes object:
>=20
> =3D=3D=3D
> class Class
> @@test =3D "test"
> end
>=20
> class B
> def self.print
> puts @@test
> end
> end
>=20
> B.print
> =3D=3D=3D
>=20
> In this case B.print fails with:
>=20
> module.rb:7:in `print': uninitialized class variable @@test in B=20
> (NameError)
> from module.rb:11
>=20
> Since B's class is Class that should be fine. Obviously I must be=20
> missing something here.



Consider the following:

class A
@@foo =3D "hello"
def foo
@@foo
end
def foo_ieval
42.instance_eval { @@foo }
end
def foo_ceval
Array.class_eval { @@foo }
end
end


puts A.new.foo # "hello"
puts A.new.foo_ieval # "hello"
puts A.new.foo_ceval # "hello"

Array.class_eval { @@foo } # undefined

The lexical scope for foo, foo_ieval, and foo_ceval is the enclosing =
class/end block for A while the lexical scope for the final =
Array.class_eval is the top level. For the three methods, they all =
resolve to the same class variable owned by the class A while the =
class_eval outside of A's definition block resolves to the top level =
class, Object.

Gary Wright=

 
Reply With Quote
 
JP Billaud
Guest
Posts: n/a
 
      03-09-2011
Alright that explains the situation even though I feel that the dynamic
context should apply in this case since class_eval changes self and the
current class. IMO lexical scope should only be useful for local
variables...

--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
John Mair
Guest
Posts: n/a
 
      03-10-2011
Hey,

While what you've said is true for `class_eval` contexts (that they
behave like constants) it doesn't explain the following behaviour, which
the OP may or may not have been getting at:

class C; end

c = C.new

class << c
@@var = 20
end

#=> Warning: class variable access from toplevel singleton method

It appears that the class var is defined on Object. In fact it's working
lexically here too:

$c = C.new

module J
class << $c; @@var = 30; end
end

J.instance_variables #=> [:@@var]

Pretty weird

Gary Wright wrote in post #985860:
> On Mar 6, 2011, at 7:55 PM, JP Billaud wrote:
>
>> Actually it seems that for some reasons the @@test class variables ended
>> up in the Object class:
>>
>> puts Object.class_variables
>>> @@test

>>
>> Anyway I am still confused about this... Help would very appreciated.

>
> The snarky answer is: "Don't use class variables". They really are hard
> to understand and generally don't have the semantics you expect or need.
>
> The non-snarky answer is that when you do:
>
> egA.class_eval do
> @@test = 5
> end
>
> Ruby does *not* evaluate '@@test' relative to self, which would be egA,
> but instead evaluates it relative to the lexical scope that is in
> effect, which in your code is the top level scope. Class variables
> evaluated at the top level scope are instantiated within Object.
>
> Most people expect class variables to only be visible to the class they
> are instantiated in but they are actually visible to their 'home' class
> as well as all subclasses. Since every class is a subclass of Object,
> in your example, @@test becomes visible in every class and in every
> instance.
>
> Gary Wright


--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Gary Wright
Guest
Posts: n/a
 
      03-10-2011

On Mar 9, 2011, at 7:55 PM, John Mair wrote:
> While what you've said is true for `class_eval` contexts (that they=20
> behave like constants) it doesn't explain the following behaviour, =

which=20
> the OP may or may not have been getting at:


I think you just restated the same thing I said.

One thing that you emphasized and which is confusing is that the =
singleton class notation:

class <<object
end

does *not* create a new lexical scope - nor does class_eval or =
instance_eval.

Because there is no new lexical scope from these constructs the =
interpretation of class variables doesn't change when these constructs =
are used, and that is generally not what is expected.

Gary Wright


 
Reply With Quote
 
John Mair
Guest
Posts: n/a
 
      03-22-2011
> One thing that you emphasized and which is confusing is that the
> singleton class notation:
>
> class <<object
> end
>
> does *not* create a new lexical scope - nor does class_eval or
> instance_eval.
>


No, it *does* create a new lexical scope -- did you test it ?

o = Object.new
j = 10

class << o
puts j
end

NameError: undefined local variable or method `j'

This was the point of my post -- that you can't simply use the 'lexical
scope' argument (as you can with class_eval); that this is a genuine
quirk of class variables in ruby

--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Gary Wright
Guest
Posts: n/a
 
      03-22-2011

On Mar 22, 2011, at 1:23 AM, John Mair wrote:

>> One thing that you emphasized and which is confusing is that the
>> singleton class notation:
>>
>> class <<object
>> end
>>
>> does *not* create a new lexical scope - nor does class_eval or
>> instance_eval.
>>

>
> No, it *does* create a new lexical scope -- did you test it ?
>
> o = Object.new
> j = 10
>
> class << o
> puts j
> end


I think it was my sloppy terminology that was confusing. My intent was that the phrase 'lexical scope' would refer to the scope that was relevant to constant and class variable resolution. As you've pointed out, that phrase just is not specific enough as there is a lexical scope created for local variables by the singleton class notation (and blocks). So there are at least two different types of lexical scopes that affect name resolution of variables and constants. I'm not sure if there is any standard terminology used to differentiate them. Perhaps that is part of the confusion.

Gary Wright

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Singleton class, metaclass, eigenclass: what do they mean? Tony Arcieri Ruby 28 01-27-2011 01:15 PM
Superclass of eigenclass in 1.8.6 Paolo Nusco Perrotta Ruby 0 04-16-2007 09:50 PM
mini-contest: eigenclass.org "Happy 2007!" Ruby challenge (2007-01-06 20H UTC) Mauricio Fernandez Ruby 0 01-05-2007 12:51 PM
Defining Eigenclass Matt Todd Ruby 20 08-13-2006 04:57 AM
Alternate notation for eigenclass Trans Ruby 19 03-15-2006 02:09 PM



Advertisments