Method that mutates object

Discussion in 'Ruby' started by jason solomon, May 25, 2011.

  1. Say we want to write a String method called clear that takes a given
    string and modifies that string to be equal to "".

    Ex.

    str = "string"

    we call str.clear and we get back "", not just "" printed to the screen,
    but the value of str is now "" (mutate the original string).


    I understand that the following code would just print "" to the screen
    but not modify the actual str object.

    class String
    def clear
    ""
    end
    end


    How would you write a method that actually modifies the str object?

    --
    Posted via http://www.ruby-forum.com/.
    jason solomon, May 25, 2011
    #1
    1. Advertising

  2. On Thursday 26 May 2011 04:22:46 jason solomon wrote:
    > Say we want to write a String method called clear that takes a given
    > string and modifies that string to be equal to "".
    >
    > Ex.
    >
    > str = "string"
    >
    > we call str.clear and we get back "", not just "" printed to the screen,
    > but the value of str is now "" (mutate the original string).
    >
    >
    > I understand that the following code would just print "" to the screen
    > but not modify the actual str object.
    >
    > class String
    > def clear
    > ""
    > end
    > end
    >
    >
    > How would you write a method that actually modifies the str object?


    This should do what you want

    class String

    def clear
    replace ''
    end

    end

    Stefano
    Stefano Crocco, May 25, 2011
    #2
    1. Advertising

  3. [Note: parts of this message were removed to make it a legal post.]

    On Wed, May 25, 2011 at 8:22 PM, jason solomon <>wrote:

    > I understand that the following code would just print "" to the screen
    > but not modify the actual str object.
    >
    > class String
    > def clear
    > ""
    > end
    > end
    >
    > How would you write a method that actually modifies the str object?
    >


    String#replace

    s1 = s2 = ""
    s2.replace("foo")
    s2 #=> "foo"
    s1.object_id == s2.object_id

    def String
    def fooify
    replace("foo")
    end
    end

    s = "bar"
    s.fooify
    s == "foo"
    Adam Prescott, May 25, 2011
    #3
  4. jason solomon

    Quintus Guest

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

    Am 25.05.2011 21:22, schrieb jason solomon:
    > Say we want to write a String method called clear that takes a given
    > string and modifies that string to be equal to "".
    >
    > Ex.
    >
    > str = "string"
    >
    > we call str.clear and we get back "", not just "" printed to the screen,
    > but the value of str is now "" (mutate the original string).
    >
    >
    > I understand that the following code would just print "" to the screen
    > but not modify the actual str object.
    >
    > class String
    > def clear
    > ""
    > end
    > end
    >
    >
    > How would you write a method that actually modifies the str object?
    >


    Just in addition to what the others said, the method String#clear
    already exists.

    =================================================
    $ ri String#clear
    = String#clear

    (from ruby core)
    -
    ------------------------------------------------------------------------------
    string.clear -> string

    -
    ------------------------------------------------------------------------------

    Makes string empty.

    a = "abcde"
    a.clear #=> ""
    =================================================

    And does exactly what you want it to.

    Vale,
    Marvin
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.11 (GNU/Linux)
    Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

    iQEcBAEBAgAGBQJN3WptAAoJELh1XLHFkqhaG5AH/1mAcLBo9eKzpJg3XHjIXXAr
    vFOUV9+Ow3hSBZ8Q1KDQrKOVd2QBRkkA2vk7wF7H9KrJCar7wElf0OgJHYmjlEhR
    HRnnxtoRgdkRo1GoFyvGr7tRzoKlAgPNC93AQFDm7mZFfO6QMtF5aR4xLgWMIZhM
    vRNMkjs71XE1lmxASvFDVgW4SS1wxJnzDe0LQZncjOOPaZHQQM2P3aR9mHL8Or8O
    FBvuzqgCptKq5Y69xv/AysLZlRu1ja37J6ggK7LIuLsmT2UaydOc9pVgDaunazrI
    ym9IASTm/7vmYRKr3FuA98JifEGAEWC6jkuP0MYcLNkGLdhEzkce04FxHdkfodk=
    =5xGw
    -----END PGP SIGNATURE-----
    Quintus, May 25, 2011
    #4
  5. Stefano Crocco wrote in post #1001011:
    > On Thursday 26 May 2011 04:22:46 jason solomon wrote:
    >>
    >> How would you write a method that actually modifies the str object?

    > This should do what you want
    >
    > class String
    >
    > def clear
    > replace ''
    > end
    >
    > end
    >
    > Stefano




    Thanks for the reply. Say we wanted to write our own replace method and
    not use the replace method provided by the String class?

    --
    Posted via http://www.ruby-forum.com/.
    jason solomon, May 25, 2011
    #5
  6. I know this is changing gears a little here, but the previous post
    reminded me of this.

    Say I want to extend the built in Array class with some useless function
    called crazy()

    class Array
    def crazy
    ...do something...
    end
    end


    Correct me if I'm wrong, but I now have a class method for Array. I
    call Array.methods just to make sure that it is there, yet it doesn't
    show up, however if I do this:

    a = []

    and then call a.methods, I can see the crazy() method that we wrote
    available. It looks to me as if I am creating an instance method, but I
    would think I would do that like this:

    def a.crazy
    ...do something...
    end


    Does this issue have anything to do with the face that the Array class
    is immutable?

    I'm a bit confused, any help. Thanks.

    --
    Posted via http://www.ruby-forum.com/.
    jason solomon, May 25, 2011
    #6
  7. Marvin G=C3=BClker wrote in post #1001033:
    > -----BEGIN PGP SIGNED MESSAGE-----
    > Hash: SHA1
    >
    > Am 25.05.2011 21:22, schrieb jason solomon:
    >>
    >> How would you write a method that actually modifies the str object?
    >>

    >
    > Just in addition to what the others said, the method String#clear
    > already exists.
    >
    > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

    > $ ri String#clear
    > =3D String#clear
    >
    > (from ruby core)
    > -
    > -----------------------------------------------------------------------=

    -------
    > string.clear -> string
    >
    > -
    >

    -------------------------------------------------------------------------=
    -----
    >
    > Makes string empty.
    >
    > a =3D "abcde"
    > a.clear #=3D> ""
    > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

    >
    > And does exactly what you want it to.
    >
    > Vale,
    > Marvin
    > -----BEGIN PGP SIGNATURE-----
    > Version: GnuPG v1.4.11 (GNU/Linux)
    > Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
    >
    > iQEcBAEBAgAGBQJN3WptAAoJELh1XLHFkqhaG5AH/1mAcLBo9eKzpJg3XHjIXXAr
    > vFOUV9+Ow3hSBZ8Q1KDQrKOVd2QBRkkA2vk7wF7H9KrJCar7wElf0OgJHYmjlEhR
    > HRnnxtoRgdkRo1GoFyvGr7tRzoKlAgPNC93AQFDm7mZFfO6QMtF5aR4xLgWMIZhM
    > vRNMkjs71XE1lmxASvFDVgW4SS1wxJnzDe0LQZncjOOPaZHQQM2P3aR9mHL8Or8O
    > FBvuzqgCptKq5Y69xv/AysLZlRu1ja37J6ggK7LIuLsmT2UaydOc9pVgDaunazrI
    > ym9IASTm/7vmYRKr3FuA98JifEGAEWC6jkuP0MYcLNkGLdhEzkce04FxHdkfodk=3D
    > =3D5xGw
    > -----END PGP SIGNATURE-----






    Correct me if I am wrong, String#clear does not exist in Ruby 1.8 and =

    earlier.

    -- =

    Posted via http://www.ruby-forum.com/.=
    jason solomon, May 25, 2011
    #7
  8. jay s. wrote in post #1001040:
    > Say I want to extend the built in Array class with some useless function
    > called crazy()
    >
    > class Array
    > def crazy
    > ...do something...
    > end
    > end
    >
    >
    > Correct me if I'm wrong, but I now have a class method for Array.


    You're wrong, so I'll correct you :) "def" creates instance methods.
    You now have a new instance method on class Array; that is, a method
    which is available to all objects which are instances of Array.

    > I
    > call Array.methods just to make sure that it is there, yet it doesn't
    > show up, however if I do this:
    >
    > a = []
    >
    > and then call a.methods, I can see the crazy() method that we wrote
    > available.


    Yes. To call that method, you'd do "a.crazy"

    > It looks to me as if I am creating an instance method, but I
    > would think I would do that like this:
    >
    > def a.crazy
    > ...do something...
    > end


    That would create a singleton method: a method which belongs only to
    that object.

    a = []
    def a.crazy
    puts "hello"
    end
    a.crazy # works

    b = []
    b.crazy # NoMethodError

    What you did before was this:

    class Array
    def crazy
    ...
    end
    end

    That defines an instance method on class Array - that is, a method which
    is available to all array objects, even arrays which existed before you
    defined the method. This is the "normal" sort of method you define when
    programming.

    Just to close the loop, here's how you do class methods:

    def Array.crazy
    puts "wibble"
    end

    Array.crazy

    Now, that syntax may look familiar. In Ruby, classes are objects. You
    are defining a singleton method on the object "Array" (which also
    happens to be an object of class "Class")

    So, "class methods" are nothing more than singleton methods, on an
    object of class Class.

    > Does this issue have anything to do with the face that the Array class
    > is immutable?


    No, and in any case the class Array is definitely *not* immutable.

    $ irb --simple-prompt
    >> a = [1,2]

    => [1, 2]
    >> a << 3

    => [1, 2, 3]
    >> a

    => [1, 2, 3]

    > I'm a bit confused


    That does appear to be the case :) You might want to work through some
    documentation. This one is good:
    http://www.ruby-doc.org/docs/ProgrammingRuby/

    And continue experimenting within irb of course.

    Regards,

    Brian.

    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, May 25, 2011
    #8
  9. jason solomon

    jay s. Guest

    jay s., May 25, 2011
    #9
  10. jason solomon

    7stud -- Guest

    jay s. wrote in post #1001051:
    > Thank you for the help, that actually cleared up quite a bit for me.
    >


    Here's some more. This line:

    > Array.methods


    asks the question, "What methods does Array respond to?" It does not
    ask, "What methods do the instances of the Array class respond to?"
    Array is a class, and in ruby a class is an object/instance of a class
    called Class. In ruby, every class is an instance of the Class class,
    and as such, a class object responds to instance methods defined in
    Class(and its superclasses: Module and Object). The most common
    instance method that class objects call is new().

    Now here is the confusing part, Class is a class, and because all
    classes in ruby are objects/instances of the Class class, the Class
    object is an instance of itself. Presto. lol. Don't even try to
    understand that--but the logic is consistent.

    --
    Posted via http://www.ruby-forum.com/.
    7stud --, May 25, 2011
    #10
  11. jason solomon

    jay s. Guest

    Thanks again for all replies as it has helped me to wrap my head around
    some of the problems that I've experienced.

    Say we wanted to write our own replace method and not use the replace
    method provided by the String class? So we want to write a method that
    takes a string object and modifies/mutates that same object and then
    returns it, without creating a copy of that object.

    --
    Posted via http://www.ruby-forum.com/.
    jay s., May 26, 2011
    #11
  12. jason solomon

    Jeremy Bopp Guest

    On 5/26/2011 08:56, jay s. wrote:
    > Say we wanted to write our own replace method and not use the replace
    > method provided by the String class? So we want to write a method that
    > takes a string object and modifies/mutates that same object and then
    > returns it, without creating a copy of that object.


    What exactly are you trying to accomplish? The String class provides
    multiple methods to mutate the String instance in various ways, and many
    of those methods could be specified in terms of the others, including
    replace. Rather than ask someone to figure out another solution to
    which you may respond, "and how do we write our own method_x and not use
    the method_x provided by the String class," could you provide some
    details about your goals? What kind of modifications on the String
    instance do you want your method to perform? What methods provided by
    the String class are out of bounds (as replace apparently is)?

    To me this is sounding a bit like a homework assignment, but maybe it's
    not. In any case, the documentation for the String class is actually
    pretty good, so you can probably answer your own question with a little
    easy reading:

    http://rdoc.info/stdlib/core/1.9.2/String

    If I understand what you're really trying to accomplish, the method you
    want is definitely listed there.

    -Jeremy
    Jeremy Bopp, May 26, 2011
    #12
  13. jason solomon

    jay s. Guest

    Jeremy Bopp wrote in post #1001249:
    > On 5/26/2011 08:56, jay s. wrote:
    >> Say we wanted to write our own replace method and not use the replace
    >> method provided by the String class? So we want to write a method that
    >> takes a string object and modifies/mutates that same object and then
    >> returns it, without creating a copy of that object.

    >
    > What exactly are you trying to accomplish? The String class provides
    > multiple methods to mutate the String instance in various ways, and many
    > of those methods could be specified in terms of the others, including
    > replace. Rather than ask someone to figure out another solution to
    > which you may respond, "and how do we write our own method_x and not use
    > the method_x provided by the String class," could you provide some
    > details about your goals? What kind of modifications on the String
    > instance do you want your method to perform? What methods provided by
    > the String class are out of bounds (as replace apparently is)?
    >
    > To me this is sounding a bit like a homework assignment, but maybe it's
    > not. In any case, the documentation for the String class is actually
    > pretty good, so you can probably answer your own question with a little
    > easy reading:
    >
    > http://rdoc.info/stdlib/core/1.9.2/String
    >
    > If I understand what you're really trying to accomplish, the method you
    > want is definitely listed there.
    >
    > -Jeremy



    Just for clarification, this is by no means a homework assignment. I am
    new to Ruby and I'm trying to get a better grasp on how Ruby handles
    mutation. I actually think at this point I'll try looking at Ruby's
    source code and see how String#replace is implemented. Maybe I'm just
    over complicating my question.

    --
    Posted via http://www.ruby-forum.com/.
    jay s., May 26, 2011
    #13
  14. jason solomon

    jay s. Guest

    /*
    * call-seq:
    * str.replace(other_str) -> str
    *
    * Replaces the contents and taintedness of <i>str</i> with the
    corresponding
    * values in <i>other_str</i>.
    *
    * s = "hello" #=> "hello"
    * s.replace "world" #=> "world"
    */

    VALUE
    rb_str_replace(VALUE str, VALUE str2)
    {
    str_modifiable(str);
    if (str == str2) return str;

    StringValue(str2);
    str_discard(str);
    return str_replace(str, str2);
    }



    So from the looks of it the String#replace method is implemented in C,
    and I'm assuming the return value of rb_str_replace is VALUE?

    --
    Posted via http://www.ruby-forum.com/.
    jay s., May 26, 2011
    #14
  15. jason solomon

    jay s. Guest

    I understand that using String#replace works for the String class, but
    what if you were writing a random method for Integer that takes a number
    and sets it equal to some other number.

    Ex.

    x = 7

    class Integer
    def crazy
    ...set x to 5...
    end
    end


    now when you call x the value is 5

    --
    Posted via http://www.ruby-forum.com/.
    jay s., May 26, 2011
    #15
  16. jason solomon

    Jeremy Bopp Guest

    On 5/26/2011 11:07, jay s. wrote:
    > I understand that using String#replace works for the String class, but
    > what if you were writing a random method for Integer that takes a number
    > and sets it equal to some other number.
    >
    > Ex.
    >
    > x = 7
    >
    > class Integer
    > def crazy
    > ...set x to 5...
    > end
    > end
    >
    >
    > now when you call x the value is 5


    Instances of Integer are immutable, so you can't do that. The
    documentation for Fixnum (a descendant of Integer) mentions this in the
    Overview section:

    http://rdoc.info/stdlib/core/1.9.2/Fixnum

    -Jeremy
    Jeremy Bopp, May 26, 2011
    #16
  17. jason solomon

    jay s. Guest

    Jeremy Bopp wrote in post #1001275:
    > On 5/26/2011 11:07, jay s. wrote:
    >> ...set x to 5...
    >> end
    >> end
    >>
    >>
    >> now when you call x the value is 5

    >
    > Instances of Integer are immutable, so you can't do that. The
    > documentation for Fixnum (a descendant of Integer) mentions this in the
    > Overview section:
    >
    > http://rdoc.info/stdlib/core/1.9.2/Fixnum
    >
    > -Jeremy





    Thanks.

    --
    Posted via http://www.ruby-forum.com/.
    jay s., May 26, 2011
    #17
  18. jason solomon

    Josh Cheek Guest

    [Note: parts of this message were removed to make it a legal post.]

    On Thu, May 26, 2011 at 12:41 PM, Chad Perrin <> wrote:
    > On Fri, May 27, 2011 at 12:00:43AM +0900, jay s. wrote:
    >>
    >> Just for clarification, this is by no means a homework assignment. I am
    >> new to Ruby and I'm trying to get a better grasp on how Ruby handles
    >> mutation. I actually think at this point I'll try looking at Ruby's
    >> source code and see how String#replace is implemented. Maybe I'm just
    >> over complicating my question.

    >
    > For that, you might want to look at the source for String#replace in the
    > Rubinius implementation of Ruby.
    >
    > https://github.com/evanphx/rubinius
    >
    > --
    > Chad Perrin [ original content licensed OWL: http://owl.apotheon.org ]
    >


    Since it took me about 10 minutes to look up, here is the actual link:

    https://github.com/evanphx/rubinius...cb610a4b41/kernel/common/string.rb#L1301-1325
    Josh Cheek, May 26, 2011
    #18
  19. jason solomon

    Gary Wright Guest

    On May 26, 2011, at 12:07 PM, jay s. wrote:

    > I understand that using String#replace works for the String class, but=20=


    > what if you were writing a random method for Integer that takes a =

    number=20
    > and sets it equal to some other number.
    >=20
    > Ex.
    >=20
    > x =3D 7
    >=20
    > class Integer
    > def crazy
    > ...set x to 5...
    > end
    > end
    >=20
    >=20
    > now when you call x the value is 5



    This seems like a simple question but it touches on some very deep =
    issues of Ruby's object model. Understanding the object model is the =
    key to understanding why your question doesn't make sense in Ruby.

    Ruby's fixnum objects are not containers for an integer value. This =
    means that for any particular fixnum object there is no way to alter it =
    so that it no longer behaves like a 7 and instead behaves like a 5, for =
    example. The integer semantics of a fixnum object are defined by the =
    object's *identity*, not by any state it carries around (i.e. instance =
    variables or state that is hidden from the programmer but maintained by =
    the runtime).

    >> x =3D 5 #=3D> 5
    >> x.object_id #=3D> 11
    >> y =3D 7 #=3D> 7
    >> y.object_id #=3D> 15
    >> z =3D 3 + 4 #=3D> 7
    >> z.object_id #=3D> 15
    >> z.eql?(y) #=3D> true


    In that example you can see that y and z reference the *same* object, =
    which happens to be object 15 in my version of Ruby and which happens to =
    behave like the integer 7. The Ruby runtime ensures that object 15 =
    always behaves like the integer 7 and that it is the *only* object that =
    behaves like the integer 7.

    And yes, you can attach instance variables to fixnum objects:

    >> a =3D 2 #=3D> 2
    >> b =3D 1 + 1 #=3D> 2
    >> a.instance_variable_set('@english', 'two') #=3D> "two"
    >> b.instance_variable_get('@english') #=3D> "two"
    >> a.object_id #=3D> 5
    >> b.object_id #=3D> 5


    So you can see that within Ruby's object model there is one and only one =
    fixnum object that behaves like the integer 2. That particular object =
    in MRI Ruby 1.9.2 happens to have an object_id of 5, but that is really =
    just an implementation detail.=20

    Lots and lots of Rubyists describe fixnum objects as 'immutable', but as =
    shown above with instance variables, that is simply not an accurate =
    description of Ruby's fixnum objects. The characteristic that =
    erroneously gets labeled as 'immutability' is that the semantics of a =
    fixnum object are defined by its *identity* and not by its state. A =
    consequence of this property is that having a *reference* to a fixnum is =
    all you need to interact with the object. The underlying object doesn't =
    even have to 'exist' within the runtime (i.e. there is no memory =
    allocated for every fixnum object). The runtime can emulate the =
    behavior of fixnum objects simply by manipulating the *references* =
    without ever instantiating the objects. See =
    <http://en.wikipedia.org/wiki/Tagged_pointer> for more about how this =
    sort of thing is implemented. There are several other Ruby classes that =
    have this behavior and tend to be implemented in this way: nil, true, =
    false from NilClass, TrueClass, and FalseClass respectively and symbols.

    Going back to your original question about setting x to a new value. =
    Another way of interpreting that request is not that you are mutating =
    the object that x references but instead you are rebinding the variable =
    x to a different object. Ruby variables are simply named containers for =
    object references so if you can replace the reference to the fixnum 7 =
    associated with variable x with a reference to the fixnum 5, you will =
    have 'set x to 5', which is exactly what Ruby's assignment operation =
    does.

    There are a variety of ways for a Ruby method to gain access to variable =
    bindings that are out of the direct scope of the method but it is =
    generally considered bad form for a method to alter variable bindings =
    outside its scope. Nevertheless, here is one way to do it:

    class Integer
    def assign(name, value, binding_object)
    eval "#{name} =3D #{value}", binding_object
    end
    end

    >> x =3D 5 #=3D> 5
    >> x.assign('x', 7, binding) #=3D> 7
    >> x #=3D> 7


    This sort of use of eval and binding is *not* at all common and probably =
    only comes into play with various debugging or programming tools rather =
    than in the normal course of writing Ruby programs.


    Gary Wright
    Gary Wright, May 26, 2011
    #19
  20. [Note: parts of this message were removed to make it a legal post.]

    On 26 May 2011 22:40, "Gary Wright" <> wrote:
    >
    > There are a variety of ways for a Ruby method to gain access to variable

    bindings that are out of the direct scope of the method but it is generally
    considered bad form for a method to alter variable bindings outside its
    scope. Nevertheless, here is one way to do it:
    >
    > class Integer
    > def assign(name, value, binding_object)
    > eval "#{name} = #{value}", binding_object
    > end
    > end
    >
    > >> x = 5 #=> 5
    > >> x.assign('x', 7, binding) #=> 7
    > >> x #=> 7

    >
    > This sort of use of eval and binding is *not* at all common and probably

    only comes into play with various debugging or programming tools rather than
    in the normal course of writing Ruby programs.

    Not to needlessly self-promote or anything, but I recently wrote about
    variables and bindings, so perhaps this is informative:

    http://aprescott.com/posts/variables-closures-and-scope
    Adam Prescott, May 27, 2011
    #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. Vivek Sawant
    Replies:
    3
    Views:
    244
    Peter Hansen
    Feb 18, 2004
  2. mike
    Replies:
    5
    Views:
    326
    Ben Pope
    Feb 22, 2006
  3. Replies:
    0
    Views:
    358
  4. Elf M. Sternberg
    Replies:
    15
    Views:
    256
    Matthias Reitinger
    Jul 29, 2009
  5. Kyung won Cheon
    Replies:
    0
    Views:
    185
    Kyung won Cheon
    Nov 21, 2008
Loading...

Share This Page