I'm having a hard time understanding the underlying technical difference between pass-by-reference and pass-by-value (in Ruby).
I keep hearing that the distinction between pass by value and pass by reference is important.
But I still can't wrap my head around it.
Response from Nested Software:
I think the value/reference stuff in Ruby is similar to Java: Variables are always references to objects (in Ruby everything is an object).
That means when you assign a variable to an object, you can imagine the variable as an arrow that points to the object. If you have
a = b = _some_object_, that’s like having two arrows both pointing to the same object.
Re-assigning a variable, e.g.
a = _some_other_object_, just points the arrow to another object. It doesn’t change the object it was pointing to before. On the other hand, dereferencing the variable, e.g.
a.x = _something_, changes the underlying object. That means the change is visible to any variable pointing to the same object. If you don’t want this behavior, you have to explicitly make a copy of the object before you make a change to it.
Lastly, when you pass a variable to a function, a copy of the reference is made. That means there’s one arrow pointing to the object in the calling function and another arrow pointing to the same object in the called function. Since a copy is made, we say the argument is passed by value. But keep in mind that the argument is a reference (an arrow), so we are passing references by value.
One more note: You can create so-called “immutable” objects. That just means that methods that modify such objects will actually create a copy. The original object remains unchanged and instead a new object is created with the desired modification. As I mentioned earlier, creating copies like this can make it seem you’re dealing with values rather than references. Primitive objects like integers, e.g.
3, are immutable. That’s why doing
3 + 3 doesn’t change what
3 means, which of course would be bad!
Response from Brian Kephart:
This is tricky to think about in Ruby because IMO the pass-by-value/reference distinction comes from languages where these are both possible as different behaviors, and Ruby is not really designed to be thought of in that way. Ruby is technically ALWAYS pass-by-value, but all variables and arguments are references to objects. Confused yet?
Pass by value: You give your friend a toy (pass your method an argument). It's theirs now, and you don't play with it anymore. Maybe you have an identical toy at home, but whatever your friend does to their toy doesn't affect yours.
Pass by reference: You tell your friend where your toy is. Now, whatever they do to the toy (pose it, cut its hair, whatever), you will find the toy as they left it next time you play with it.
How Ruby works: You give your friend a treasure map (a reference to an object). You can pass your friend a treasure map just like another one you have, and changes to their map don't affect yours. If they redraw their map, yours doesn't change.
def change(str) str = 'Nothing here!' end var = 'Treasure' change(var) # => 'Nothing here!' var # => 'Treasure'
But if they follow the map to the treasure and mess with it...
def change(str) str << ' used to be here :(' end var = 'Treasure' change(var) # => "Treasure used to be here :(" var # => "Treasure used to be here :("