1

Okay, I got confused by how ruby passes it's arguments to a function. I've read in the documentation that ruby passes by value, but in my case it looks like it's passing by referance Here's the problem:

def buble_sort(arr) 
unordered = true
while unordered
    unordered = false
    for i in (1..arr.size-1)
        if(arr[i-1] > arr[i])
            arr[i-1], arr[i] = arr[i], arr[i-1] 
            unordered = true;
        end
    end
end
arr
end

Calling this method shouldn't modify the arr value, since ruby passes it by value. But in my case, it does modify the original array. Why? Code:

p "#{arr} before sort" # => "[85, -4, 1, 2, 55, 23, 0] before sort"
p buble_sort(arr) # => [-4, 0, 1, 2, 23, 55, 85]
p "#{arr} after sort" # => "[-4, 0, 1, 2, 23, 55, 85] after sort"
dev-cyprium
  • 758
  • 2
  • 8
  • 25
  • 6
    A reference is a value. Unless you copy the array you're operating on the same array. – Dave Newton Apr 11 '16 at 13:27
  • 2
    Possible duplicate of [Is Ruby pass by reference or by value?](http://stackoverflow.com/questions/1872110/is-ruby-pass-by-reference-or-by-value) – anquegi Apr 11 '16 at 13:38
  • You need to dup an object or to construct a new one, e. g. `def buble_sort(*arr)` – Nick Roz Apr 11 '16 at 13:46
  • This doesn't have anything to do with pass-by-reference or pass-by-value. The difference between the two can only be observed when you re-bind the reference, but you never do that, so the results are actually the same regardless of whether Ruby is pass-by-reference or pass-by-value. What you are seeing is simply mutable state. Ruby is not a purely functional language, it has mutable state and side-effects. This is an example of mutable state, and this is an example of why it should be avoided. – Jörg W Mittag Apr 12 '16 at 00:46

1 Answers1

2

To understand that, you have to make a distinction between a variable and what this variable stands for. Consider the following example :

items = [1, 2, 3]
# the variable items points to an array we just instantiated
items = [4, 5, 6]
# items now points to a new array

If ruby passed arguments by reference, doing so within a method with an argument it received would also make the variable exposed to the method by the caller point to a new location

items = [1, 2, 3]
def my_method array
    array = [4, 5, 6]
    return array
end
my_method(items) # --> [4, 5, 6]
items # --> [1, 2, 3]
# if ruby passed arguments by reference, items would now be [4, 5, 6]

Now ruby passes arguments by value, but the value you received is a reference to the same location in memory as the one the called passed you. In other words, you don't get a clone, a dup, but the same object.

items = [1, 2, 3]
def my_method array
    array << 4
    return array
end
my_method(items) # --> [1, 2, 3, 4]
items # --> [1, 2, 3, 4]

If you want your method to have no side-effect on its arguments you can clone them.

VonD
  • 5,075
  • 2
  • 20
  • 30