Class variables, instance variables, singleton; Ruby v. C++

Discussion in 'Ruby' started by Ralph Shnelvar, Nov 27, 2009.

  1. Newb here coming from C++

    Ok, I _think_ I know what a class variable is. It is similar to a
    static variable in a class in C++. Rght?

    An instance variable is apart of an instantiated class, right?

    What's a singleton? I don't think it's the same as as singleton in
    C++ parlance.

    - - -

    If Class X wants to access a class variable and/or constant in Class Y, must a class
    method be defined or is there a direct way to do it?

    Besides the Pickaxe book, can anyone recommend a document that
    describes this a bit more clearly?

    - - -

    So I did a search for "ruby for c++ programmers." on Google and came
    up with exactly one article
    (http://californickation.blogspot.com/2008/02/first-look-at-ruby.html)
    ... one that says "Another funny fact is that searching for "Ruby for
    Java programmers" retrieves a few articles right on the first page while "Ruby for C++ programmers" does not."

    Anyone know of any articles?
     
    Ralph Shnelvar, Nov 27, 2009
    #1
    1. Advertising

  2. Re: Class variables, instance variables, singleton; Ruby v.

    Ralph Shnelvar wrote:
    > Newb here coming from C++
    >
    > Ok, I _think_ I know what a class variable is. It is similar to a
    > static variable in a class in C++. Rght?


    Yes.

    >
    > An instance variable is apart of an instantiated class, right?


    Not an "instantiated class", but a class instance -- which pretty much
    describes everything in Ruby, since everything is an object.

    >
    > What's a singleton? I don't think it's the same as as singleton in
    > C++ parlance.


    But you are wrong.

    >
    > - - -
    >
    > If Class X wants to access a class variable and/or constant in Class Y,
    > must a class
    > method be defined


    For variables, yes. Constants are directly accessible. Remember, Ruby
    has no such thing as public data members in C++.

    > or is there a direct way to do it?


    Only for constants (you know, the Class::CONSTANT syntax).

    >
    > Besides the Pickaxe book, can anyone recommend a document that
    > describes this a bit more clearly?


    The Pickaxe book explains all this *very* clearly.

    >
    > - - -
    >
    > So I did a search for "ruby for c++ programmers." on Google and came
    > up with exactly one article
    > (http://californickation.blogspot.com/2008/02/first-look-at-ruby.html)
    > ... one that says "Another funny fact is that searching for "Ruby for
    > Java programmers" retrieves a few articles right on the first page while
    > "Ruby for C++ programmers" does not."
    >
    > Anyone know of any articles?


    Do you really need something like that? And if you do, won't the Java
    articles suffice?

    Best,
    --
    Marnen Laibow-Koser
    http://www.marnen.org

    --
    Posted via http://www.ruby-forum.com/.
     
    Marnen Laibow-Koser, Nov 27, 2009
    #2
    1. Advertising

  3. On Friday 27 November 2009 01:07:45 pm Ralph Shnelvar wrote:
    > Newb here coming from C++
    >
    > Ok, I _think_ I know what a class variable is. It is similar to a
    > static variable in a class in C++. Rght?


    Yes.

    A quick warning, though: Class variables behave weirdly with inheritance.
    Avoid them. Since all Ruby classes are themselves objects, it makes more sense
    to define an instance variable of the class.

    That is, instead of doing this:

    class Foo
    def bar
    @@some_count += 1
    end
    end

    Do this:

    class Foo
    def self.increment_count
    @some_count += 1
    end
    def bar
    self.class.increment_count
    end
    end

    If you understand how that works, you should be able to understand this
    example, which is how I'd actually do it:

    class Foo
    class << self
    attr_accessor :some_count
    end
    def bar
    self.class.some_count += 1
    end
    end

    I'm sure there's a library somewhere that deals with these more easily.

    > An instance variable is apart of an instantiated class, right?
    >
    > What's a singleton? I don't think it's the same as as singleton in
    > C++ parlance.


    It probably is, but you never know...

    There is actually a Singleton module in the standard library. The idea is to
    prevent you from creating more than one instance of a given class.

    There's also the idea of singleton methods -- for example, you can take two
    objects of a given class, and define a method on one of them, without making a
    new class. Try this in irb:

    a = 'foo'
    b = 'bar'
    def a.speak
    puts self
    end
    a.class == b.class
    a.speak
    b.speak

    This is, by the way, why we don't tend to care what class an object is, but
    rather, how it behaves -- because in Ruby, duck typing is the only kind of
    typing that makes sense, since you really can't know how an object will behave
    just by looking at its class.

    > If Class X wants to access a class variable and/or constant in Class Y,
    > must a class method be defined or is there a direct way to do it?


    Marnen is mostly right. There actually is a way -- class_variable_get -- but
    that's cumbersome, and you shouldn't use it unless you know what you're doing.

    And again, if you're already going to define a class variable, you might
    consider using an instance variable on the class.
     
    David Masover, Nov 27, 2009
    #3
  4. DM> On Friday 27 November 2009 01:07:45 pm Ralph Shnelvar wrote:
    >> Newb here coming from C++
    >>
    >> Ok, I _think_ I know what a class variable is. It is similar to a
    >> static variable in a class in C++. Rght?


    DM> Yes.

    DM> A quick warning, though: Class variables behave weirdly with inheritance.
    DM> Avoid them. Since all Ruby classes are themselves objects, it makes more sense
    DM> to define an instance variable of the class.

    DM> That is, instead of doing this:

    DM> class Foo
    DM> def bar
    DM> @@some_count += 1
    DM> end
    DM> end

    DM> Do this:

    DM> class Foo
    DM> def self.increment_count
    DM> @some_count += 1
    DM> end
    DM> def bar
    DM> self.class.increment_count
    DM> end
    DM> end

    DM> If you understand how that works, you should be able to understand this
    DM> example, which is how I'd actually do it:

    I am clueless what all of the above does. It is WAY over my head.

    I have read that section on how self is set in the Pickaxe book a
    dozen times ... and I'm still lost.

    How would I go about deciphering the meaning of what you wrote, above?

    DM> class Foo
    DM> class << self
    DM> attr_accessor :some_count
    DM> end
    DM> def bar
    DM> self.class.some_count += 1
    DM> end
    DM> end


    And this is even more obscure to me.
     
    Ralph Shnelvar, Nov 27, 2009
    #4
  5. Re: Class variables, instance variables, singleton; Ruby v.

    Ralph Shnelvar wrote:
    [...]
    > I am clueless what all of the above does. It is WAY over my head.
    >
    > I have read that section on how self is set in the Pickaxe book a
    > dozen times ... and I'm still lost.


    Then read it 13 times, or find supplementary material on the Web.
    You've got to understand this stuff if you want to do nontrivial stuff
    in Ruby.

    >
    > How would I go about deciphering the meaning of what you wrote, above?


    The same way you'd decipher anything else. Read it. Understand every
    word and symbol. What you don't understand, look up. Ask questions
    only after you've made a bona fide serious attempt to figure it out
    yourself.

    Best,
    --
    Marnen Laibow-Koser
    http://www.marnen.org

    --
    Posted via http://www.ruby-forum.com/.
     
    Marnen Laibow-Koser, Nov 28, 2009
    #5
  6. Ralph Shnelvar wrote:
    > Newb here coming from C++
    >
    > Ok, I _think_ I know what a class variable is. It is similar to a
    > static variable in a class in C++. Rght?
    >
    > An instance variable is apart of an instantiated class, right?
    >
    > What's a singleton? I don't think it's the same as as singleton in
    > C++ parlance.
    >
    > - - -
    >
    > If Class X wants to access a class variable and/or constant in Class Y,
    > must a class
    > method be defined or is there a direct way to do it?
    >
    > Besides the Pickaxe book, can anyone recommend a document that
    > describes this a bit more clearly?



    'The Ruby Programming Language' by Flanagan and Matsumoto describes the
    differences between class variables and class instances variables. Don't
    know if it will be any clearer than 'Programming Ruby' by Thomas,
    Fowler, and Hunt.

    >
    > - - -
    >
    > So I did a search for "ruby for c++ programmers." on Google and came
    > up with exactly one article
    > (http://californickation.blogspot.com/2008/02/first-look-at-ruby.html)
    > ... one that says "Another funny fact is that searching for "Ruby for
    > Java programmers" retrieves a few articles right on the first page while
    > "Ruby for C++ programmers" does not."
    >
    > Anyone know of any articles?


    --
    Posted via http://www.ruby-forum.com/.
     
    Steve Wilhelm, Nov 28, 2009
    #6
  7. On Friday 27 November 2009 05:00:32 pm Ralph Shnelvar wrote:
    > I am clueless what all of the above does. It is WAY over my head.


    I don't really know what to say, then, other than:

    What is it you don't get?

    I don't mean to be cruel, but there isn't a technical question in here -- not
    really something that I can answer. Instead, all you have is this:

    > How would I go about deciphering the meaning of what you wrote, above?


    Ask me, or ask the group. But ask something specific.

    For example: Is it that you don't understand what I'm doing with 'def
    self.whatever'? Or is it that you don't understand what self.class is? Or are
    the words "Foo" and "bar" confusing? Maybe it was += that threw you off?

    I could go through and attempt to explain every detail of how it works, and I
    could probably do a good job, but it'd be a lot of effort on my part (better
    spent writing a "how to program" book), and you'd probably find it pretty
    condescending.

    Also: Open up irb and mess around. See what happens. For example, type this
    into your irb shell:

    class Foo
    self
    end

    What does that return? Did you learn anything?

    In other words: One very good way to learn is through experimentation. Run the
    examples I've given and see what they do. Run them in a debugger, or sprinkle
    a few 'puts' statements to see what's going on. Run them in irb, and play with
    different versions of them.
     
    David Masover, Nov 28, 2009
    #7
  8. Hi --

    On Sat, 28 Nov 2009, Steve Wilhelm wrote:

    > Ralph Shnelvar wrote:
    >> Newb here coming from C++
    >>
    >> Ok, I _think_ I know what a class variable is. It is similar to a
    >> static variable in a class in C++. Rght?
    >>
    >> An instance variable is apart of an instantiated class, right?
    >>
    >> What's a singleton? I don't think it's the same as as singleton in
    >> C++ parlance.
    >>
    >> - - -
    >>
    >> If Class X wants to access a class variable and/or constant in Class Y,
    >> must a class
    >> method be defined or is there a direct way to do it?
    >>
    >> Besides the Pickaxe book, can anyone recommend a document that
    >> describes this a bit more clearly?

    >
    >
    > 'The Ruby Programming Language' by Flanagan and Matsumoto describes the
    > differences between class variables and class instances variables. Don't
    > know if it will be any clearer than 'Programming Ruby' by Thomas,
    > Fowler, and Hunt.


    And of course this is one of the (many) problems with class variables:
    they make obscure the otherwise rather simple notion that classes can
    have instance variables because classes are objects and any object can
    have instance variables.


    David

    --
    THE COMPLEAT RUBYIST, Ruby training with Black/Brown/McAnally!
    January 22-23, Tampa, Florida
    Info and registration at http://www.thecompleatrubyist.com
    --------------------------------------
    My new job: http://tinyurl.com/yfpn9hz
     
    David A. Black, Nov 28, 2009
    #8
  9. DM> On Friday 27 November 2009 05:00:32 pm Ralph Shnelvar wrote:
    >> I am clueless what all of the above does. It is WAY over my head.


    DM> I don't really know what to say, then, other than:

    DM> What is it you don't get?

    DM> I don't mean to be cruel, but there isn't a technical question in here -- not
    DM> really something that I can answer. Instead, all you have is this:

    >> How would I go about deciphering the meaning of what you wrote, above?


    DM> Ask me, or ask the group. But ask something specific.

    It is the gestalt ... the world-view ... that I am not getting. It is
    not the specifics that are the difficulty.

    DM> For example: Is it that you don't understand what I'm doing with 'def
    DM> self.whatever'? Or is it that you don't understand what self.class is? Or are
    DM> the words "Foo" and "bar" confusing? Maybe it was += that threw you off?

    DM> I could go through and attempt to explain every detail of how it works, and I
    DM> could probably do a good job, but it'd be a lot of effort on my part (better
    DM> spent writing a "how to program" book), and you'd probably find it pretty
    DM> condescending.

    DM> Also: Open up irb and mess around. See what happens. For example, type this
    DM> into your irb shell:

    DM> class Foo
    DM> self
    DM> end

    DM> What does that return? Did you learn anything?

    DM> In other words: One very good way to learn is through experimentation. Run the
    DM> examples I've given and see what they do. Run them in a debugger, or sprinkle
    DM> a few 'puts' statements to see what's going on. Run them in irb, and play with
    DM> different versions of them.

    David, I thank you for trying to help.

    There is a gestalt here that I am missing.

    As the original poster, I said I'm coming from a C++ environment. I'm
    actually pretty good there. Well, more than pretty good.

    I've had SNOBOL, SPITBOL, and APL (several years) experience. I'm familiar with
    interpreted code.

    So ... there's something at a high level that is going on in your code that I'm unable to wrap
    my head around.
     
    Ralph Shnelvar, Nov 28, 2009
    #9
  10. DAB> And of course this is one of the (many) problems with class variables:
    DAB> they make obscure the otherwise rather simple notion that classes can
    DAB> have instance variables because classes are objects and any object can
    DAB> have instance variables.

    David ... this may be the higher-level gestalt that I was missing. It
    sure sounds like it.

    Let me flesh out my questions/comments about this paragraph so that you and
    others have something specific to answer. Let's call the classed F &
    G.

    (1) OK, classes are (i) objects; (ii) are executable code.


    (2) If I do the following
    class F
    end
    f = F.new
    F.class # class
    f.class # F
    this makes sense to me.

    What (relevant and important conceptually) messages (other than "new")
    can I send to a class? But see (3), below.



    (3)
    class F
    def sub1
    @@x = 1
    end
    end

    class G
    self.sub1
    @@x=2
    end
    end

    # Why? Didn't the interpreter "see" @@x in class F?
    F.class_variables # []

    # makes sense
    G.class_variables # ["@@x"]

    f = F.new

    # Why? Shouldn't the method inherit from the class?
    f.class_variables # undefined method

    f.sub1 # 1

    # makes sense. class variable now explicitly executed
    F.class_variables # ["@@x"]

    # How to use class_variable_get if the method is private???
    F.class_variable_get:)@@x) # error private method!



    OK, that should do it for now.
     
    Ralph Shnelvar, Nov 28, 2009
    #10
  11. Re: Class variables, instance variables, singleton; Ruby v.

    Ralph Shnelvar wrote:
    [...]
    > Let me flesh out my questions/comments about this paragraph so that you
    > and
    > others have something specific to answer. Let's call the classed F &
    > G.
    >
    > (1) OK, classes are (i) objects;


    Right.

    > (ii) are executable code.


    Wrong. Class *definitions* are executable code.

    >
    >
    > (2) If I do the following
    > class F
    > end
    > f = F.new
    > F.class # class
    > f.class # F
    > this makes sense to me.
    >
    > What (relevant and important conceptually) messages (other than "new")
    > can I send to a class?


    See the documentation for class Class.

    > But see (3), below.
    >
    >
    >
    > (3)
    > class F
    > def sub1
    > @@x = 1
    > end
    > end
    >
    > class G
    > self.sub1
    > @@x=2
    > end
    > end
    >
    > # Why? Didn't the interpreter "see" @@x in class F?
    > F.class_variables # []


    Probably not, since you haven't called the function yet!

    >
    > # makes sense
    > G.class_variables # ["@@x"]


    I'm actually rather surprised by this.

    >
    > f = F.new
    >
    > # Why? Shouldn't the method inherit from the class?
    > f.class_variables # undefined method


    No! class_variables is a class method of F. Instances do not get
    access to their class' class methods, because they don't inherit from
    the Class object in the conventional sense. The Class object is a
    little bit like a JavaScript prototype, if that helps.

    If it doesn't...well, I don't know what to say. If you're really as
    good a C++ programmer as you claim to be, then you should be having no
    trouble at all with the difference between class and instance methods.

    >
    > f.sub1 # 1
    >
    > # makes sense. class variable now explicitly executed
    > F.class_variables # ["@@x"]
    >
    > # How to use class_variable_get if the method is private???
    > F.class_variable_get:)@@x) # error private method!
    >


    Just don't. You're not meant to be getting at class variables from
    outside the class. Use an accessor function if you need it.

    (There is a way to call private methods from outside, but I will leave
    you to find it out on your own. It's not generally a good thing, and
    I'm not going to hand you a dangerous tool until you understand when not
    to use it.)

    >
    >
    > OK, that should do it for now.


    Best,
    --
    Marnen Laibow-Koser
    http://www.marnen.org

    --
    Posted via http://www.ruby-forum.com/.
     
    Marnen Laibow-Koser, Nov 28, 2009
    #11
  12. Re: Class variables, instance variables, singleton; Ruby v.

    >> (2) If I do the following
    >> class F
    >> end
    >> f = F.new
    >> F.class # class
    >> f.class # F
    >> this makes sense to me.
    >>
    >> What (relevant and important conceptually) messages (other than "new")
    >> can I send to a class?


    MLK> See the documentation for class Class.

    >> But see (3), below.
    >>
    >>
    >>
    >> (3)
    >> class F
    >> def sub1
    >> @@x = 1
    >> end
    >> end
    >>
    >> class G
    >> self.sub1
    >> @@x=2
    >> end
    >> end
    >>
    >> # Why? Didn't the interpreter "see" @@x in class F?
    >> F.class_variables # []


    MLK> Probably not, since you haven't called the function yet!

    Didn't the interpreter parse it?

    If I do
    class X
    def y
    xyzzy = 3++
    end
    end

    then the interpreter/parser will complain immediately that there was a
    syntax error even though the function method y was not executed.

    >>
    >> # makes sense
    >> G.class_variables # ["@@x"]


    MLK> I'm actually rather surprised by this.

    I made a mistake. I apologize.
    class G
    def self.sub1
    @@x=2
    end
    end

    G.class_variables # []

    (I must have run the function accidentally. Sorry.)

    >>
    >> f = F.new
    >>
    >> # Why? Shouldn't the method inherit from the class?
    >> f.class_variables # undefined method


    MLK> No! class_variables is a class method of F. Instances do not get
    MLK> access to their class' class methods, because they don't inherit from
    MLK> the Class object in the conventional sense. The Class object is a
    MLK> little bit like a JavaScript prototype, if that helps.

    MLK> If it doesn't...well, I don't know what to say. If you're really as
    MLK> good a C++ programmer as you claim to be, then you should be having no
    MLK> trouble at all with the difference between class and instance methods.

    In C++, instances have access to the static variables and functions of
    the class.

    They don't inherit it ... but merely have access to it as if they
    inherited it.

    >>
    >> f.sub1 # 1
    >>
    >> # makes sense. class variable now explicitly executed
    >> F.class_variables # ["@@x"]
    >>
    >> # How to use class_variable_get if the method is private???
    >> F.class_variable_get:)@@x) # error private method!
    >>


    MLK> Just don't. You're not meant to be getting at class variables from
    MLK> outside the class. Use an accessor function if you need it.

    MLK> (There is a way to call private methods from outside, but I will leave
    MLK> you to find it out on your own. It's not generally a good thing, and
    MLK> I'm not going to hand you a dangerous tool until you understand when not
    MLK> to use it.)

    So ... when _can_ I use class_variable_get ???
     
    Ralph Shnelvar, Nov 28, 2009
    #12
  13. On Sat, Nov 28, 2009 at 8:00 AM, Ralph Shnelvar <> wrote:
    > DAB> And of course this is one of the (many) problems with class variable=

    s:
    > DAB> they make obscure the otherwise rather simple notion that classes ca=

    n
    > DAB> have instance variables because classes are objects and any object c=

    an
    > DAB> have instance variables.
    >
    > David ... this may be the higher-level gestalt that I was missing. =A0It
    > sure sounds like it.
    >
    > Let me flesh out my questions/comments about this paragraph so that you a=

    nd
    > others have something specific to answer. =A0Let's call the classed =A0F =

    &
    > G.
    >
    > (1) OK, classes are (i) objects; (ii) are executable code.



    I wouldn't say that classes are executable code. However the
    difference between Ruby and C++ here is that in C++ a class is really
    just a C Struct definition with new features like virtual member
    functions and inheritance. It's a static compile time construct.

    In Ruby on the other hand, classes are defined at run time as code is
    executed, and the stuff inside a class definition is executable code.

    Another related difference is that in C++ the class describes which
    instance variables are present in every instance of that class by
    virtue of the instance variables (members) being statically declared.

    In Ruby an object gets instance variables one by one only when it
    executes a method which sets the instance variable. Since classes are
    objects this applies to classes as well.

    A primary purpose of a class is to collect method implementations
    which will be part of the repertoire of instances of that class.

    So for example

    class A
    # At this point the class has no class instance variables
    @class_instance_variable1 =3D 42 # This statement is executed when
    the class def is, so
    # after this A
    has a class instance variable

    # The following defines a method which will be in the repertoire
    of instances of A or any
    # of its subclasses
    def some_method
    @instance_var =3D "Hello"
    end

    # The self. makes the following a method of the class A. We
    call this a class method
    # it will also be in the repertoire of any class objects which
    subclass A (but not their instances)
    def self.a_class_method
    @class_instance_variable2 =3D [1, 2, 3]
    end
    end

    a =3D A.new
    # At this point of execution:
    #
    # The class A has ONE class instance variable @class_instance_variable1
    #
    # a, which is an instance of A, has NO instance variables

    a.some_method

    # And now a has an instance variable named @instance_var

    A.a_class_method
    # And now A has another class instance variable @class_instance_variable2



    > (2) If I do the following
    > =A0 =A0 =A0class F
    > =A0 =A0 =A0end
    > =A0 =A0 =A0f =3D F.new
    > =A0 =A0 =A0F.class =A0# class
    > =A0 =A0 =A0f.class =A0# F
    > this makes sense to me.
    >
    > What (relevant and important conceptually) messages (other than "new")
    > can I send to a class? =A0But see (3), below.


    Well like any object the answer to that depends on the class. All
    classes are instances of Class, which defines three methods, only two
    of which are normally called by user code.

    Class#allocate which actually allocates the storage for a new
    instance, this is rarely if ever overriden or called directly
    Class#new which calls allocate to get a new instance and then calls
    intialialize on the new instance passing any arguments along. This is
    called often but rarely overridden.
    Class#superclass which returns the superclass of the class, again
    called but almost never overridden.

    In addition Class is a subclass of Module, and inherits from module
    the ability to collect methods and to serve as a nested namespace. So
    every class object has the instance methods defined in Module as part
    of its repertoire, I'll leave you to look these up.

    And of course the instance methods defined in Object and the module
    Kernel (which is included by Object) are part of the repertoire of
    very Object and therefore every object which happens to be a class.

    Some Ruby standard library classes like Array, Dir, File and others
    define additional class methods specific to the class and its
    subclasses.


    > (3)
    > =A0 =A0class F
    > =A0 =A0 =A0def sub1
    > =A0 =A0 =A0 =A0@@x =3D 1
    > =A0 =A0 =A0end
    > =A0 =A0end
    >
    > =A0 =A0class G
    > =A0 =A0 =A0self.sub1
    > =A0 =A0 =A0 =A0@@x=3D2
    > =A0 =A0 =A0end
    > =A0 =A0end
    >
    > =A0 =A0# Why? =A0Didn't the interpreter "see" @@x in class F?
    > =A0 =A0F.class_variables =A0# []


    See my explanation above. In this regard class variables like
    instance variables

    F doesn't have any class variables because the sub1 method hasn't been exec=
    uted.

    G does because you execute sub1 inside its class definition code. I
    assume that you actually defined G as a subclass of F or you would
    have gotten an undefined sub1 method error.

    And you have invalid syntax in that snippet because there's an extra end

    class G
    self.sub1
    @@x =3D 2
    end # this ends the class def which consists of two
    end

    > =A0 =A0# makes sense
    > =A0 =A0G.class_variables =A0# ["@@x"]
    >
    > =A0 =A0f =3D F.new
    >
    > =A0 =A0# Why? =A0Shouldn't the method inherit from the class?
    > =A0 =A0f.class_variables =A0# undefined method


    Because f is an instance of F, and is not a class, class_variables is
    a method defined in Module, not Object or kernel
    >
    > =A0 =A0f.sub1 =A0# 1
    >
    > =A0 =A0# makes sense. =A0class variable now explicitly executed
    > =A0 =A0F.class_variables # ["@@x"]
    >
    > =A0 =A0# How to use class_variable_get if the method is private???
    > =A0 =A0F.class_variable_get:)@@x) =A0# error private method!


    F.send:)class_variable_get, :mad:@x)


    As others have pointed out class variables are a pretty wonky area of
    Ruby. In Ruby 1.8 if G is a actually a subclass of F, then whether or
    not @@x is the same instance variable for both depends in some cases
    on whether or not F got its instance variable before G did or not.

    When a class variable is initialized Ruby 1.8 looks through the chain
    of superclasses to see if a class variable with that name already
    exists, and if so uses that definition. If not it defines it for the
    current class. Ruby 1.9 changed that so that now class variables are
    no longer shared with subclasses.


    Now it may seem hard or harsh, but I'd recommend that you try to
    forget what you know about C++ when learning Ruby.

    Although C++ and Ruby are both said to be object-oriented, they come
    from two very different views of what that means. C++ is the epitome
    of what Ralph Johnson calls the "Software Engineering" school, where
    objects are seen as an extension of abstract data types. Ruby is of
    what he calls the "Mystical" school where objects are seen as entities
    which encapsulate both the data representation and the methods which
    operate on the data, and which interact with other objects only by
    message invocation of methods, looked up by name at runtime. Java is
    influenced by the SE school, but is more dynamic in other regards.
    Other mystical languages include Smalltalk, Self, and JavaScript
    although JavaScript is not fundamentally OO.

    --=20
    Rick DeNatale

    Blog: http://talklikeaduck.denhaven2.com/
    Twitter: http://twitter.com/RickDeNatale
    WWR: http://www.workingwithrails.com/person/9021-rick-denatale
    LinkedIn: http://www.linkedin.com/in/rickdenatale
     
    Rick DeNatale, Nov 28, 2009
    #13
  14. Re: Class variables, instance variables, singleton; Ruby v.

    On Saturday 28 November 2009 08:43:30 am Ralph Shnelvar wrote:

    > >> But see (3), below.
    > >>
    > >>
    > >>
    > >> (3)
    > >> class F
    > >> def sub1
    > >> @@x = 1
    > >> end
    > >> end
    > >>
    > >> class G
    > >> self.sub1
    > >> @@x=2
    > >> end
    > >> end
    > >>
    > >> # Why? Didn't the interpreter "see" @@x in class F?
    > >> F.class_variables # []

    >
    > MLK> Probably not, since you haven't called the function yet!
    >
    > Didn't the interpreter parse it?
    >
    > If I do
    > class X
    > def y
    > xyzzy = 3++
    > end
    > end
    >
    > then the interpreter/parser will complain immediately that there was a
    > syntax error even though the function method y was not executed.


    Yes, syntax errors are caught immediately by parsing. But think of instance
    variables as a hash associated with the object and it might be more clear. For
    example, if you did this:

    SomeHash = {}
    def foo
    SomeHash[:x] = :y
    end

    Would you expect SomeHash[:x] to exist just because you defined that method?

    Now, I don't know whether instance variables are _actually_ implemented as a
    hash. It might well be something much more efficient, but it behaves like a
    hash, so that makes sense.

    Also, consider: The method in question may _never_ be called. Why should Ruby
    bother to create a variable that may never be used? That would be just as
    foolish as implying that SomeHash[:x] exists before foo is called in my
    example above. Sure, you could create it and set it to nil, but that'd be
    pointless.

    > In C++, instances have access to the static variables and functions of
    > the class.
    >
    > They don't inherit it ... but merely have access to it as if they
    > inherited it.


    Instances indeed get access to class variables associated with that instance,
    but again, class variables behave weirdly. But here's a quick example to help
    clarify things:

    SomeClass.new

    Would you expect an object created that way to have a 'new' method of its own?
    That is, would this make any sense:

    SomeClass.new.new

    Similarly, do the methods available at class creation time make any sense in
    an object? For example, when creating a class:

    class Foo
    attr_accessor :bar
    end

    You might think attr_accessor is a keyword. It isn't, it's just a method on
    Class, so it's a class method on Foo.

    There is no proper analog to "static functions" in C++, by the way -- they're
    just methods on the class. But again, they aren't included into the instance
    -- you access them on the class, just like you would with any other object.

    So let me return to some simple examples that I hope make sense. Let's create
    a counter for the number of instances that have been created.

    class Foo
    def self.count
    @count
    end
    def self.increment_count
    @count ||= 0
    @count += 1
    end
    end

    This should be easy to understand. (If it's not, pretend I defined them
    without self, and see if they make sense.)

    Now, go define them, and play with them in irb. You wouldn't create any
    instances of Foo yet, but you can do things like this:

    Foo.count
    Foo.increment_count
    Foo.count
    Foo.increment_count
    Foo.increment_count
    Foo.count

    Go try that in irb, and see if the result makes sense.

    Now let's move on. Keep the same class above, but add this -- if you're in the
    same irb session, you can just re-open the class:

    class Foo
    def initialize
    Foo.increment_count
    end
    end

    Now our counter should work as expected:

    Foo.count
    f = Foo.new
    Foo.count

    It won't tell you how many Foo objects actually exist. It's more a count of
    how many have ever been created.

    Also, if you understand this so far, go back to my earlier example that was
    "way over your head" -- see if it makes sense. I'll give you an example -- if
    you have a variable f, which is an instance of class Foo, what is f.class?

    And if you're inside the initialize method of f, what is self? And what is
    self.class?

    > MLK> (There is a way to call private methods from outside, but I will leave
    > MLK> you to find it out on your own. It's not generally a good thing, and
    > MLK> I'm not going to hand you a dangerous tool until you understand when
    > not MLK> to use it.)
    >
    > So ... when _can_ I use class_variable_get ???


    You can use it whenever you want. When _should_ you use it?

    Like instance_variable_get, it's designed for metaprogramming -- that is, when
    you're trying to access a variable, but its name is dynamic.

    I'll give you an example of when instance_variable_get might be used. Remember
    attr_reader? (If not, look it up...) Now, for speed, attr_reader is defined
    in C, but it can be defined in Ruby. Here's the obvious 'eval' solution:

    class Module
    def attr_reader *names
    names.each do |name|
    eval "def #{name}; @#{name}; end"
    end
    end
    end

    But there are many reasons I dislike eval. Here's the solution I'd prefer:

    class Module
    def attr_reader *names
    names.each do |name|
    var_name = :"@#{name}"
    define_method name do
    instance_variable_get var_name
    end
    end
    end
    end

    I don't expect you to follow every detail here. The use of define_method is an
    advanced topic already. Hopefully, though, the fact that you already know how
    to use attr_reader should give you an idea of how that works.

    Also, I don't really expect you to need any of this yet -- attr_reader,
    attr_writer, and attr_accessor should already do everything you need.
     
    David Masover, Nov 28, 2009
    #14
  15. Rick,

    I know I am top-posting but ...

    This has been super-helpful. It presents a helicopter view of what
    was, uh, mystifying me. :)

    Many, many, thanks.

    Ralph


    Saturday, November 28, 2009, 7:46:26 AM, you wrote:

    RD> On Sat, Nov 28, 2009 at 8:00 AM, Ralph Shnelvar <> wrote:
    >> DAB> And of course this is one of the (many) problems with class variables:
    >> DAB> they make obscure the otherwise rather simple notion that classes can
    >> DAB> have instance variables because classes are objects and any object can
    >> DAB> have instance variables.
    >>
    >> David ... this may be the higher-level gestalt that I was missing.  It
    >> sure sounds like it.
    >>
    >> Let me flesh out my questions/comments about this paragraph so that you and
    >> others have something specific to answer.  Let's call the classed  F &
    >> G.
    >>
    >> (1) OK, classes are (i) objects; (ii) are executable code.



    RD> I wouldn't say that classes are executable code. However the
    RD> difference between Ruby and C++ here is that in C++ a class is really
    RD> just a C Struct definition with new features like virtual member
    RD> functions and inheritance. It's a static compile time construct.

    RD> In Ruby on the other hand, classes are defined at run time as code is
    RD> executed, and the stuff inside a class definition is executable code.

    RD> Another related difference is that in C++ the class describes which
    RD> instance variables are present in every instance of that class by
    RD> virtue of the instance variables (members) being statically declared.

    RD> In Ruby an object gets instance variables one by one only when it
    RD> executes a method which sets the instance variable. Since classes are
    RD> objects this applies to classes as well.

    RD> A primary purpose of a class is to collect method implementations
    RD> which will be part of the repertoire of instances of that class.

    RD> So for example

    RD> class A
    RD> # At this point the class has no class instance variables
    RD> @class_instance_variable1 = 42 # This statement is executed when
    RD> the class def is, so
    RD> # after this A
    RD> has a class instance variable

    RD> # The following defines a method which will be in the repertoire
    RD> of instances of A or any
    RD> # of its subclasses
    RD> def some_method
    RD> @instance_var = "Hello"
    RD> end

    RD> # The self. makes the following a method of the class A. We
    RD> call this a class method
    RD> # it will also be in the repertoire of any class objects which
    RD> subclass A (but not their instances)
    RD> def self.a_class_method
    RD> @class_instance_variable2 = [1, 2, 3]
    RD> end
    RD> end

    RD> a = A.new
    RD> # At this point of execution:
    RD> #
    RD> # The class A has ONE class instance variable @class_instance_variable1
    RD> #
    RD> # a, which is an instance of A, has NO instance variables

    RD> a.some_method

    RD> # And now a has an instance variable named @instance_var

    RD> A.a_class_method
    RD> # And now A has another class instance variable @class_instance_variable2



    >> (2) If I do the following
    >>      class F
    >>      end
    >>      f = F.new
    >>      F.class  # class
    >>      f.class  # F
    >> this makes sense to me.
    >>
    >> What (relevant and important conceptually) messages (other than "new")
    >> can I send to a class?  But see (3), below.


    RD> Well like any object the answer to that depends on the class. All
    RD> classes are instances of Class, which defines three methods, only two
    RD> of which are normally called by user code.

    RD> Class#allocate which actually allocates the storage for a new
    RD> instance, this is rarely if ever overriden or called directly
    RD> Class#new which calls allocate to get a new instance and then calls
    RD> intialialize on the new instance passing any arguments along. This is
    RD> called often but rarely overridden.
    RD> Class#superclass which returns the superclass of the class, again
    RD> called but almost never overridden.

    RD> In addition Class is a subclass of Module, and inherits from module
    RD> the ability to collect methods and to serve as a nested namespace. So
    RD> every class object has the instance methods defined in Module as part
    RD> of its repertoire, I'll leave you to look these up.

    RD> And of course the instance methods defined in Object and the module
    RD> Kernel (which is included by Object) are part of the repertoire of
    RD> very Object and therefore every object which happens to be a class.

    RD> Some Ruby standard library classes like Array, Dir, File and others
    RD> define additional class methods specific to the class and its
    RD> subclasses.


    >> (3)
    >>    class F
    >>      def sub1
    >>        @@x = 1
    >>      end
    >>    end
    >>
    >>    class G
    >>      self.sub1
    >>        @@x=2
    >>      end
    >>    end
    >>
    >>    # Why?  Didn't the interpreter "see" @@x in class F?
    >>    F.class_variables  # []


    RD> See my explanation above. In this regard class variables like
    RD> instance variables

    RD> F doesn't have any class variables because the sub1 method hasn't been executed.

    RD> G does because you execute sub1 inside its class definition code. I
    RD> assume that you actually defined G as a subclass of F or you would
    RD> have gotten an undefined sub1 method error.

    RD> And you have invalid syntax in that snippet because there's an extra end

    RD> class G
    RD> self.sub1
    RD> @@x = 2
    RD> end # this ends the class def which consists of two
    RD> end

    >>    # makes sense
    >>    G.class_variables  # ["@@x"]
    >>
    >>    f = F.new
    >>
    >>    # Why?  Shouldn't the method inherit from the class?
    >>    f.class_variables  # undefined method


    RD> Because f is an instance of F, and is not a class, class_variables is
    RD> a method defined in Module, not Object or kernel
    >>
    >>    f.sub1  # 1
    >>
    >>    # makes sense.  class variable now explicitly executed
    >>    F.class_variables # ["@@x"]
    >>
    >>    # How to use class_variable_get if the method is private???
    >>    F.class_variable_get:)@@x)  # error private method!


    RD> F.send:)class_variable_get, :mad:@x)


    RD> As others have pointed out class variables are a pretty wonky area of
    RD> Ruby. In Ruby 1.8 if G is a actually a subclass of F, then whether or
    RD> not @@x is the same instance variable for both depends in some cases
    RD> on whether or not F got its instance variable before G did or not.

    RD> When a class variable is initialized Ruby 1.8 looks through the chain
    RD> of superclasses to see if a class variable with that name already
    RD> exists, and if so uses that definition. If not it defines it for the
    RD> current class. Ruby 1.9 changed that so that now class variables are
    RD> no longer shared with subclasses.


    RD> Now it may seem hard or harsh, but I'd recommend that you try to
    RD> forget what you know about C++ when learning Ruby.

    RD> Although C++ and Ruby are both said to be object-oriented, they come
    RD> from two very different views of what that means. C++ is the epitome
    RD> of what Ralph Johnson calls the "Software Engineering" school, where
    RD> objects are seen as an extension of abstract data types. Ruby is of
    RD> what he calls the "Mystical" school where objects are seen as entities
    RD> which encapsulate both the data representation and the methods which
    RD> operate on the data, and which interact with other objects only by
    RD> message invocation of methods, looked up by name at runtime. Java is
    RD> influenced by the SE school, but is more dynamic in other regards.
    RD> Other mystical languages include Smalltalk, Self, and JavaScript
    RD> although JavaScript is not fundamentally OO.




    --
    Best regards,
    Ralph mailto:
     
    Ralph Shnelvar, Nov 28, 2009
    #15
  16. Re: Class variables, instance variables, singleton; Ruby v.

    DM> On Saturday 28 November 2009 08:43:30 am Ralph Shnelvar wrote:

    >> >> But see (3), below.
    >> >>
    >> >>
    >> >>
    >> >> (3)
    >> >> class F
    >> >> def sub1
    >> >> @@x = 1
    >> >> end
    >> >> end
    >> >>
    >> >> class G
    >> >> self.sub1
    >> >> @@x=2
    >> >> end
    >> >> end
    >> >>
    >> >> # Why? Didn't the interpreter "see" @@x in class F?
    >> >> F.class_variables # []

    >>
    >> MLK> Probably not, since you haven't called the function yet!
    >>
    >> Didn't the interpreter parse it?
    >>
    >> If I do
    >> class X
    >> def y
    >> xyzzy = 3++
    >> end
    >> end
    >>
    >> then the interpreter/parser will complain immediately that there was a
    >> syntax error even though the function method y was not executed.


    DM> Yes, syntax errors are caught immediately by parsing. But think of instance
    DM> variables as a hash associated with the object and it might be more clear. For
    DM> example, if you did this:

    DM> SomeHash = {}
    DM> def foo
    DM> SomeHash[:x] = :y
    DM> end

    DM> Would you expect SomeHash[:x] to exist just because you defined that method?

    DM> Now, I don't know whether instance variables are _actually_ implemented as a
    DM> hash. It might well be something much more efficient, but it behaves like a
    DM> hash, so that makes sense.

    DM> Also, consider: The method in question may _never_ be called. Why should Ruby
    DM> bother to create a variable that may never be used? That would be just as
    DM> foolish as implying that SomeHash[:x] exists before foo is called in my
    DM> example above. Sure, you could create it and set it to nil, but that'd be
    DM> pointless.

    >> In C++, instances have access to the static variables and functions of
    >> the class.
    >>
    >> They don't inherit it ... but merely have access to it as if they
    >> inherited it.


    DM> Instances indeed get access to class variables associated with that instance,
    DM> but again, class variables behave weirdly. But here's a quick example to help
    DM> clarify things:

    DM> SomeClass.new

    DM> Would you expect an object created that way to have a 'new' method of its own?
    DM> That is, would this make any sense:

    DM> SomeClass.new.new

    DM> Similarly, do the methods available at class creation time make any sense in
    DM> an object? For example, when creating a class:

    DM> class Foo
    DM> attr_accessor :bar
    DM> end

    DM> You might think attr_accessor is a keyword. It isn't, it's just a method on
    DM> Class, so it's a class method on Foo.

    DM> There is no proper analog to "static functions" in C++, by the way -- they're
    DM> just methods on the class. But again, they aren't included into the instance
    DM> -- you access them on the class, just like you would with any other object.

    DM> So let me return to some simple examples that I hope make sense. Let's create
    DM> a counter for the number of instances that have been created.

    DM> class Foo
    DM> def self.count
    DM> @count
    DM> end
    DM> def self.increment_count
    DM> @count ||= 0
    DM> @count += 1
    DM> end
    DM> end

    DM> This should be easy to understand. (If it's not, pretend I defined them
    DM> without self, and see if they make sense.)

    DM> Now, go define them, and play with them in irb. You wouldn't create any
    DM> instances of Foo yet, but you can do things like this:

    DM> Foo.count
    DM> Foo.increment_count
    DM> Foo.count
    DM> Foo.increment_count
    DM> Foo.increment_count
    DM> Foo.count

    DM> Go try that in irb, and see if the result makes sense.

    DM> Now let's move on. Keep the same class above, but add this -- if you're in the
    DM> same irb session, you can just re-open the class:

    DM> class Foo
    DM> def initialize
    DM> Foo.increment_count
    DM> end
    DM> end

    DM> Now our counter should work as expected:

    DM> Foo.count
    DM> f = Foo.new
    DM> Foo.count

    DM> It won't tell you how many Foo objects actually exist. It's more a count of
    DM> how many have ever been created.

    Cool.

    Is there a way to tell how many instances actually exist? Is there
    anything like a destructor for class instances? Just curious.

    DM> Also, if you understand this so far, go back to my earlier example that was
    DM> "way over your head" -- see if it makes sense. I'll give you an example -- if
    DM> you have a variable f, which is an instance of class Foo, what is f.class?

    DM> And if you're inside the initialize method of f, what is self? And what is
    DM> self.class?

    >> MLK> (There is a way to call private methods from outside, but I will leave
    >> MLK> you to find it out on your own. It's not generally a good thing, and
    >> MLK> I'm not going to hand you a dangerous tool until you understand when
    >> not MLK> to use it.)
    >>
    >> So ... when _can_ I use class_variable_get ???


    DM> You can use it whenever you want. When _should_ you use it?

    DM> Like instance_variable_get, it's designed for metaprogramming -- that is, when
    DM> you're trying to access a variable, but its name is dynamic.

    DM> I'll give you an example of when instance_variable_get might be used. Remember
    DM> attr_reader? (If not, look it up...) Now, for speed, attr_reader is defined
    DM> in C, but it can be defined in Ruby. Here's the obvious 'eval' solution:

    DM> class Module
    DM> def attr_reader *names
    DM> names.each do |name|
    DM> eval "def #{name}; @#{name}; end"
    DM> end
    DM> end
    DM> end

    DM> But there are many reasons I dislike eval. Here's the solution I'd prefer:

    DM> class Module
    DM> def attr_reader *names
    DM> names.each do |name|
    DM> var_name = :"@#{name}"
    DM> define_method name do
    DM> instance_variable_get var_name
    DM> end
    DM> end
    DM> end
    DM> end

    So, basically, the reason that instance_variable_get is private to
    Module is that one does not wish make breaking encapsulation too easy?

    I mean, it seems easy enough to break encapsulation by adding an
    accessor, right?

    DM> I don't expect you to follow every detail here. The use of define_method is an
    DM> advanced topic already. Hopefully, though, the fact that you already know how
    DM> to use attr_reader should give you an idea of how that works.

    DM> Also, I don't really expect you to need any of this yet -- attr_reader,
    DM> attr_writer, and attr_accessor should already do everything you need.

    This is, actually, very lucid. I had few problems following any of it.

    Also ... I _did_ try (successfully, I hope) to follow every detail.

    Many many thanks.
     
    Ralph Shnelvar, Nov 28, 2009
    #16
  17. Re: Class variables, instance variables, singleton; Ruby v.

    Ralph Shnelvar wrote
    [...]
    >
    >>> MLK> (There is a way to call private methods from outside, but I will leave
    >>> MLK> you to find it out on your own. It's not generally a good thing, and
    >>> MLK> I'm not going to hand you a dangerous tool until you understand when
    >>> not MLK> to use it.)
    >>>
    >>> So ... when _can_ I use class_variable_get ???

    >
    > DM> You can use it whenever you want. When _should_ you use it?
    >
    > DM> Like instance_variable_get, it's designed for metaprogramming --
    > that is, when
    > DM> you're trying to access a variable, but its name is dynamic.
    >
    > DM> I'll give you an example of when instance_variable_get might be
    > used. Remember
    > DM> attr_reader? (If not, look it up...) Now, for speed, attr_reader is
    > defined
    > DM> in C, but it can be defined in Ruby. Here's the obvious 'eval'
    > solution:
    >
    > DM> class Module
    > DM> def attr_reader *names
    > DM> names.each do |name|
    > DM> eval "def #{name}; @#{name}; end"
    > DM> end
    > DM> end
    > DM> end
    >
    > DM> But there are many reasons I dislike eval. Here's the solution I'd
    > prefer:
    >
    > DM> class Module
    > DM> def attr_reader *names
    > DM> names.each do |name|
    > DM> var_name = :"@#{name}"
    > DM> define_method name do
    > DM> instance_variable_get var_name
    > DM> end
    > DM> end
    > DM> end
    > DM> end
    >
    > So, basically, the reason that instance_variable_get is private to
    > Module is that one does not wish make breaking encapsulation too easy?
    >
    > I mean, it seems easy enough to break encapsulation by adding an
    > accessor, right?


    Wrong. attr_accessor really doesn't break encapsulation in the
    conventional sense -- that is, it's not even remotely equivalent to
    declaring a public data member in C++ or Java. Ruby has *no way* to
    make instance variables public. This is a Good Thing.

    attr_accessor just defines getter and setter methods -- and keeps the
    variable encapsulated. When you do
    @p = Person.new
    @p.name = 'Ralph'
    puts @p.name

    the caller is making no assumptions at all about whether @p has an
    instance variable called @name. It is impossible to tell from the code
    supplied -- that detail is completely encapsulated. We assume that @p
    has methods called :name and :name= , but that leaks nothing of @p's
    internals.

    Best,
    --
    Marnen Laibow-Koser
    http://www.marnen.org

    >
    > DM> I don't expect you to follow every detail here. The use of
    > define_method is an
    > DM> advanced topic already. Hopefully, though, the fact that you already
    > know how
    > DM> to use attr_reader should give you an idea of how that works.
    >
    > DM> Also, I don't really expect you to need any of this yet --
    > attr_reader,
    > DM> attr_writer, and attr_accessor should already do everything you
    > need.
    >
    > This is, actually, very lucid. I had few problems following any of it.
    >
    > Also ... I _did_ try (successfully, I hope) to follow every detail.
    >
    > Many many thanks.


    --
    Posted via http://www.ruby-forum.com/.
     
    Marnen Laibow-Koser, Nov 28, 2009
    #17
  18. Re: Class variables, instance variables, singleton; Ruby v.

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1


    On Nov 28, 2009, at 5:12 PM, Ralph Shnelvar wrote:
    >
    > So, basically, the reason that instance_variable_get is private to
    > Module is that one does not wish make breaking encapsulation too easy?
    >
    > I mean, it seems easy enough to break encapsulation by adding an
    > accessor, right?


    The reason that instance_variable_get exists is solely to allow dynamic
    lookup of instance variables to work in cases like define_method. It =20
    is not
    intended to be used from the outside, because it would unintentionally =20=

    publish
    all internal state of a class. This can be easily circumvented in such a
    dynamic language like Ruby, but it has a big, fat warning sign =20
    attached to it.


    But even from the outside, it doesn't break one of the main properties =20=

    of the
    ruby language: the uniform access principle. There is only one way to
    retrieve or change a value from/in an Object: by calling a method.
    C++ and Java have two: directly accessing a member or calling a method.
    In Ruby, this is especially true, because:

    a.foo =3D "bar"

    Is the same as sending the message :foo=3D to a.

    a.send:)foo=3D, "bar")

    where foo=3D is implemented as:

    class A
    def foo=3D(val)
    #internal assignment
    end
    end

    In every language it is easy to publish a value by adding a method. This
    is not "breaking encapsulation", it is intentional publishing. If you =20=

    don't
    know what you are doing when implementing this method, no language can =20=

    help
    you. The way Ruby handles instance variables only makes it harder to =20
    access
    them in ways that the class implementer intended.

    But even with instance_variable_get public, your only way of getting a =20=

    value
    would still be to call that method. Which would give the class =20
    implementer
    the possibility to delete, change or hook that method.

    Regards,
    Florian

    [1]: http://en.wikipedia.org/wiki/Uniform_access_principle
    - --
    Florian Gilcher

    smtp:
    jabber:
    gpg: 533148E2

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG/MacGPG2 v2.0.12 (Darwin)

    iEYEARECAAYFAksR5PMACgkQyLKU2FMxSOLjWACdH+UwQoPd9NvQdXcxygsjDVBI
    PLgAniLm2EMTmTnlZGne9Ep4I02D72Gb
    =3DFlTZ
    -----END PGP SIGNATURE-----
     
    Florian Gilcher, Nov 29, 2009
    #18
  19. Re: Class variables, instance variables, singleton; Ruby v.

    On Saturday 28 November 2009 02:42:08 pm Ralph Shnelvar wrote:
    > DM> It won't tell you how many Foo objects actually exist. It's more a
    > count of DM> how many have ever been created.
    >
    > Cool.
    >
    > Is there a way to tell how many instances actually exist? Is there
    > anything like a destructor for class instances? Just curious.


    These are separate questions.

    In MRI, you can tell how many instances exist by actually counting them. Look
    at the documentation for ObjectSpace.

    And yes, you can register a destructor -- that's also in ObjectSpace, and it's
    called a "finalizer". But remember, Ruby is garbage-collected -- that means
    you have absolutely no guarantee of _when_ that object will be removed. The
    finalizer is guaranteed to be called before the program exits, but that's the
    only guarantee you get.

    Both of these are relatively advanced topics, and something that shouldn't be
    needed in most programs. Keep in mind that in C++, then main purpose of a
    destructor is to free resources used by the object in question -- and most of
    these resources are simply other objects. So, the fact that Ruby is garbage-
    collected removes most of the reason for destructors/finalizers.

    An exception would be a resource that is more than just an object -- for
    example, an open file, or a database handle. But these are generally much
    scarcer resources than memory, so if at all possible, you want to manually
    close these as soon as you can, rather than waiting for something to get
    garbage collected. For example:

    open 'some_file' do |file|
    file.each_line do |line|
    # do some stuff with each line in the file
    end
    end

    What might not be obvious here is that the 'open' call will automatically
    close the file when the block exits.

    > So, basically, the reason that instance_variable_get is private to
    > Module is that one does not wish make breaking encapsulation too easy?


    Others have answered this already...

    In a very basic sense, yes, that seems like a valid answer. There is really no
    good reason why code outside a class should have to call
    instance_variable_get, most of the time. It's private so that when you try,
    you'll rethink your architecture so you don't need it.

    On the other hand, Ruby has open classes. While there are ways to supposedly
    lock it down and run untrusted code in a safe sandbox, in general, any code
    running in the same interpreter can do all sorts of things to existing
    classes. In other words, if you want to access the variable @bar in an object
    of class Foo, you could always do something like this:

    class Foo
    attr_reader :bar
    end

    There are many other ways of getting the same result.

    Now, Florian mentioned another aspect, which is that you still can only know
    anything about an object by calling methods on it. So even if
    instance_variable_get was public, there's nothing from stopping an especially
    paranoid class from redefining it or removing it.

    I think that's more than enough to answer your question, but if you're
    curious, you could always have a sort of "arms race" of trying to enforce
    encapsulation. For example, even if someone redefines instance_variable_get, I
    can always do this:

    Class.instance_method:)instance_method).bind(Foo).call:)instance_variable_get).bind(foo).call:)@bar)

    That means there's nothing the Foo class itself can do to hide the @bar
    variable from you, including redefining instance_method on itself.

    But wait! How do you know Class itself hasn't been modified?

    The lesson to learn here is that while Ruby is very good at encapsulation by
    convention, it's not very good at all at enforced encapsulation, as C++ is. At
    the end of the day, you have to remember that this is a language which lets
    you define null to be not null. Here, try this in irb:

    class NilClass
    def nil?
    false
    end
    end

    Now type any other command, and watch irb crash.

    > I mean, it seems easy enough to break encapsulation by adding an
    > accessor, right?


    Well, yes and no.

    Yes, you can break encapsulation by just adding an accessor to any instance
    variable that anyone was trying to hide from you. You can also break it by
    using one of several tricks to call the private instance_variable_get, and
    probably a few ways I haven't thought of. Ruby doesn't enforce encapsulation.

    On the other hand, accessors are the ultimate in encapsulation -- partly
    because they're the only sane way to get at instance variables, and partly
    because they're so easy to define. I remember wishing for them in Java, where
    good coding style led to lots of these:

    private int foo;
    public int getFoo() {
    return foo;
    }
    public void setFoo(int value) {
    foo = value;
    }

    I can see why Java people use tools like Eclipse -- there's no way you want to
    type all that stuff yourself. But it's still a good idea, because it allows
    you to change your internal structure to no longer require that variable,
    without changing your external interface.

    The point here is, if you actually expose an accessor, no one has to use
    instance_variable_get or anything like it -- they won't be mucking about with
    the internals of your class. (If they do, they're asking for trouble when you
    change something.) That means you can, among other things, override the
    behavior of the accessor on subclasses, replace it entirely with a method,
    etc.

    Just as an example: Suppose you have a class like this:

    class Line
    attr_reader :a, :b, :slope
    def initialize(point_a, point_b)
    @a = point_a
    @b = point_b
    @slope = (a.x - b.x) / (a.y - b.y)
    end
    end

    Now, maybe later on, you notice this isn't working out too well -- maybe not
    everyone cares about the slope, so you're wasting cycles calculating it every
    time. Maybe the points are changing frequently, and you don't want to have to
    re-calculate the slope on every change, only when someone requests it. Since
    you defined slope as a reader method, you can just change your implementation:

    class Line
    attr_reader :a, :b
    def slope
    (a.x - b.x) / (a.y - b.y)
    end
    end

    No one has to know that @slope no longer exists.

    Granted, you might have some coders who deliberately break things by talking
    to @slope directly, but if you've defined an accessor, they have to be a
    masochist to want to do it that way. Similarly, because it's just one command
    for you to define them, you really have no excuse not to.

    I suppose that's the fundamental difference -- in Java and C++, encapsulation
    can be enforced to some extent, while in Ruby, it can be easily circumvented.
    But Ruby makes it easy to write well-encapsulated code, while Java and C++
    make it annoying and tedious.
     
    David Masover, Nov 29, 2009
    #19
  20. Re: Class variables, instance variables, singleton; Ruby v.

    DM> On Saturday 28 November 2009 02:42:08 pm Ralph Shnelvar wrote:
    >> DM> It won't tell you how many Foo objects actually exist. It's more a
    >> count of DM> how many have ever been created.
    >>
    >> Cool.
    >>
    >> Is there a way to tell how many instances actually exist? Is there
    >> anything like a destructor for class instances? Just curious.


    DM> These are separate questions.

    [snip]

    DM> I suppose that's the fundamental difference -- in Java and C++, encapsulation
    DM> can be enforced to some extent, while in Ruby, it can be easily circumvented.
    DM> But Ruby makes it easy to write well-encapsulated code, while Java and C++
    DM> make it annoying and tedious.

    Oh, wow, what a great explanation! Thanks for taking the time. Wow.
     
    Ralph Shnelvar, Nov 29, 2009
    #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,407
    =?iso-8859-1?Q?Fran=E7ois?= Pinard
    Feb 10, 2004
  2. Martin P. Hellwig
    Replies:
    1
    Views:
    377
    Martin P. Hellwig
    Mar 26, 2010
  3. Caleb Tennis
    Replies:
    3
    Views:
    161
  4. Paul McMahon
    Replies:
    3
    Views:
    206
    David A. Black
    Jun 9, 2008
  5. Charles Oliver Nutter

    Singleton methods without the singleton class

    Charles Oliver Nutter, Mar 15, 2010, in forum: Ruby
    Replies:
    4
    Views:
    204
    Charles Oliver Nutter
    Mar 22, 2010
Loading...

Share This Page