All variables in Ruby are references to objects. You cannot "pass by value" versus "pass by reference" in the same way as you have that choice in C, C++ or Perl. Ruby in fact forces pass by value, there are no options to do otherwise. However, the values that are sent are always references to objects. It's a bit like using C or C++ where all member variables are pointers, or using Perl where you must work with references at all times, even when working with simple scalars.
I think that it is this separation of variable from object data that is confusing you.
A few points:
Variable allocation never over-writes other variables that may point to the same object. This is pretty much the definition of pass-by-value. However this isn't meeting your expectations that object contents are also protected.
Instance variables, and items in containers (e.g. in Array
s and String
s) are separate variables, and if you send a container you can alter its content directly, because you sent the reference to the container, and that includes the same variables for its contents. I think this is what you mean by "seems to be pass-by reference"
Some classes - including those representing numbers, and Symbol
- are immutable i.e. there are no change-in-place methods for the number 4
. But conceptually you are still passing a reference to the singular object 4
into a routine (under the hood, for efficiency Ruby will have the value 4
encoded simply in the variable's memory allocation, but that is an implementation detail - the value is also the "pointer" in this case).
The simplest way to get close to the "pass by value" semantics you seem to be looking for with SampleModule
is to clone
the parameters at the start of the routine. Note this does not actually cause Ruby to change calling semantics, just that in this case from the outside of the method you get the safe assumption (whatever happens to the param inside the method stays inside the method) that you seem to want:
module SampleModule
def self.testing(o)
o = o.clone
o.test
end
end
- Technically this should be a deep clone to be generic, but that wouldn't be required to make your example work close to a pass-by-value. You could call
SampleModule.testing( any_var_or_expression )
and know that whatever any_var_or_expression
is in the rest of your code, the associated object will not have been changed.