Class Variable Confusion

Discussion in 'Ruby' started by gwtmp01@mac.com, Dec 21, 2006.

  1. Guest

    I generally avoid class variables but at the last meeting of the New
    Haven Ruby Brigade a simple question about them led to a long
    discussion and irb session that only served to confuse us all more.

    I'm hoping someone on the list can shed some light on a couple of
    issues that were raised:

    >> class A
    >> @@avar = 'hello'
    >> end

    => "hello"
    >> A.class_variables

    => ["@@avar"]
    >> A.class_eval { puts @@avar }

    NameError: uninitialized class variable @@avar in Object
    from (irb):5
    from (irb):5
    >> class A
    >> puts @@avar
    >> end

    hello
    => nil
    >> class A
    >> def get_avar
    >> @@avar
    >> end
    >> end

    => nil
    >> a = A.new

    => #<A:0x4ba360>
    >> a.get_avar

    => "hello"
    >> a.instance_eval { puts @@avar }

    NameError: uninitialized class variable @@avar in Object
    from (irb):16
    from (irb):16
    >>



    It seems like a block evaluated by class_eval should have access to
    the class variables. Similarly, it seems like if an instance method
    (get_avar in the example) has access to the class variable then the
    variable should also be visible via instance_eval.

    In both examples above (class_eval and instance_eval) it seems like
    the class variable @@avar is being looked up relative to the
    top_level object and not relative to the class and instance objects
    respectively.


    What am I missing?

    Gary Wright
     
    , Dec 21, 2006
    #1
    1. Advertising

  2. Guest

    Hi --

    On Fri, 22 Dec 2006, wrote:

    > I generally avoid class variables but at the last meeting of the New Haven
    > Ruby Brigade a simple question about them led to a long discussion and irb
    > session that only served to confuse us all more.
    >
    > I'm hoping someone on the list can shed some light on a couple of issues that
    > were raised:
    >
    >>> class A
    >>> @@avar = 'hello'
    >>> end

    > => "hello"
    >>> A.class_variables

    > => ["@@avar"]
    >>> A.class_eval { puts @@avar }

    > NameError: uninitialized class variable @@avar in Object
    > from (irb):5
    > from (irb):5
    >>> class A
    >>> puts @@avar
    >>> end

    > hello
    > => nil
    >>> class A
    >>> def get_avar
    >>> @@avar
    >>> end
    >>> end

    > => nil
    >>> a = A.new

    > => #<A:0x4ba360>
    >>> a.get_avar

    > => "hello"
    >>> a.instance_eval { puts @@avar }

    > NameError: uninitialized class variable @@avar in Object
    > from (irb):16
    > from (irb):16
    >>>

    >
    >
    > It seems like a block evaluated by class_eval should have access to the
    > class variables. Similarly, it seems like if an instance method (get_avar in
    > the example) has access to the class variable then the variable should also
    > be visible via instance_eval.
    >
    > In both examples above (class_eval and instance_eval) it seems like the
    > class variable @@avar is being looked up relative to the top_level object
    > and not relative to the class and instance objects respectively.
    >
    >
    > What am I missing?


    You had me at "I generally avoid class variables" :)

    Here's another one you'll like:

    @@avar = 1
    class A
    @@avar = "hello"
    end
    puts @@avar # => hello

    A.class_eval { puts @@avar } # => hello

    I love Ruby madly, but (or "therefore"? :) I would be happy never to
    see another class variable again. The confusingness-to-usefulness
    ratio is extremely high.


    David

    --
    Q. What's a good holiday present for the serious Rails developer?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    aka The Ruby book for Rails developers!
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
     
    , Dec 21, 2006
    #2
    1. Advertising

  3. On 12/21/06, Chunyun Zhao <> wrote:
    > Seems it works perfectly fine when evaluating the string instead of block:
    >
    > class A
    > @@avar = "hello"
    > end
    >
    > A.class_eval("puts @@avar") # => hello
    > A.class_eval { puts @@avar } #=> throws NameError
    >
    > Very interestsing, anyone could explain it?


    Since the block acts as a closure, the class variable references seem
    to be bound to its original scope; iirc, the only variable types that
    will change scope in the context of a class_eval (which changes the
    value of 'self') are instance variables. That's why the string will
    evaluate correctly, while the block fails to find the class variable.

    I'm not an expert, but this has been my experience.

    Dave

    >
    > On 12/21/06, <> wrote:
    > >
    > > Hi --
    > >
    > > On Fri, 22 Dec 2006, wrote:
    > >
    > > > I generally avoid class variables but at the last meeting of the New

    > > Haven
    > > > Ruby Brigade a simple question about them led to a long discussion and

    > > irb
    > > > session that only served to confuse us all more.
    > > >
    > > > I'm hoping someone on the list can shed some light on a couple of issues

    > > that
    > > > were raised:
    > > >
    > > >>> class A
    > > >>> @@avar = 'hello'
    > > >>> end
    > > > => "hello"
    > > >>> A.class_variables
    > > > => ["@@avar"]
    > > >>> A.class_eval { puts @@avar }
    > > > NameError: uninitialized class variable @@avar in Object
    > > > from (irb):5
    > > > from (irb):5
    > > >>> class A
    > > >>> puts @@avar
    > > >>> end
    > > > hello
    > > > => nil
    > > >>> class A
    > > >>> def get_avar
    > > >>> @@avar
    > > >>> end
    > > >>> end
    > > > => nil
    > > >>> a = A.new
    > > > => #<A:0x4ba360>
    > > >>> a.get_avar
    > > > => "hello"
    > > >>> a.instance_eval { puts @@avar }
    > > > NameError: uninitialized class variable @@avar in Object
    > > > from (irb):16
    > > > from (irb):16
    > > >>>
    > > >
    > > >
    > > > It seems like a block evaluated by class_eval should have access to the
    > > > class variables. Similarly, it seems like if an instance

    > > method (get_avar in
    > > > the example) has access to the class variable then the variable should

    > > also
    > > > be visible via instance_eval.
    > > >
    > > > In both examples above (class_eval and instance_eval) it seems like the
    > > > class variable @@avar is being looked up relative to the top_level

    > > object
    > > > and not relative to the class and instance objects respectively.
    > > >
    > > >
    > > > What am I missing?

    > >
    > > You had me at "I generally avoid class variables" :)
    > >
    > > Here's another one you'll like:
    > >
    > > @@avar = 1
    > > class A
    > > @@avar = "hello"
    > > end
    > > puts @@avar # => hello
    > >
    > > A.class_eval { puts @@avar } # => hello
    > >
    > > I love Ruby madly, but (or "therefore"? :) I would be happy never to
    > > see another class variable again. The confusingness-to-usefulness
    > > ratio is extremely high.
    > >
    > >
    > > David
    > >
    > > --
    > > Q. What's a good holiday present for the serious Rails developer?
    > > A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    > > aka The Ruby book for Rails developers!
    > > Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    > > A. Ruby Power and Light, LLC (http://www.rubypal.com)
    > >
    > >

    >
    >



    --
    Dave Goodlad
    or
    http://david.goodlad.ca/
     
    David Goodlad, Dec 21, 2006
    #3
  4. Guest

    On Dec 21, 2006, at 4:44 PM, wrote:
    > Here's another one you'll like:
    >
    > @@avar = 1
    > class A
    > @@avar = "hello"
    > end
    > puts @@avar # => hello
    >
    > A.class_eval { puts @@avar } # => hello


    Let's see if I understand what is going on:

    When @@var is set to 1 at the top-level it is associated with the
    class Object (a feature of the top-level context) and as such @@var
    then becomes visible to the entire class hierarchy rooted at Object
    (i.e., all objects). When @@avar is evaluated in the class A block,
    Ruby finds @@var already defined for the hierarchy (because A is a
    subclass of Object). So in this example all three occurrences of
    @@avar are associated with the same class variable. If you reverse
    the assignments:

    class A
    @@avar = "hello"
    end
    @@avar = 1

    A.class_eval { puts @@avar } # => 1
    class A
    puts @@avar # => hello
    end

    There are now two distinct class variables named @@avar, one is
    associated with Object and another is associated with class A and
    shadows the one associated with Object.

    I still don't understand why class_eval/instance_eval don't affect
    the resolution of class variables in a manner analogous to how they
    affect the resolution of instance variables. Is this by design or
    accident?


    Gary Wright
     
    , Dec 22, 2006
    #4
  5. Guest

    Hi --

    On Fri, 22 Dec 2006, wrote:

    > class A
    > @@avar = "hello"
    > end
    > @@avar = 1
    >
    > A.class_eval { puts @@avar } # => 1
    > class A
    > puts @@avar # => hello
    > end
    >
    > There are now two distinct class variables named @@avar, one is associated
    > with Object and another is associated with class A and shadows the one
    > associated with Object.


    Yes -- basically, if you create the class variable in the subclass
    first, then it's different from the one in the superclass. Mind you,
    a lot of this is scheduled to change in 2.0. I fear, though that the
    confusion caused by class variables will persist. A class variable is
    going to be (as I understand it) more similar to an instance variable
    than it is now, but with visibility to instances of the class. A lot
    of the problem with class variables is that they cloud the matter of
    classes being objects and having their own instance variables. I'm
    not sure whether these changes will change that.

    (When I say they cloud it, I'm basing this on six years of watching
    person after person after person have trouble grasping this area of
    Ruby, and it's always something like, "Wait -- doesn't a class have
    *class* variables? If they're analogous to instance variables for
    instances, then what are they?" It can be explained, of course (I've
    done it many times :) but there's definitely something in the
    behavior that makes this harder to get than most other language
    features.)

    > I still don't understand why class_eval/instance_eval don't affect the
    > resolution of class variables in a manner analogous to how they affect the
    > resolution of instance variables. Is this by design or accident?


    See David Goodlad's explanation; I think it's by design. class_eval
    brings about a scope that's like a 'class' block in some ways but not
    in others. The surrounding class and local variables can permeate
    their way in.


    David

    --
    Q. What's a good holiday present for the serious Rails developer?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    aka The Ruby book for Rails developers!
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
     
    , Dec 22, 2006
    #5
  6. wrote:
    > You had me at "I generally avoid class variables" :)
    > ...snip...
    > I love Ruby madly, but (or "therefore"? :) I would be happy never to
    > see another class variable again. The confusingness-to-usefulness
    > ratio is extremely high.


    David and gang, thanks for pulling me out of denial.

    [Here's a blog post about my facing reality, finally:
    http://rob.muhlestein.net/2007/01/ruby-class-variables-just-dont-go-there.html]

    Rob
     
    Rob Muhlestein, Jan 5, 2007
    #6
  7. On 12/21/06, <> wrote:

    > You had me at "I generally avoid class variables" :)
    >
    > Here's another one you'll like:
    >
    > @@avar = 1
    > class A
    > @@avar = "hello"
    > end
    > puts @@avar # => hello
    >
    > A.class_eval { puts @@avar } # => hello
    >
    > I love Ruby madly, but (or "therefore"? :) I would be happy never to
    > see another class variable again. The confusingness-to-usefulness
    > ratio is extremely high.


    Wow David, that is scary.
     
    Gregory Brown, Jan 5, 2007
    #7
  8. Rob Muhlestein wrote:
    > wrote:
    > > You had me at "I generally avoid class variables" :)
    > > ...snip...
    > > I love Ruby madly, but (or "therefore"? :) I would be happy never to
    > > see another class variable again. The confusingness-to-usefulness
    > > ratio is extremely high.

    >
    > David and gang, thanks for pulling me out of denial.
    >
    > [Here's a blog post about my facing reality, finally:
    > http://rob.muhlestein.net/2007/01/ruby-class-variables-just-dont-go-there.html]


    After reading the comments in the response it is probably worth
    mentioning in this thread that class *variable* scope inheritance is
    changing between 1.8 and 1.9/2.0 (as noted in the pickax). I ran an irb
    confirmation of this and posted results there to make sure.
     
    Rob Muhlestein, Jan 5, 2007
    #8
  9. On 1/5/07, Rob Muhlestein <> wrote:
    > wrote:
    > > You had me at "I generally avoid class variables" :)
    > > ...snip...
    > > I love Ruby madly, but (or "therefore"? :) I would be happy never to
    > > see another class variable again. The confusingness-to-usefulness
    > > ratio is extremely high.

    >
    > David and gang, thanks for pulling me out of denial.
    >
    > [Here's a blog post about my facing reality, finally:
    > http://rob.muhlestein.net/2007/01/ruby-class-variables-just-dont-go-there.html]


    I blogged it too, though mine is mostly just a quick paste of the two
    bits of code from David and Gary, and a link to your blog entry. My
    NubyGems series is usually like that, a big chunk of code from an IRB
    session meant to make people go 'whoa, yeah, that does suck'

    http://www.oreillynet.com/ruby/blog/2007/01/nubygems_dont_use_class_variab_1.html
     
    Gregory Brown, Jan 5, 2007
    #9
  10. Brock Lee Guest

    So, would it be fair to say that you won't run into difficulties with
    class variables (denoted with @@) if:

    a. you assign class variables in the superclass before assigning
    them in the sublcass, and
    b. you don't expect class_eval to provide access to them?

    Or are there other areas of confusion?

    Thanks,

    Brock
     
    Brock Lee, Jan 5, 2007
    #10
  11. Guest

    Hi --

    On Sat, 6 Jan 2007, Brock Lee wrote:

    > So, would it be fair to say that you won't run into difficulties with
    > class variables (denoted with @@) if:
    >
    > a. you assign class variables in the superclass before assigning
    > them in the sublcass, and


    Assuming you understand that when you assign them in the subclass,
    you're assigning to the exact same variable, throughout the hierarchy.

    > b. you don't expect class_eval to provide access to them?
    >
    > Or are there other areas of confusion?


    The most important lesson to learn about class variables, I believe,
    is that they have *nothing* to do with instance variables. They're
    not a replacement for them; they're not the equivalent for classes
    (instance variables exist for classes); and the @/@@ thing is purely
    cosmetic.

    The reason I say this is that most of the confusion I've seen over the
    years has to do with class variables getting in the way of
    understanding instance variables, since they lead people to assume
    that the idea of a class having an instance variable is meaningless
    (since there are already class variables...). That, in turn, makes it
    much harder to understand instance variables.


    David

    --
    Q. What is THE Ruby book for Rails developers?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
     
    , Jan 5, 2007
    #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. E11
    Replies:
    1
    Views:
    4,942
    Thomas Weidenfeller
    Oct 12, 2005
  2. Variable length array confusion

    , Sep 29, 2003, in forum: C Programming
    Replies:
    5
    Views:
    375
    -berlin.de
    Oct 3, 2003
  3. wanwan
    Replies:
    3
    Views:
    453
    Alex Martelli
    Oct 14, 2005
  4. gyro
    Replies:
    1
    Views:
    253
    Diez B. Roggisch
    Feb 14, 2009
  5. Keith Salisbury

    Class variable confusion

    Keith Salisbury, Apr 23, 2009, in forum: Ruby
    Replies:
    5
    Views:
    126
    Rob Biedenharn
    Apr 23, 2009
Loading...

Share This Page