Ruby - Modifying Receivers and Yielding New Objects

Introduction

In most cases, Ruby methods do not modify the receiver object.

However, some methods, such as those ending with !, do modify their receiver.

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:

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

String concatenation method, <<, just like those methods that end with !, modifies the receiver object without creating a new object.

Demo

str1 = "hello"          
str2 = "world"          
str3 = "goodbye"        

str3 = str2 << str1#  w  w w  .  j  av  a 2  s  .c  o m
puts( str1.object_id )  #=> unchanged
puts( str2.object_id )  #=> unchanged
puts( str3.object_id )  #=> now the same as str2!

Result

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

str2 and str3 now reference the same object.

Note

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.

Related Topic