Ruby - Parameters by Reference or by Value

Is Ruby pass by reference or by value?

In traditional terminology, Ruby is strictly pass-by-value. But that's not really what you're asking here.

Ruby doesn't have any concept of a pure, non-reference value, so you certainly can't pass one to a method. Variables are always references to objects. In order to get an object that won't change out from under you, you need to dup or clone the object you're passed, thus giving an object that nobody else has a reference to. (Even this isn't bulletproof, though — both of the standard cloning methods do a shallow copy, so the instance variables of the clone still point to the same objects that the originals did. If the objects referenced by the ivars mutate, that will still show up in the copy, since it's referencing the same objects.)

How to pass by reference in Ruby?

Ruby is strictly pass-by-value, which means references in the caller's scope are immutable. Obviously they are mutable within the scope, since you can assign to them after all, but they don't mutate the caller's scope.

a = 'foo'

def bar(b)
b = 'bar'
end

bar(a)

a
# => 'foo'

Note, however, that the object can be mutated even if the reference cannot:

a = 'foo'

def bar(b)
b << 'bar' # the only change: mutate the object instead of the reference
b = 'baz'
end

bar(a)

a
# => 'foobar'

If the object you get passed is immutable, too, then there is nothing you can do. The only possibilities for mutation in Ruby are mutating the reference (by assignment) or asking an object to mutate itself (by calling methods on it).

You can return an updated value from your method and have the caller assign that to the reference:

a = :foo

def bar(b)
:"#{a}bar"
end

c = bar(a)

c
# => :foobar

Or you can wrap the immutable object in a mutable one and mutate that mutable wrapper:

a = [:foo]

def bar(b)
b[0] = :bar
end

bar(a)

a
# => [:bar]

[This is really the same thing as the second example above.]

But if you can't change anything, then you are stuck.

'pass parameter by reference' in Ruby?

You can accomplish this by explicitly passing in the current binding:

def func(x, bdg)
eval "#{x} += 1", bdg
end

a = 5
func(:a, binding)
puts a # => 6

Are arguments passed to methods by reference or value?

Everything in Ruby is an object.

Close enough.

Variables are references to objects

No. A variable "names" an object: when a variable is evaluated, it evaluates to the object that it currently "names". Internally this is done by "storing a pointer" (or equivalent mechanism) to an object. (Although an implementation does not need to always use pointers: in Ruby MRI, for instance, Fixnum values actually exist without a real object.)

(When passing in a variable into a method): The parameter in the method that catches the variable is a local variable to that method. The parameter (local variable) now also has a reference to the same object.

No. See above. However, both variables now name (or "evaluate to") the same object. The parameters are passed internally using Call-by-Value -- that is, internally, the pointers to the objects are passed -- although Ruby has Call-by-Object-Sharing semantics, which is a term I try to promote as I find it succinctly describes the behavior.

I could alter the object (in place) and this alteration will hold when the method scope is exited. Any variables referencing this object outside the method scope will reflect that the object has been altered.

Yes, an object is itself. If you mutate that object, you mutate that object everywhere. But note: none of the variables are changed. Both the inside and the outside variables will still name (or "evaluate to") the same object.

A new assignment to that parameter (local variable) does not change the original object, thus any references to it when the method leaves scope will remain unchanged.

Correct. If you assign a different value to the local variable you make it, the local variable, name a different object. Ruby is not Call-by-Reference so the variable in the calling context is not altered.

If I am passing a variable into the method that references an Integer there is effectively no way that once that method exits I could have that variable referencing a new Integer?

Variables are never passed. Variables are evaluated to the objects they name and those objects are passed. Anyway, we know that:

  1. Ruby is not Call-by-Reference and;
  2. Integers (Fixnums) are immutable

Thus:

x = 1
y.foo(x)

can never change what x names, nor can it even change the contents of the object x names (because it's, well, immutable). Even if the object that x named was mutable, the method could not have changed what object x names: it could only have mutated the object that resulted from the evaluation of x.

Happy coding.


Now, The Ruby Way -- in my book -- would be to use a better return value that compassed all the new state, and let the caller put it where it needs to go :-)

Of course, mutable objects (including simple arrays) are also an option, but that's ick. And, if there is enough state that travels together, it might be a candidate for a separate class.


