Call-by-Sharing
It's becoming increasingly popular to say that languages such as JavaScript, Python, and of course Ruby use an argument-passing style known as call-by-sharing. As you can probably guess, call-by-sharing is basically call-by-reference without the reassignment requirement. The Ruby language specification uses some interesting terms that will help us identify Ruby as using call-by-sharing.
The specification says that variables are names that are bound to objects. When a method is called, an array is allocated to hold what will become its formal arguments. For each actual argument, the object to which it is bound is placed into the array. The objects in the array are then bound to the formal arguments. (This extra step involving an array allows Ruby to handle optional arguments and splatting arguments correctly.)
So the actual arguments and the formal arguments are different variables, but they're bound to the same object. Assigning a new object to a formal argument won't affect the actual argument, but mutating the shared object would. Does this description sound familiar? The process of binding an object to a variable while mapping the actual arguments to the formal arguments sounds very similar to the previous description of call-by-value using indirect references—with two exceptions:
- We don't need any appeal to an additional abstraction to understand call-by-sharing.
- The language specification clearly states that the value of a variable is an object, not a reference to an object.
Therefore, if you want to understand how the C implementation of the Ruby interpreter works internally, it might be helpful to further explore this idea of call-by-value and reference types. But if you want to write Ruby code and understand its behavior, you'll need to dig into call-by-sharing and the concept of variable binding.