In case, you're not so familiar with programming, here's what this referencing is about. I simplify the explanation, so that it is understandable. It might not be an 100% accurate image of the technical ongoings.
Generally, and in OOP especially, values can be passed in two ways: By reference ("byRef") or by value ("byVal"). The difference is significant.
byRef means that only an address to a spot in memory is passed, and the method then looks at this spot to use the data that's stored there.
byVal means that still an address to a spot in memory is passed, but the method doesn't use the data directly, but first copies it to another spot in memory and works with this copy.
In Ruby everything is passed byRef, until you explicitly tell it to not do so. The advantage is clear. There's no copying going on, so it is faster. The disadvantage is also clear. Every method that's supposed to work with the data will have the same access. If method A changes the content, method B will see the changed content and not the original data. Often times this is wanted, so you don't stumble upon it. For arrays however, this can produce unwanted results.
arr = [1, 2, 3]
arr address will point to this object. The data stored there are the addresses to the number objects 1, 2 and 3
my_2d_arr = [arr, arr]
my_2d_arr address will point to this object. The data stored there is two times the address to arr.
arr[1] = 4
we changed the data stored at arr address. The data stored there are now the addresses to the number objects 1, 4 and 3
my_2d_arr
this call will show the stored data. Since it points two times to arr, we will see
[[1, 4, 3],[1, 4, 3]]
Simplified one could get the impression that we changed the content of my_2d_arr without ever touching it. But that's not true. It still has the same content, which is two times arr. But we changed arr, and so we see the changes in my_2d_arr as well.
A byVal passing of data is possible, but complex.
arr2 = arr.clone
This method creates a shallow copy of arr. What does that mean? It means that arr2 is now an array of its own. arr and arr2 point to different spots in memory. BUT, the contents of those two arrays still point to the same addresses to the number objects.
A true copy, where every element is in its own spot in memory, can be achieved in various ways, for example via marshalling or by using blocks. Those are the {} elements you often see in Ruby code. A block basically is a short method attached to a loop. It will runs the code inside {} for each element of the loop.
Code: Select all
a = ["a", "b", "c"]
b = a.map { |e| e.dup}
a[1] = "d"
Now you have a deep copy, where every element is in its own spot in memory. That means, after the last line of above code, the contents of the arrays will be
a = ["a", "d", "c"]
b = ["a", "b", "c"]