Modifying Receivers and Yielding New Objects

You may recall from Chapter 4 that I made the distinction between methods that modify their receiver and those that do not. (Remember that a receiver is the object that “owns” the method.) In most cases, Ruby methods do not modify the receiver object. However, some methods, such as those ending with !, do modify their receiver.

The str_reverse.rb sample program should help clarify this. This shows that when you use the reverse method, for example, no change is made to the receiver object (that is, an object such as str1). But when you use the reverse! method, a change is made to the object (its letters are reversed). Even so, no new object is created: str1 is the same object before and after the reverse! method is called.

Here reverse operates like most Ruby methods: It yields a value, and in order to use that value, you must assign it to a new object. Consider the following:

str_reverse.rb

str1 = "hello"
str1.reverse

Here, str1 is unaffected by calling reverse. It still has the value “hello” and still has its original object_id. Now look at this:

str1 = "hello"
str1.reverse!

This time, str1 is changed (it becomes “olleh”). Even so, no new object is created: str1 has the same object_id with which it started. So, how about this:

str1 = "hello"
str1 = str1.reverse

This time, the value yielded by str1.reverse is assigned to str1. The yielded value is a new object, so str1 is now assigned the reversed string (“olleh”), and it now has a new object_id.

Refer to the sample program concat.rb for an example of the string concatenation method, <<, which, just like those methods that end with !, modifies the receiver object without creating a new object (once again, the actual object_id numbers may be different when you run the code):

concat.rb

str1 = "hello"          #object_id = 23033940
str2 = "world"          #object_id = 23033928
str3 = "goodbye"        #object_id = 23033916
str3 = str2 << str1
puts( str1.object_id )  #=> 23033940 # unchanged
puts( str2.object_id )  #=> 23033928 # unchanged
puts( str3.object_id )  #=> 23033928 # now the same as str2!

In this example, str1 is never modified, so it has the same object_id throughout; str2 is modified through concatenation. However, the << operator does not create a new object, so str2 also retains its original object_id.

But str3 is a different object at the end than at the beginning, because it is assigned the value yielded by this expression: str2 << str1. This value happens to be the str2 object itself, so the object_id of str3 is now identical to that of str2 (that is, str2 and str3 now reference the same object).

In summary, then, methods ending with a ! such as reverse!, plus some other methods such as the << concatenation method, change the value of the receiver object. Most other methods do not change the value of the receiver object. To use any new value yielded as a result of calling one of these methods, you have to assign that value to a variable (or pass the yielded value as an argument to a method).

Note

The fact that a few methods modify the receiver object whereas most do not may seem harmless enough, but beware: This behavior provides you with the ability to retrieve the values of arguments “by reference” rather than retrieving values that are explicitly returned. Doing so breaks encapsulation by allowing your code to rely upon the internal implementation details of a method. This can potentially lead to unpredictable side effects and, in my view, should be avoided.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.78.136