Friday, March 8, 2013

Ruby Pass By Value? Pass By Reference? Pass By Sharing!!

Updated at Dec 27, 2013

There has been a debate over the Internet about whether Ruby's method parameters are passed by value or by reference. Some people claim that it's passed by value by providing the following code.

str_1 = "pass_by_value"

def pass_by_value(str)
  str = "pass_by_reference"
end

pass_by_value(str_1)
str_1
=> "pass_by_value"

It looks convincing at the first glance, as the function pass_by_value didn't change the value of the str_1. But if you change the code a little bit, you will find this assertion is erroneous.

str_1 = "pass_by_value"
str_1.object_id
=> 70332873209820

def pass_by_value(str)
  puts str.object_id
end

pass_by_value(str_1)
70332873209820
 => nil
In the method pass_by_value, when we call method object_id of the object referenced by the variable str, it returns the same id as the object referenced by "str_1". If Ruby pass argument by value, the object_id should NOT be the same. As the value is copied to a new memory location and the local variable str will point to the new object.

Now we can come to the conclusion that Ruby does not pass argument by value, but neither does it pass argument by reference. Because if it does, str_1 should've been changed in our first code snippet. So there must be another evaluation strategy that Ruby uses. This third evaluation strategy is called pass by sharing. Here is a citation from wikipedia that states how pass by sharing works. The semantics of call by sharing differ from call by reference in that assignments to function arguments within the function aren't visible to the caller (unlike by reference semantics)[citation needed], so e.g. if a variable was passed, it is not possible to simulate an assignment on that variable in the caller's scope. However since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call by value semantics. Let's take a look at the following code snippet.

str_1 = 'abc'
str_2 = 'abc'

def mutate_str(str)
str << 'efg'
end

def assign_str(str)
str = 'abcefg'
end

And if we call mutate_str on str_1 and assign_str on str_2. We can find that str_1 is changed to 'abcefg', while str_2 remains 'abc'.
> mutate_str(str_1)
=> "abcefg" 
> str_1
=> "abcefg" 
> assign_str(str_2)
=> "abcefg" 
> str_2
=> "abc" 

4 comments:

  1. Hello!!
    This works only for a String class. What about with numbers or hashes?? It is possible?

    ReplyDelete
    Replies
    1. Hi, Alfredo. String and hash works the same way because they are mutable in Ruby, while numbers are different, as they are immutable in Ruby.

      Delete