Method that mutates object


#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?


#2

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


#3

On Wed, May 25, 2011 at 8:22 PM, jason solomon
removed_email_address@domain.invalidwrote:

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”


#4

-----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.

=================================================
$ 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-----


#5

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.


#6

Marvin Gülker 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.

=================================================
$ 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-----

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


#7

Stefano C. 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?


#8

Thank you for the help, that actually cleared up quite a bit for me.


#9

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 :slight_smile: “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 :slight_smile: 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.


#10

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 fact, every class in ruby is an instance of Class, and
as such, a class object responds to instance methods defined
in Class(and its superclasses: Module and Object, and Kernel which
Object includes. The methods() method is defined in Kernel). The most
common instance method that a class object calls 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 itself is an instance of Class–in other words, the Class object
is an instance of itself. Presto. lol. Don’t even try to understand
that–but the logic is consistent.


#11

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


#12

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.


#13

Jeremy B. 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.


#14

/*

  • call-seq:
  • str.replace(other_str)   -> str
    
  • Replaces the contents and taintedness of str with the
    corresponding
  • values in other_str.
  • 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?


#15

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


#16

Jeremy B. 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.


#17

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

#18

On Thu, May 26, 2011 at 12:41 PM, Chad P. removed_email_address@domain.invalid wrote:

https://github.com/evanphx/rubinius


Chad P. [ 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/blob/84264ce515d64d2d1c7faf4c8cefa1cb610a4b41/kernel/common/string.rb#L1301-1325


#19

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


#20

On 26 May 2011 22:40, “Gary W.” removed_email_address@domain.invalid 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:

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