Class instance variable idiom

Discussion in 'Ruby' started by Perry Smith, Oct 17, 2007.

  1. Perry Smith

    Perry Smith Guest

    I am using this technique for class instance variables:

    class << self
    def set_foo(s)
    @foo = s
    end
    alias :foo= :set_foo

    def foo
    @foo
    end
    end

    Then to reference foo from an instance of the class (or subclass), I do:

    self.class.foo

    Is there a cleaner way, in particular for the reference of the class
    instance variable, to do this?

    Thank you,
    pedz
    --
    Posted via http://www.ruby-forum.com/.
    Perry Smith, Oct 17, 2007
    #1
    1. Advertising

  2. On 17.10.2007 22:10, Perry Smith wrote:
    > I am using this technique for class instance variables:
    >
    > class << self
    > def set_foo(s)
    > @foo = s
    > end
    > alias :foo= :set_foo
    >
    > def foo
    > @foo
    > end
    > end
    >
    > Then to reference foo from an instance of the class (or subclass), I do:
    >
    > self.class.foo
    >
    > Is there a cleaner way, in particular for the reference of the class
    > instance variable, to do this?


    class << self
    attr_accessor :foo
    end

    robert
    Robert Klemme, Oct 17, 2007
    #2
    1. Advertising

  3. Hi --

    On Thu, 18 Oct 2007, Perry Smith wrote:

    > I am using this technique for class instance variables:
    >
    > class << self
    > def set_foo(s)
    > @foo = s
    > end
    > alias :foo= :set_foo
    >
    > def foo
    > @foo
    > end
    > end
    >
    > Then to reference foo from an instance of the class (or subclass), I do:
    >
    > self.class.foo
    >
    > Is there a cleaner way, in particular for the reference of the class
    > instance variable, to do this?


    Yes:

    class C
    class << self
    attr_accessor :foo
    end
    end


    David

    --
    Upcoming training from Ruby Power and Light, LLC:
    * Intro to Ruby on Rails, Edison, NJ, October 23-26
    * Advancing with Rails, Edison, NJ, November 6-9
    Both taught by David A. Black.
    See http://www.rubypal.com for more info!
    David A. Black, Oct 17, 2007
    #3
  4. Perry Smith

    Perry Smith Guest

    Robert Klemme wrote:
    > On 17.10.2007 22:10, Perry Smith wrote:
    >> end
    >> end
    >>
    >> Then to reference foo from an instance of the class (or subclass), I do:
    >>
    >> self.class.foo
    >>
    >> Is there a cleaner way, in particular for the reference of the class
    >> instance variable, to do this?

    >
    > class << self
    > attr_accessor :foo
    > end
    >
    > robert


    Thanks!

    Do I still do the self.class.foo to access it?

    --
    Posted via http://www.ruby-forum.com/.
    Perry Smith, Oct 17, 2007
    #4
  5. Hi --

    On Thu, 18 Oct 2007, Perry Smith wrote:

    > Robert Klemme wrote:
    >> On 17.10.2007 22:10, Perry Smith wrote:
    >>> end
    >>> end
    >>>
    >>> Then to reference foo from an instance of the class (or subclass), I do:
    >>>
    >>> self.class.foo
    >>>
    >>> Is there a cleaner way, in particular for the reference of the class
    >>> instance variable, to do this?

    >>
    >> class << self
    >> attr_accessor :foo
    >> end
    >>
    >> robert

    >
    > Thanks!
    >
    > Do I still do the self.class.foo to access it?


    Yes. The call to attr_accessor will create singleton methods for use
    by the class object Foo.


    David

    --
    Upcoming training from Ruby Power and Light, LLC:
    * Intro to Ruby on Rails, Edison, NJ, October 23-26
    * Advancing with Rails, Edison, NJ, November 6-9
    Both taught by David A. Black.
    See http://www.rubypal.com for more info!
    David A. Black, Oct 17, 2007
    #5
  6. Perry Smith

    Gary Wright Guest

    On Oct 17, 2007, at 4:22 PM, Perry Smith wrote:

    > Do I still do the self.class.foo to access it?


    yes, and

    self.class.foo = obj

    to invoke the writer/setter method.

    Gary Wright
    Gary Wright, Oct 17, 2007
    #6
  7. Perry Smith

    Brian Adkins Guest

    On Oct 17, 4:10 pm, Perry Smith <> wrote:
    > I am using this technique for class instance variables:
    >
    > class << self
    > def set_foo(s)
    > @foo = s
    > end
    > alias :foo= :set_foo
    >
    > def foo
    > @foo
    > end
    > end
    >
    > Then to reference foo from an instance of the class (or subclass), I do:
    >
    > self.class.foo
    >
    > Is there a cleaner way, in particular for the reference of the class
    > instance variable, to do this?


    Just out of curiosity, why do you want a "class instance variable"
    instead of a class variable?
    Brian Adkins, Oct 18, 2007
    #7
  8. 2007/10/18, Brian Adkins <>:
    > On Oct 17, 4:10 pm, Perry Smith <> wrote:
    > > I am using this technique for class instance variables:
    > >
    > > class << self
    > > def set_foo(s)
    > > @foo = s
    > > end
    > > alias :foo= :set_foo
    > >
    > > def foo
    > > @foo
    > > end
    > > end
    > >
    > > Then to reference foo from an instance of the class (or subclass), I do:
    > >
    > > self.class.foo
    > >
    > > Is there a cleaner way, in particular for the reference of the class
    > > instance variable, to do this?

    >
    > Just out of curiosity, why do you want a "class instance variable"
    > instead of a class variable?


    Probably because class variables have @@various issues as has
    discusses before. I would also recommend to not use them.

    Kind regards

    robert
    Robert Klemme, Oct 18, 2007
    #8
  9. Perry Smith

    Brian Adkins Guest

    On Oct 18, 2:44 am, "Robert Klemme" <>
    wrote:
    > 2007/10/18, Brian Adkins <>:
    > > On Oct 17, 4:10 pm, Perry Smith <> wrote:
    > > > I am using this technique for class instance variables:

    > > Just out of curiosity, why do you want a "class instance variable"
    > > instead of a class variable?

    >
    > Probably because class variables have @@various issues as has
    > discusses before. I would also recommend to not use them.


    What issues have you experienced with them to cause you to not
    recommend them? I rarely have a need for either class variables or
    "class instance variables", but I've yet to experience any problems
    with class variables.

    I think they have different purposes, strengths and weaknesses, but I
    wouldn't recommend not using class variables, so I'm curious if I'm
    missing some problem with them.
    Brian Adkins, Oct 18, 2007
    #9
  10. Hi --

    On Fri, 19 Oct 2007, Brian Adkins wrote:

    > On Oct 18, 2:44 am, "Robert Klemme" <>
    > wrote:
    >> 2007/10/18, Brian Adkins <>:
    >>> On Oct 17, 4:10 pm, Perry Smith <> wrote:
    >>>> I am using this technique for class instance variables:
    >>> Just out of curiosity, why do you want a "class instance variable"
    >>> instead of a class variable?

    >>
    >> Probably because class variables have @@various issues as has
    >> discusses before. I would also recommend to not use them.

    >
    > What issues have you experienced with them to cause you to not
    > recommend them? I rarely have a need for either class variables or
    > "class instance variables", but I've yet to experience any problems
    > with class variables.
    >
    > I think they have different purposes, strengths and weaknesses, but I
    > wouldn't recommend not using class variables, so I'm curious if I'm
    > missing some problem with them.


    I'm on record as saying that class variables are the thing I dislike
    most about Ruby, so I'll try to explain why.

    They break encapsulation. They are visible to a weird assortment of
    objects: class C, instances of C, class D < C, instances of D... all
    the same variable. This cross-section of objects doesn't have anything
    in common except that they can all see each other's class variables.

    The prefix @@ makes it appear that they have some connection or
    kinship with instance variables. Actually, they're almost the
    opposite. Instance variables represent state on a strictly per-object
    basis. Class variables cut across many different objects and scopes.
    I would prefer them to look like $$this, since they're really a
    kind of restricted global variable rather than an extended instance
    variable.

    The worst thing about them, in my view, is the amount of confusion
    they have caused. The fact that there is something called a "class
    variable" -- and that it looks vaguely like an instance variable --
    has been a huge obstacle for people trying to get a grasp on the idea
    that classes are objects and can, via *instance* variable, have their
    own state. Class variables throw a big shadow over that otherwise very
    consistent and lucid state of things. I've seen this happen again and
    again for seven years.

    In Ruby > 1.8, class variables are going to be somewhat more strictly
    per-class. That's a mixed blessing. They're going to come closer to
    representing a class's state, but then the question will arise: why
    have both that *and* instance variables of classes? It's not
    impossible to answer that, but it's not a bad question.

    That sums up my views. Just so you know: I love Ruby madly :) This is
    one of the very few areas where I dissent strongly from the way it's
    designed.


    David

    --
    Upcoming training from Ruby Power and Light, LLC:
    * Intro to Ruby on Rails, Edison, NJ, October 23-26
    * Advancing with Rails, Edison, NJ, November 6-9
    Both taught by David A. Black.
    See http://www.rubypal.com for more info!
    David A. Black, Oct 18, 2007
    #10
  11. On 10/18/07, David A. Black <> wrote:

    > I'm on record as saying that class variables are the thing I dislike
    > most about Ruby, so I'll try to explain why.
    >
    > They break encapsulation. They are visible to a weird assortment of
    > objects: class C, instances of C, class D < C, instances of D... all
    > the same variable. This cross-section of objects doesn't have anything
    > in common except that they can all see each other's class variables.

    And even that is squirrely. Visibility depends on sequence of
    appearance, watch carefully, my fingers will ever leave my hands! <G>
    >

    class A
    @@x = "A"

    def self.show_x
    @@x
    end
    end
    A.show_x # => "A"

    class B < A
    end
    B.show_x # => "A"

    class B
    @@x = "B" # !> already initialized class variable @@x
    end
    B.show_x # => "B"
    A.show_x # => "B"

    class C
    end

    class D < C
    @@x = "D"
    def self.show_x
    @@x # !> class variable @@x of C is overridden by D
    end
    end
    D.show_x # => "D"

    class C
    @@x = "C"
    def self.show_x
    @@x
    end
    end
    D.show_x # => "D"
    C.show_x # => "C"

    class D
    @@x = "Blorp" # !> class variable @@x of C is overridden by D
    end
    D.show_x # => "Blorp"
    C.show_x # => "C"

    > That sums up my views. Just so you know: I love Ruby madly :) This is
    > one of the very few areas where I dissent strongly from the way it's
    > designed.


    Amen, brother!

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
    Rick DeNatale, Oct 18, 2007
    #11
  12. Perry Smith

    Gary Wright Guest

    On Oct 18, 2007, at 1:22 PM, David A. Black wrote:
    > In Ruby > 1.8, class variables are going to be somewhat more strictly
    > per-class. That's a mixed blessing. They're going to come closer to
    > representing a class's state, but then the question will arise: why
    > have both that *and* instance variables of classes? It's not
    > impossible to answer that, but it's not a bad question.


    My gut says that code that utilizes class variables can always be
    refactored to use class instance variables and perhaps some accessor
    methods and the result will be equal or better to the original
    class variable code.

    I say ditch class variables all together.

    Gary Wright
    Gary Wright, Oct 18, 2007
    #12
  13. Perry Smith

    John Joyce Guest

    Well, I have to agree there are some odd things about Ruby's class
    variables, and they're not terribly useful most of the time, but in
    the cases where they are useful, they are useful.
    Unless you need to count the number of instantiations of a class, I
    can't imagine what else to use them for.
    But perhaps this kind of counter of class instantiations ( minus GC'd
    instances ) should be built-in to all Ruby classes and accessible via
    a method. Or at least the ability to create that count without using
    class variables proper.
    Then again, is it that useful?
    It is when it is needed.

    I do think all the books should generally make a note that most folks
    will rarely need or want to use class variables.
    Then each book should explicitly state that instance vars are what
    you will normally want to use day to day.

    In the case of subclasses and so forth, choosing where you want to
    have a class variable is a design issue.
    While OOP is easy to learn and understand, it is not easy to become
    good at designing classes. I know. I'm still not good at it.
    John Joyce, Oct 19, 2007
    #13
  14. Perry Smith

    ara.t.howard Guest

    On Oct 18, 2007, at 11:22 AM, David A. Black wrote:

    and ara responds to him but mostly to the general thread:

    >
    > I'm on record as saying that class variables are the thing I dislike
    > most about Ruby, so I'll try to explain why.
    >
    > They break encapsulation.


    i honestly don't think they do - inheritance breaks encapsulation.
    for example

    class A
    CONST = 42

    class << self
    def shared() 42.0 end
    end
    end

    class B < A
    end

    p B::CONST
    p B::shared

    class vars are exactly like this - only with state that happens to be
    resettable. i don't see anything particular about the way class vars
    behave that is different from constants or singleton (note the
    *single* in singleton methods that can be called on multiple
    objects!). it's the concept of inheritance that breaks
    encapsulation, this is of course generally accepted by oop geeks, and
    ruby doesn't change this wart on oop's many graces.

    > They are visible to a weird assortment of
    > objects: class C, instances of C, class D < C, instances of D... all
    > the same variable. This cross-section of objects doesn't have anything
    > in common except that they can all see each other's class variables.
    >


    and constants and singleton methods.... of course class singleton
    methods, in an instance context, require a 'self.class' prefix to
    invoke while constants do not but this is not encapsulation - it's
    the breaking of it - instances *should* be allowed to access the
    unfettered methods of their class because requiring the 'self.class'
    prefix also makes them *public* which, of course, seriously breaks
    encapsulation.

    in point of fact inheritance is *designed* to break encapsulation so
    that we can reuse code and remain sane. child classes, mixins,
    friend classes et al are all about tearing down the barriers between
    bits of code so we don't descend.into.dot.dot.dot.dot.hell and
    develop carpal tunnel from all that code pasting

    > The prefix @@ makes it appear that they have some connection or
    > kinship with instance variables. Actually, they're almost the
    > opposite. Instance variables represent state on a strictly per-object
    > basis. Class variables cut across many different objects and scopes.
    > I would prefer them to look like $$this, since they're really a
    > kind of restricted global variable rather than an extended instance
    > variable.


    i can see that. still, they *are* associated with an instance - an
    instance of a class hierarchy. i realize people don't generally seem
    to grasp this concept though. the idea of switching syntax is a good
    one. i hate $ because it looks like perl and perl is clearly evil.
    i'm not sure what would be better though.

    >
    > The worst thing about them, in my view, is the amount of confusion
    > they have caused. The fact that there is something called a "class
    > variable" -- and that it looks vaguely like an instance variable --
    > has been a huge obstacle for people trying to get a grasp on the idea
    > that classes are objects and can, via *instance* variable, have their
    > own state. Class variables throw a big shadow over that otherwise very
    > consistent and lucid state of things. I've seen this happen again and
    > again for seven years.


    absolutely correct.

    >
    > In Ruby > 1.8, class variables are going to be somewhat more strictly
    > per-class. That's a mixed blessing. They're going to come closer to
    > representing a class's state, but then the question will arise: why
    > have both that *and* instance variables of classes? It's not
    > impossible to answer that, but it's not a bad question.
    >
    > That sums up my views. Just so you know: I love Ruby madly :) This is
    > one of the very few areas where I dissent strongly from the way it's
    > designed.
    >


    yeah i see all that. still, i've deigned quite a few ruby classes
    and i can assure people that they will miss them when they are gone/
    limited. the reason, curiously, is that classes do not have an
    initialize method/hook. let me explain: let's say you want to do
    something quite reasonable like so

    class Parser

    def self.bufsize(*value)
    value.size == 0 ? @@bufsize : self.bufsize=(value.first)
    end

    def self.bufsize=(value)
    @@bufsize = Integer value
    end

    bufsize 4242

    def initialize options = {}
    @bufsize = options[:bufsize] || @@bufsize
    end

    end

    Parser.new


    that is to say you want to grab default initialization options from
    your class and you want users to be able to configure the class such
    that it stamps out instances with those defaults. it's really nice
    if people can configure via the environment or like so

    Parser.bufsize 42

    as i'm sure we can all agree. obviously constants aren't really in
    order unless you want to use hackery like

    class Parser

    BUFSIZE = [ :value ]

    def self.bufsize=(value) BUFSIZE[0] = Integer value end

    ...

    blechh!

    i can hear people thinking "you need instance variables!" sure, if
    you want to write totally non-reusable code. why? because if i do

    class Parser
    def self.bufsize(*value)
    value.size == 0 ? @bufsize : self.bufsize=(value.first)
    end

    def self.bufsize=(value)
    @bufsize = Integer value
    end

    bufsize 4242

    def initialize options = {}
    @bufsize = options[:bufsize] || self.class.bufsize
    end
    end

    Parser.new

    then, seemingly, all is well. but then

    class SubParser < Parser
    ...

    now i have a problem: *only* the Parser class has an initialized of
    the class instance variable @bufsize - it's of course 'nil' in
    SubParser. now, it's true that we can write something like

    class Parser

    def self.inherited other
    super if defined? super
    ensure
    other.init ### note that this must be *public* less we result
    to class_eval...
    end

    def other.init
    bufsize 4242
    end

    init()

    this all starts to get just as confusing as the current situation. i
    can hear people now: "why is it so hard to inherit class variables in
    ruby?"

    in short there are a million reasons to use class variables revolving
    around the glitch that class inheritance in ruby does not provide a
    straightforward way for child classes to have any sort of setup step
    performed and that class variables let you perform that setup once in
    a way that is inherited and yet settable by client code.

    anyhow i really think it's the syntax, not the concept, that is cause
    for confusion.

    my 2cts.

    ps. there are a lot of powerful concepts in ruby that are mostly mis-
    understood: closures, mixins, singleton classes, callcc, throw/catch,
    and lambda abstraction are part of what allows ruby to grow in
    usefulness beyond the realm of the 'mere scripting language' some
    people set out to learn. i would be loathe so any of them vanish.

    pss. encapsulation is vastly overrated. when is that last time you
    used 'protected' in any ruby code? ;-)

    a @ http://codeforpeople.com/
    --
    it is not enough to be compassionate. you must act.
    h.h. the 14th dalai lama
    ara.t.howard, Oct 19, 2007
    #14
  15. Hi --

    On Fri, 19 Oct 2007, ara.t.howard wrote:

    >
    > On Oct 18, 2007, at 11:22 AM, David A. Black wrote:
    >
    > and ara responds to him but mostly to the general thread:
    >
    >>
    >> I'm on record as saying that class variables are the thing I dislike
    >> most about Ruby, so I'll try to explain why.
    >>
    >> They break encapsulation.

    >
    > i honestly don't think they do - inheritance breaks encapsulation. for
    > example
    >
    > class A
    > CONST = 42
    >
    > class << self
    > def shared() 42.0 end
    > end
    > end
    >
    > class B < A
    > end
    >
    > p B::CONST
    > p B::shared


    I think we're defining encapsulation differently. I don't mean that no
    two objects should ever share any kind of data; rather, it's that
    class variables don't play nicely with the system of which they are
    part. I know about the "singleton" non-singletons... but at least
    that's implemented in terms of inheritance (so really only the
    terminology is at stake). I can see what a subclass has to do with its
    parent class, especially given Matz's point that inheritance in Ruby
    is mostly about "shared implementation". I find automatic variable
    sharing between classes and instances much more problematic,
    especially given the fact that classes are first-class objects (which
    leads to all the problems with @@vars obscuring @vars, conceptually at
    least).

    >> They are visible to a weird assortment of
    >> objects: class C, instances of C, class D < C, instances of D... all
    >> the same variable. This cross-section of objects doesn't have anything
    >> in common except that they can all see each other's class variables.
    >>

    >
    > and constants and singleton methods.... of course class singleton methods,


    It's not a contest, though :) It's possible that constants are
    well-designed and class variables aren't, even if they share certain
    behaviors. Actually, I'd add constants to the list of things, along
    with instance variables, that can do most of what people usually use
    class variables for.

    > in an instance context, require a 'self.class' prefix to invoke while
    > constants do not but this is not encapsulation - it's the breaking of it -
    > instances *should* be allowed to access the unfettered methods of their class
    > because requiring the 'self.class' prefix also makes them *public* which, of
    > course, seriously breaks encapsulation.


    I'm not following this, I'm afraid. If an object has a public method
    defined on it, and you call obj.meth, how does that break
    encapsulation? I guess it's the "*should*" I'm not understanding.

    > in point of fact inheritance is *designed* to break encapsulation so that we
    > can reuse code and remain sane. child classes, mixins, friend classes et al
    > are all about tearing down the barriers between bits of code so we don't
    > descend.into.dot.dot.dot.dot.hell and develop carpal tunnel from all that
    > code pasting


    OK... but I don't think we have to choose between (a) no two objects
    ever sharing anything, and (b) deciding that some objects share some
    things so we might as well give up trying to differentiate among
    different cases. It's possible that mixins are well-designed and class
    variables aren't, even if both of them involve, described at a very
    high level, tearing down barriers between bits of code.

    The sense I get from class variables is of quasi-globalness. I don't
    get that sense when I include a mixin; I actually don't think it's the
    same in either kind or degree.

    >> The prefix @@ makes it appear that they have some connection or
    >> kinship with instance variables. Actually, they're almost the
    >> opposite. Instance variables represent state on a strictly per-object
    >> basis. Class variables cut across many different objects and scopes.
    >> I would prefer them to look like $$this, since they're really a
    >> kind of restricted global variable rather than an extended instance
    >> variable.

    >
    > i can see that. still, they *are* associated with an instance - an instance
    > of a class hierarchy. i realize people don't generally seem to grasp this
    > concept though.


    I'm not sure what the advantage is of generalizing the technical term
    "instance" that way. You can say that global variables are associated
    with an "instance" of a computer program, so they must be OK :)

    > the idea of switching syntax is a good one. i hate $
    > because it looks like perl and perl is clearly evil. i'm not sure what would
    > be better though.


    "Clearly evil" works for me :)

    >> In Ruby > 1.8, class variables are going to be somewhat more strictly
    >> per-class. That's a mixed blessing. They're going to come closer to
    >> representing a class's state, but then the question will arise: why
    >> have both that *and* instance variables of classes? It's not
    >> impossible to answer that, but it's not a bad question.
    >>
    >> That sums up my views. Just so you know: I love Ruby madly :) This is
    >> one of the very few areas where I dissent strongly from the way it's
    >> designed.
    >>

    >
    > yeah i see all that. still, i've deigned quite a few ruby classes and i can
    > assure people that they will miss them when they are gone/limited. the
    > reason, curiously, is that classes do not have an initialize method/hook.
    > let me explain: let's say you want to do something quite reasonable like so
    >
    > class Parser
    >
    > def self.bufsize(*value)
    > value.size == 0 ? @@bufsize : self.bufsize=(value.first)
    > end
    >
    > def self.bufsize=(value)
    > @@bufsize = Integer value
    > end
    >
    > bufsize 4242
    >
    > def initialize options = {}
    > @bufsize = options[:bufsize] || @@bufsize


    I don't think it would be such a disaster to have to say
    "|| self.class.bufsize". It would certainly be worthwhile tradeoff for
    all the other problems.

    > end
    >
    > end
    >
    > Parser.new
    >
    >
    > that is to say you want to grab default initialization options from your
    > class and you want users to be able to configure the class such that it
    > stamps out instances with those defaults. it's really nice if people can
    > configure via the environment or like so
    >
    > Parser.bufsize 42
    >
    > as i'm sure we can all agree.


    (I'm happier with an equal-sign but I won't press the point :)

    > obviously constants aren't really in order
    > unless you want to use hackery like
    >
    > class Parser
    >
    > BUFSIZE = [ :value ]
    >
    > def self.bufsize=(value) BUFSIZE[0] = Integer value end
    >
    > ...
    >
    > blechh!
    >
    > i can hear people thinking "you need instance variables!" sure, if you want
    > to write totally non-reusable code. why? because if i do
    >
    > class Parser
    > def self.bufsize(*value)
    > value.size == 0 ? @bufsize : self.bufsize=(value.first)
    > end
    >

    [code snipped]
    >
    > in short there are a million reasons to use class variables revolving around
    > the glitch that class inheritance in ruby does not provide a straightforward
    > way for child classes to have any sort of setup step performed and that class
    > variables let you perform that setup once in a way that is inherited and yet
    > settable by client code.


    I'm still happier with class objects playing in the same ballpark as
    other objects, when it comes to per-object state. Set up, if desired,
    a way for other objects to get at the state, and then have the other
    objects send you messages. It's all about where one thinks the
    special-case horizon should be, I guess.

    > ps. there are a lot of powerful concepts in ruby that are mostly
    > mis-understood: closures, mixins, singleton classes, callcc, throw/catch, and
    > lambda abstraction are part of what allows ruby to grow in usefulness beyond
    > the realm of the 'mere scripting language' some people set out to learn. i
    > would be loathe so any of them vanish.


    I'm not saying they should. I'm saying I'd like it if class variables
    did :) It's not a one-size-fits-all argument about misunderstood Ruby
    features; it's specifically about class variables.


    David

    --
    Upcoming training from Ruby Power and Light, LLC:
    * Intro to Ruby on Rails, Edison, NJ, October 23-26
    * Advancing with Rails, Edison, NJ, November 6-9
    Both taught by David A. Black.
    See http://www.rubypal.com for more info!
    David A. Black, Oct 19, 2007
    #15
  16. Perry Smith

    ara.t.howard Guest

    On Oct 19, 2007, at 5:09 AM, David A. Black wrote:


    >
    > I think we're defining encapsulation differently. I don't mean that no
    > two objects should ever share any kind of data; rather, it's that
    > class variables don't play nicely with the system of which they are
    > part. I know about the "singleton" non-singletons... but at least
    > that's implemented in terms of inheritance (so really only the
    > terminology is at stake). I can see what a subclass has to do with its
    > parent class, especially given Matz's point that inheritance in Ruby
    > is mostly about "shared implementation". I find automatic variable
    > sharing between classes and instances much more problematic,
    > especially given the fact that classes are first-class objects (which
    > leads to all the problems with @@vars obscuring @vars, conceptually at
    > least).


    yeah i see that. i avoid them much of the time for those reasons.
    but, technically, doing something like this

    class C
    SHARED_WITH_ALL_SUBCLASSES_AND_INSTANCES = []
    end

    does the same. it's something worth considering.

    >> and constants and singleton methods.... of course class singleton
    >> methods,

    >
    > It's not a contest, though :) It's possible that constants are
    > well-designed and class variables aren't, even if they share certain
    > behaviors. Actually, I'd add constants to the list of things, along
    > with instance variables, that can do most of what people usually use
    > class variables for.
    >


    sort of. if you need state to be inherited you can use constants.
    if you want true class singleton state that is settable you can use
    class instance variables. if you want state that is settable AND
    inherited the simplest option at the moment are class @@variables.
    the way they mix into instances, i would agree is confusing, but
    there really aren't any other *simple* options for inheriting state
    in classes

    >> in an instance context, require a 'self.class' prefix to invoke
    >> while constants do not but this is not encapsulation - it's the
    >> breaking of it - instances *should* be allowed to access the
    >> unfettered methods of their class because requiring the
    >> 'self.class' prefix also makes them *public* which, of course,
    >> seriously breaks encapsulation.

    >
    > I'm not following this, I'm afraid. If an object has a public method
    > defined on it, and you call obj.meth, how does that break
    > encapsulation? I guess it's the "*should*" I'm not understanding.


    in some languages instances of a class may call private/protected
    methods of that class which, if you think about it, makes sense. in
    ruby, a method must (ignoring xxx_eval and send) be exposed to the
    world if instances also need to call it. so when using class
    instance vars you give instances one simple option for accessing
    them: expose them through attr_accessor thereby also exposing them to
    the world. for example

    class C
    @how_do_instances_get_at_this

    def initialize
    class << self.class
    def with_a_public_accessor() @how_do_instances_get_at_this end
    end

    self.class.with_a_public_accessor
    end

    so the typical pattern with class instance variables is to expose
    them publicly and this may break encapsulation iff the information
    exposed is best left internal to the class and it's instances

    >
    > OK... but I don't think we have to choose between (a) no two objects
    > ever sharing anything, and (b) deciding that some objects share some
    > things so we might as well give up trying to differentiate among
    > different cases. It's possible that mixins are well-designed and class
    > variables aren't, even if both of them involve, described at a very
    > high level, tearing down barriers between bits of code.
    >
    > The sense I get from class variables is of quasi-globalness. I don't
    > get that sense when I include a mixin; I actually don't think it's the
    > same in either kind or degree.
    >


    yeah the fact that instances see them does indeed make them seem
    quasi global - but the lack of another inherited class state
    mechanism is a show stopper when it comes to declaring them useless
    and poorly designed. that's critical functionality in some object
    hierarchies.


    >
    > I'm not sure what the advantage is of generalizing the technical term
    > "instance" that way. You can say that global variables are associated
    > with an "instance" of a computer program, so they must be OK :)
    >


    heh. i actually meant it quite specifically with regard to classes -
    each iteration of oo laguanges is breaking down the barrier between
    classes, objects, and other constructs like modules. i think we all
    can see that the distinction in ruby is largely artificial: layers
    put on top to make us see them as distinct. i probably program a lot
    more class factories than your average ruby programmer and, when you
    are working with classes at that level you, correctly, are thinking
    of them as instances. but you also start wondering why things like
    this don't work:

    class C
    @var = 42
    class << self
    p @var
    end
    end

    and this too

    class B < C
    p @var
    end

    if you've programmed using prototypes this shouldn't really come as a
    surprise: it's normal to expect classes that *are* objects to have
    some mechanism for sharing or copying that object's state. in ruby
    you have to resort to @@vars and other weirdness like klass.clone or
    klass.dup to get the affect. in summary it's correct, i think, in a
    language where classes are first class objects to consider attributes
    of that class, like it's singleton class and it's child classes, as
    *instance* data.

    >>
    >> class Parser
    >>
    >> def self.bufsize(*value)
    >> value.size == 0 ? @@bufsize : self.bufsize=(value.first)
    >> end
    >>
    >> def self.bufsize=(value)
    >> @@bufsize = Integer value
    >> end
    >>
    >> bufsize 4242
    >>
    >> def initialize options = {}
    >> @bufsize = options[:bufsize] || @@bufsize

    >
    > I don't think it would be such a disaster to have to say "||
    > self.class.bufsize". It would certainly be worthwhile tradeoff for
    > all the other problems.


    i disagree - if you do that you've designed a class that cannot be
    subclassed: as that line will return 'nil' in those subclasses. if
    you do that you should be using a singleton object or module - not a
    class - to model your problem domain.

    >>
    >> i can hear people thinking "you need instance variables!" sure,
    >> if you want to write totally non-reusable code. why? because if
    >> i do
    >>
    >> class Parser
    >> def self.bufsize(*value)
    >> value.size == 0 ? @bufsize : self.bufsize=(value.first)
    >> end
    >>

    > [code snipped]
    >>
    >> in short there are a million reasons to use class variables
    >> revolving around the glitch that class inheritance in ruby does
    >> not provide a straightforward way for child classes to have any
    >> sort of setup step performed and that class variables let you
    >> perform that setup once in a way that is inherited and yet
    >> settable by client code.

    >
    > I'm still happier with class objects playing in the same ballpark as
    > other objects, when it comes to per-object state. Set up, if desired,
    > a way for other objects to get at the state, and then have the other
    > objects send you messages. It's all about where one thinks the
    > special-case horizon should be, I guess.


    the lack of class setup with class instance variables isn't really a
    special case though - any newbie would expect to be able to write this

    class C
    @a, @b = 4, 2
    end

    class B < C
    end

    and have @a and @b end up being initialized in B somehow. i guess i
    just don't think that inheritance/setup of class state is something
    that people should be expected to roll on their own in a language as
    powerful as ruby - it can get quite complex when modules enter the
    picture too. i'd rather entrust matz to solved the problem
    generically ;-)

    >
    > I'm not saying they should. I'm saying I'd like it if class variables
    > did :) It's not a one-size-fits-all argument about misunderstood Ruby
    > features; it's specifically about class variables.
    >
    >


    oh i understand that david - no worries. what i'm saying is simply
    that i've probably designed as many complex ruby class hierarchies as
    anyone else out there and i've solved the class state sharing issue a
    whole bunch of times in different ways: sometimes using 'inherited',
    sometimes by factoring things out into modules, and sometimes using
    @@variables and none of them are perfect. my experience has lead me
    to think that any discussion of the evils of class variables (and
    i've said they are evil on this list too!) shouldn't be outside the
    context of how to *better* share and initialize state between parent
    and child classes because it's an important feature in an oop
    language - in short, it's a red herring.

    cheers.

    a @ http://codeforpeople.com/
    --
    share your knowledge. it's a way to achieve immortality.
    h.h. the 14th dalai lama
    ara.t.howard, Oct 19, 2007
    #16
  17. ara.t.howard wrote:
    > yeah i see all that. still, i've deigned quite a few ruby classes and i
    > can assure people that they will miss them when they are gone/limited.
    > the reason, curiously, is that classes do not have an initialize
    > method/hook. let me explain: let's say you want to do something quite
    > reasonable like so
    >
    > class Parser
    >
    > def self.bufsize(*value)
    > value.size == 0 ? @@bufsize : self.bufsize=(value.first)
    > end
    >
    > def self.bufsize=(value)
    > @@bufsize = Integer value
    > end
    >
    > bufsize 4242
    >
    > def initialize options = {}
    > @bufsize = options[:bufsize] || @@bufsize
    > end
    >
    > end
    >
    > Parser.new


    But this still works with ruby1.9! And it works in subclasses too. As
    long as @@bufsize is within the lexical context of Parser, it works just
    like 1.8. The difference is only if you try to use @@bufsize within the
    (lexical) scope of a subclass.
    Daniel DeLorme, Oct 19, 2007
    #17
  18. On 10/19/07, ara.t.howard <> wrote:
    >
    > On Oct 18, 2007, at 11:22 AM, David A. Black wrote:
    >
    > and ara responds to him but mostly to the general thread:
    >
    > >
    > > I'm on record as saying that class variables are the thing I dislike
    > > most about Ruby, so I'll try to explain why.
    > >
    > > They break encapsulation.

    >
    > i honestly don't think they do - inheritance breaks encapsulation.
    > for example
    >
    > class A
    > CONST = 42
    >
    > class << self
    > def shared() 42.0 end
    > end
    > end
    >
    > class B < A
    > end
    >
    > p B::CONST
    > p B::shared
    >
    > class vars are exactly like this - only with state that happens to be
    > resettable. i don't see anything particular about the way class vars
    > behave that is different from constants or singleton (note the
    > *single* in singleton methods that can be called on multiple
    > objects!).


    The main reason, I've never been completely comfortable with the Ruby
    conflation of singleton class and metaclass. Or maybe it's the
    conflation of singleton methods and class methods.

    Seems to me that singleton methods SHOULD only be applicable to a
    single object. A singleton class of a non-class is constrained to
    containing only singleton methods in that sense, because it can't be
    subclassed. A singleton class of a class is not. It's actually the
    class that's the singleton here in that it's the only allowed instance
    of its, dare I say it, metaclass.

    But I digress.

    > it's the concept of inheritance that breaks
    > encapsulation, this is of course generally accepted by oop geeks, and
    > ruby doesn't change this wart on oop's many graces.


    Agreed.

    Inheritance is a power tool, valuable and sometimes dangerous. Did I
    mention that it's valuable!

    > > They are visible to a weird assortment of
    > > objects: class C, instances of C, class D < C, instances of D... all
    > > the same variable. This cross-section of objects doesn't have anything
    > > in common except that they can all see each other's class variables.
    > >

    >
    > and constants and singleton methods.... of course class singleton
    > methods, in an instance context, require a 'self.class' prefix to
    > invoke while constants do not but this is not encapsulation - it's
    > the breaking of it - instances *should* be allowed to access the
    > unfettered methods of their class because requiring the 'self.class'
    > prefix also makes them *public* which, of course, seriously breaks
    > encapsulation.


    I'm not sure that I totally agree here. There might well be class
    methods which the class doesn't/shouldn't expose even to its
    instances.

    Perhaps there are use cases for a fourth visibility (in addition to
    public, protected, and private) which makes a method visible to
    instances, between public and protected.

    > in point of fact inheritance is *designed* to break encapsulation so
    > that we can reuse code and remain sane. child classes, mixins,
    > friend classes et al are all about tearing down the barriers between
    > bits of code so we don't descend.into.dot.dot.dot.dot.hell and
    > develop carpal tunnel from all that code pasting


    Yes.

    > > The prefix @@ makes it appear that they have some connection or
    > > kinship with instance variables. Actually, they're almost the
    > > opposite. Instance variables represent state on a strictly per-object
    > > basis. Class variables cut across many different objects and scopes.
    > > I would prefer them to look like $$this, since they're really a
    > > kind of restricted global variable rather than an extended instance
    > > variable.

    >
    > i can see that. still, they *are* associated with an instance - an
    > instance of a class hierarchy. i realize people don't generally seem
    > to grasp this concept though.


    I understand what you're saying Ara, but it's a little hard to grasp
    because there really isn't anything which reifies 'a class hierarchy'.
    In reality a class variable is associated with a class, which of
    course is the root of a class hierarchy, but the way they are
    implemented, it really means they get associated with a kind of
    snapshot of the hierarchy as it existed at the time the class variable
    was defined. I say this by way of explaining the problems of defining
    a class variable in a superclass, AFTER a subclass has already defined
    a class variable with the same name.

    This is one instance of a small set of curiosities in Ruby due to
    problems in re-building the runtime structures when certain
    inheritance related changes occur. To me it seems to be similar to
    the problems with the semantics of module re-inclusion.

    Now I'm not sure that Matz was directly inspired by Smalltalk in
    coming up with class variables, but given my background I tend to
    think so. Ruby class variable have a lot in common with Smaltalk's
    certainly in terms of inheritance and visibility in both class and
    instance methods. Assuming he was...

    One of the biggest differences (and I'd say for the most part it's an
    improvement) between Ruby and Smalltalk is that in Smaltalk variables
    are declared, whereas in Ruby they are defined in the process of
    expression parsing/execution.

    In Smalltalk, you declare a class with something like

    Object subclass: #Foo
    instanceVariableNames: 'instVar'
    classVariableNames: 'ClassVar'
    classInstanceVariableNames: 'classInstVar'
    poolDictionaries: 'PoolDict'

    And the compiler uses these declarations when compiling a method. In
    Smalltalk instance variables and class instance variables can be bound
    to a slot at a fixed offset from the begining of the instance, or
    class. Class variables can be bound to the value slot in a dictionary
    associated with the class. I'll ignore pool dictionaries, they serve
    some of the purposes of the name space aspect of modules.

    The compiler searches up the hierarchy to find inherited class
    variables, and the methods for manipulating the classVariableNames
    list of a class validate that a conflict can't be created. Changing
    the class declaration in Smalltalk triggers a recompilation of all
    methods of the class and its subclasses.

    Ruby substitutes run-time binding binding of variables, rather than
    being at a fixed offset, ruby instance (and class instance) variables
    are bound to a value slot in a hash associated with the instance or
    class, class variables are bound to a hash as well (the last time I
    looked it was the same hash, which works because the key contains the
    sigil, so the keys :mad:instance_var, and :mad:@class_var can both be in the
    hash, reflection methods like Object#instance_variables filter their
    results to hide this implementation. Note also that this description
    is from my memory of reading the MRI 1.8.x code, other Ruby 1.8
    implementations might well use different implementation techniques but
    should have the same semantics.

    So what was my point here? Oh yes. I was talking about what happens
    when you make certain changes to the inheritance structure. If we
    had:

    class A
    end

    class B < A
    @@cv = 42
    end

    And then later
    class A
    @@cv = 57
    end

    Ruby currently at most warns about a conflict then goes ahead and adds
    a new class variable to A, leaving the existing one in C.

    I think that the change in 1.9 was motivated by this anomaly, by doing
    away with the inheritance of class variables we avoid the surprise.
    On the other hand, as you point out below, the baby might be being
    thrown out with the bath water!

    It seems to me that another solution would be to simply remove the
    class variable from a subclass when a superclass subsequently creates
    one with the same name. Sure B's view of @@cv would change from 42 to
    57, but that's consistent with the intended semantics, I think.

    On the other hand, there might be subtleties I can't yet fathom, much
    like I still don't understand why 1.9 changed the semantics of:

    module M
    def meth
    "M"
    end
    end

    class A
    include M
    end

    class B < A
    def meth
    "B"
    end
    end

    class C
    include M
    end

    C.new.meth

    So that in 1.9 this used to result in "M" but then they changed it
    back to the 1.8 semantics which ignore the re-inclusion and results in
    "B".

    > > The worst thing about them, in my view, is the amount of confusion
    > > they have caused. The fact that there is something called a "class
    > > variable" -- and that it looks vaguely like an instance variable --
    > > has been a huge obstacle for people trying to get a grasp on the idea
    > > that classes are objects and can, via *instance* variable, have their
    > > own state. Class variables throw a big shadow over that otherwise very
    > > consistent and lucid state of things. I've seen this happen again and
    > > again for seven years.

    >
    > absolutely correct.


    i think that the problem should be dissected, it's really two problems:

    1) Ruby class variables look too much like instance variables
    because of syntax @@ vs @
    2) The Ruby class variable implementation has a few rough edges.

    The first problem makes me tend to agree that it would have been
    better to choose another sigil for denoting class variables, although
    this would seem to have a pretty sizable cost in backward
    compatibility.

    The second problem would seem to be fixable, at some cost to backward
    compatibility, but 1.9 has already taken one path at fixing it.

    > >
    > > In Ruby > 1.8, class variables are going to be somewhat more strictly
    > > per-class. That's a mixed blessing. They're going to come closer to
    > > representing a class's state, but then the question will arise: why
    > > have both that *and* instance variables of classes? It's not
    > > impossible to answer that, but it's not a bad question.


    I guess that the only difference between class variables and class
    instance variables in 1.9 is that the former are visible in instance
    methods.

    It seems to me that the baby is in the bathwater here, the baby being
    uses which rely on inheritance of class variables.

    It might be interesting to see what happens when rails steps up to
    ruby 1.9. It appears to use class variables pretty extensively. I'm
    not sure how much it relies on class variable inheritance though.

    > > That sums up my views. Just so you know: I love Ruby madly :) This is
    > > one of the very few areas where I dissent strongly from the way it's
    > > designed.
    > >

    >
    > yeah i see all that. still, i've deigned quite a few ruby classes
    > and i can assure people that they will miss them when they are gone/
    > limited. the reason, curiously, is that classes do not have an
    > initialize method/hook. let me explain: let's say you want to do
    > something quite reasonable like so
    >

    .. Long example justifying inheritable class variables snipped.
    >
    > in short there are a million reasons to use class variables revolving
    > around the glitch that class inheritance in ruby does not provide a
    > straightforward way for child classes to have any sort of setup step
    > performed and that class variables let you perform that setup once in
    > a way that is inherited and yet settable by client code.


    Not much to disagree with here.

    An interesting side note. In Smalltalk, the declaration of variables
    doesn't initialize them. Conventionally, class variables are
    initialized in a class method called initialize. I'm a bit rusty on
    this but IIRC this is something which has to be done manually after
    defining the method and before instantiating any instances of the
    class.

    > anyhow i really think it's the syntax, not the concept, that is cause
    > for confusion.


    To summarize what I've said, I think it's a combination of the
    semantics and the implementation.

    > ps. there are a lot of powerful concepts in ruby that are mostly mis-
    > understood: closures, mixins, singleton classes, callcc, throw/catch,
    > and lambda abstraction are part of what allows ruby to grow in
    > usefulness beyond the realm of the 'mere scripting language' some
    > people set out to learn. i would be loathe so any of them vanish.


    Amen.


    > pss. encapsulation is vastly overrated. when is that last time you
    > used 'protected' in any ruby code? ;-)


    Careful, Ara, the thought police are lurking! <G>

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
    Rick DeNatale, Oct 19, 2007
    #18
  19. Perry Smith

    Brian Adkins Guest

    On Oct 19, 12:22 pm, "Rick DeNatale" <> wrote:
    > On 10/19/07, ara.t.howard <> wrote:
    > > On Oct 18, 2007, at 11:22 AM, David A. Black wrote:

    >
    > So what was my point here? Oh yes. I was talking about what happens
    > when you make certain changes to the inheritance structure. If we
    > had:
    >
    > class A
    > end
    >
    > class B < A
    > @@cv = 42
    > end
    >
    > And then later
    > class A
    > @@cv = 57
    > end
    >
    > Ruby currently at most warns about a conflict then goes ahead and adds
    > a new class variable to A, leaving the existing one in C.


    Ok, you've used a similar example multiple times now, so my curiosity
    is getting the best of me - do you actually code this way, or are you
    trying to come up with a contrived example to show the alleged
    problems with class variables? Wouldn't you typically initialize the
    class variable in the "superest" class only?

    > ...
    > On the other hand, there might be subtleties I can't yet fathom, much
    > like I still don't understand why 1.9 changed the semantics of:
    >
    > module M
    > def meth
    > "M"
    > end
    > end
    >
    > class A
    > include M
    > end
    >
    > class B < A
    > def meth
    > "B"
    > end
    > end
    >
    > class C
    > include M
    > end
    >
    > C.new.meth
    >
    > So that in 1.9 this used to result in "M" but then they changed it
    > back to the 1.8 semantics which ignore the re-inclusion and results in
    > "B".


    Should 'class C' be 'class C < B' ?
    Brian Adkins, Oct 19, 2007
    #19
  20. Perry Smith

    ara.t.howard Guest

    On Oct 19, 2007, at 9:39 AM, Daniel DeLorme wrote:

    > But this still works with ruby1.9! And it works in subclasses too.
    > As long as @@bufsize is within the lexical context of Parser, it
    > works just like 1.8. The difference is only if you try to use
    > @@bufsize within the (lexical) scope of a subclass.
    >


    yup. i haven't used that in anger so i really don't know if it'll be
    helpful or even more confusing - at least state can still be
    inherited, even with a somewhat crippled impl.

    time will tell!

    cheers.

    a @ http://codeforpeople.com/
    --
    it is not enough to be compassionate. you must act.
    h.h. the 14th dalai lama
    ara.t.howard, Oct 19, 2007
    #20
    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. Sridhar R
    Replies:
    14
    Views:
    1,397
    =?iso-8859-1?Q?Fran=E7ois?= Pinard
    Feb 10, 2004
  2. Gerry Sutton
    Replies:
    1
    Views:
    538
    Peter Otten
    Apr 16, 2005
  3. Martin P. Hellwig
    Replies:
    1
    Views:
    374
    Martin P. Hellwig
    Mar 26, 2010
  4. David Garamond
    Replies:
    5
    Views:
    237
    Ara.T.Howard
    Jun 8, 2004
  5. Mike Mr.
    Replies:
    4
    Views:
    201
    Mike Jo
    Sep 21, 2008
Loading...

Share This Page