Class Variables in EigenClass

Discussion in 'Ruby' started by JP Billaud, Mar 7, 2011.

  1. JP Billaud

    JP Billaud Guest

    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/.
    JP Billaud, Mar 7, 2011
    #1
    1. Advertising

  2. JP Billaud

    JP Billaud Guest

    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/.
    JP Billaud, Mar 7, 2011
    #2
    1. Advertising

  3. JP Billaud

    Gary Wright Guest

    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=
    Gary Wright, Mar 7, 2011
    #3
  4. JP Billaud

    JP Billaud Guest

    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/.
    JP Billaud, Mar 7, 2011
    #4
  5. JP Billaud

    Gary Wright Guest

    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=
    Gary Wright, Mar 7, 2011
    #5
  6. JP Billaud

    JP Billaud Guest

    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/.
    JP Billaud, Mar 9, 2011
    #6
  7. JP Billaud

    John Mair Guest

    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 #=> [:mad:@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/.
    John Mair, Mar 10, 2011
    #7
  8. JP Billaud

    Gary Wright Guest

    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
    Gary Wright, Mar 10, 2011
    #8
  9. JP Billaud

    John Mair Guest

    > 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/.
    John Mair, Mar 22, 2011
    #9
  10. JP Billaud

    Gary Wright Guest

    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
    Gary Wright, Mar 22, 2011
    #10
  11. JP Billaud

    Sony S. Guest

    Jean-Pascal Billaud wrote in post #985843:
    > Any idea?
    >
    > Thanks,


    You can use class_variable_set:

    def eigen
    class << self
    self
    end
    end

    class A
    end

    class B
    end

    egA = A.send :eigen
    puts egA.object_id

    class A
    @@in_A = 'A'
    end

    egA.send:)class_variable_set, :mad:@in_egA, 'egA') # The secret!

    puts "A Class Variables"
    puts A.class_variables #=> @@in_A

    puts "egA Class Variables"
    puts egA.class_variables #=> @@in_egA

    puts "B Class Variables"
    puts B.class_variables #=> empty

    --
    Posted via http://www.ruby-forum.com/.
    Sony S., Mar 23, 2011
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Trans
    Replies:
    19
    Views:
    177
    Trans
    Mar 15, 2006
  2. Matt Todd

    Defining Eigenclass

    Matt Todd, Aug 11, 2006, in forum: Ruby
    Replies:
    20
    Views:
    324
    Logan Capaldo
    Aug 13, 2006
  3. Mauricio Fernandez
    Replies:
    0
    Views:
    168
    Mauricio Fernandez
    Jan 5, 2007
  4. Paolo Nusco Perrotta

    Superclass of eigenclass in 1.8.6

    Paolo Nusco Perrotta, Apr 16, 2007, in forum: Ruby
    Replies:
    0
    Views:
    90
    Paolo Nusco Perrotta
    Apr 16, 2007
  5. Tony Arcieri
    Replies:
    28
    Views:
    359
    Benoit Daloze
    Jan 27, 2011
Loading...

Share This Page