As a closing note: Ruby supports a concept of closures, so it is possible in a lexically-scoped manner:

x = 1; (lamb­da {|a| x = a}).c­all(2); x  // => 2

(This was shown for a simple lambda, but it is possible to design/craft a method to work similarly: in all the silly counter-examples like this, the outside variable itself needs to be known, however, as there is no way for the lambda/method of make an outside variable name a new object otherwise.)

Ruby string pass by reference function parameter

I understand ruby does pass by reference for function parameters

Ruby is strictly pass-by-value, always. There is no pass-by-reference in Ruby, ever.

This is simply out of curiosity -- any explanations would be appreciated

The simple explanation for why your code snippet doesn't show the result you would expect for pass-by-reference is that Ruby isn't pass-by-reference. It is pass-by-value, and your code snippet proves that.

Here is a small snippet that demonstrates that Ruby is, in fact, pass-by-value and not pass-by-reference:

#!/usr/bin/env ruby

def is_ruby_pass_by_value?(foo)
foo << <<~HERE
More precisely, it is call-by-object-sharing!
Call-by-object-sharing is a special case of pass-by-value,
where the value is always an immutable pointer to a (potentially mutable) value.
HERE
foo = 'No, Ruby is pass-by-reference.'
return
end

bar = ['Yes, of course, Ruby *is* pass-by-value!']

is_ruby_pass_by_value?(bar)

puts bar
# Yes, of course, Ruby *is* pass-by-value!,
# More precisely, it is call-by-object-sharing!
# Call-by-object-sharing is a special case of pass-by-value,
# where the value is always an immutable pointer to a (potentially mutable) value.

Ruby does however allow mutation of objects, it is not a purely functional language like Haskell or Clean.

Integer variables pass by value, string variables by reference?

You need to understand the difference between variables and values. A variable points to a value. Multiple variables can point to the same value.

In Ruby, the only way to modify a variable is via assignment, either simple

foo = :something

or compound assignment

foo ω= :something # for some operator ω
# e.g.
foo += :something
foo <<= :something
foo ||= :something

If you modify a value, that modification will be visible no matter what variable you use to access that value.

Think about it this way: my mum calls me "son", my friends call me "Jörg", my close friends call me "jwm", my band colleagues call me "Jörgislaw", my girlfriend calls me "baby", but no matter what they call me, if I cut my hair, my hair will be gone, regardless of what name they use to refer to me. If, however, my girlfriend assigns a new value to the label "baby", then that does not affect me. (Well … bear with me, it's an analogy :-D )

In Ruby, << typically modifies the receiver, whereas / doesn't.

However, Ruby is always pass-by-value. But the value being passed is a pointer to a value, so that multiple variables can contain multiple copies of the same pointer to the same value.

How to make a Ruby method to pass output parameters (change the value of referenced arguments)?

Ruby has only pass by value, just like Python and Java. Also like Python and Java, objects are not values directly, and are manipulated through references.

It seems you already understand how it works -- assigning to a local variable never has any effect on a caller scope. And to "share" information with the caller scope other than returning, you must use some method on the object to "mutate" the object (if such a method exists; i.e. if the object is mutable) that is pointed to by the passed reference. However, this simply modifies the same object rather than giving a reference to a new object, which you want.

If you are not willing to return the value, you can pass a mutable container (like an array of one element) that the called function can then mutate and put whatever in there and have it be seen in the caller scope.

Another option is to have the function take a block. The function would give the block the new value of pizza, and the block (which is given by the caller) can then decide what to do with it. The caller can pass a block that simply sets the pizza in its own scope.

Pass by reference or pass by copy - Ruby Modules

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 Arrays and Strings) 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.

ruby pass-by-reference vs pass-reference-by-value

I do not understand why this distinction is made.

This distinction is the essence of pass-by-reference. In your first function, you can do a simple assignment to the parameter: i = something, and it will do the same thing as an assignment in the calling scope. In your second function, i = something can never have an effect on the calling scope. In fact, there is nothing that you can do inside the second function that has the exact same semantics as assigning to the variable in the calling scope. That's it. That's the distinction.

In Ruby (as well as Python, Java, and many other languages), assigning to a parameter variable (with =) never has an effect on the calling scope. Hence, they are pass by value.



Related Topics



Leave a reply



Submit