282
@user.update_languages(params[:language][:language1], 
                       params[:language][:language2], 
                       params[:language][:language3])
lang_errors = @user.errors
logger.debug "--------------------LANG_ERRORS----------101-------------" 
                + lang_errors.full_messages.inspect

if params[:user]
  @user.state = params[:user][:state]
  success = success & @user.save
end
logger.debug "--------------------LANG_ERRORS-------------102----------" 
                + lang_errors.full_messages.inspect

if lang_errors.full_messages.empty?

@user object adds errors to the lang_errors variable in the update_lanugages method. when I perform a save on the @user object I lose the errors that were initially stored in the lang_errors variable.

Though what I am attempting to do would be more of a hack (which does not seem to be working). I would like to understand why the variable values are washed out. I understand pass by reference so I would like to know how the value can be held in that variable without being washed out.

isomorphismes
  • 8,233
  • 9
  • 59
  • 70
Sid
  • 6,134
  • 9
  • 34
  • 57
  • I also notice that I am able to retain that value in a cloned object – Sid Dec 09 '09 at 07:13
  • 2
    You should look at Abe Voelker answer. But after running around the block on this, here's how I would say it. when you pass an object Foo to a procedure, a copy of the reference to the object is passed, bar, Pass by value. you cannot change the object that the Foo points to, but you can change the contents of the object that it points to. So if you pass an array, the contents of the array can be changed, but you cannot change what array is being referenced. nice to be able to use the methods of Foo without having to worry about messing up other dependencies on Foo. – bobbdelsol Jan 10 '14 at 02:02

14 Answers14

474

The other answerers are all correct, but a friend asked me to explain this to him and what it really boils down to is how Ruby handles variables, so I thought I would share some simple pictures / explanations I wrote for him (apologies for the length and probably some oversimplification):


Q1: What happens when you assign a new variable str to a value of 'foo'?

str = 'foo'
str.object_id # => 2000

enter image description here

A: A label called str is created that points at the object 'foo', which for the state of this Ruby interpreter happens to be at memory location 2000.


Q2: What happens when you assign the existing variable str to a new object using =?

str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002

enter image description here

A: The label str now points to a different object.


Q3: What happens when you assign a new variable = to str?

str2 = str
str2.object_id # => 2002

enter image description here

A: A new label called str2 is created that points at the same object as str.


Q4: What happens if the object referenced by str and str2 gets changed?

str2.replace 'baz'
str2 # => 'baz'
str  # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002

enter image description here

A: Both labels still point at the same object, but that object itself has mutated (its contents have changed to be something else).


How does this relate to the original question?

It's basically the same as what happens in Q3/Q4; the method gets its own private copy of the variable / label (str2) that gets passed in to it (str). It can't change which object the label str points to, but it can change the contents of the object that they both reference to contain else:

str = 'foo'

def mutate(str2)
  puts "str2: #{str2.object_id}"
  str2.replace 'bar'
  str2 = 'baz'
  puts "str2: #{str2.object_id}"
end

str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004
Abe Voelker
  • 30,124
  • 14
  • 81
  • 98
  • 3
    Robert Heaton also blogged about this lately: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/ – Michael Renner Dec 11 '14 at 02:33
260

In traditional terminology, Ruby is strictly pass-by-value. However, everything in Ruby is an object, so Ruby can appear to behave like pass-by-reference languages.

Ruby breaks the traditional definition of "pass-by-reference" or "pass-by-value" because everything is an object, and when it passes things, it passes references to objects. So really, it Ruby can be classified as a 3rd type of language we might call "pass by object reference." In the strict definition of the computer science term, Ruby is pass-by-value.

Ruby doesn't have any concept of a pure, non-reference value, so you 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. However, even this isn't bulletproof: 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.

Jason FB
  • 4,752
  • 3
  • 38
  • 69
Chuck
  • 234,037
  • 30
  • 302
  • 389
  • Thank you. I'm still not sure if this is completely a good feature. Wouldn't an explicit method to pass by value be helpful though everything is an object. Another thing is I find that the cloned copy has a different object_id so doesn't that make it completely indifferent to the original object though it may hold the values of the original object or are my fundamentals totally flawed here? – Sid Dec 09 '09 at 08:00
  • 3
    Yes, the clone is a completely independent object. As for pass-by-value, it's not really compatible with pure OO, where "values" don't exist except as object state. The closest you could get is something like Objective-C's `bycopy` type modifier that tells the runtime to make a copy behind the scenes. That does sound useful. – Chuck Dec 09 '09 at 08:39
  • 94
    Ruby is *pass-by-value*. No ifs. No buts. No exceptions. If you want to know whether Ruby (or any other language) is *pass-by-reference* or *pass-by-value*, just try it out: `def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"`. – Jörg W Mittag Apr 26 '12 at 09:26
  • 112
    @JörgWMittag: Yeah, but the OP's confusion is actually not pass-by-value or pass-by-reference in the strict CS sense of the words. What he was missing is that the "values" you're passing *are* references. I felt that just saying "It's pass-by-value" would be pedantic and do the OP a disservice, as that isn't actually what he meant. But thanks for the clarification, because it is important for future readers and I should have included it. (I'm always torn between including more info and not confusing people.) – Chuck Apr 26 '12 at 14:53
  • In this answer, what does "ivars" mean? – Eddified Jul 21 '12 at 23:37
  • @Eddified: Instance variables. I didn't think it had any other meaning. – Chuck Jul 23 '12 at 18:33
  • 18
    Disagreeing with @Jorg. Ruby is pass by reference, he just changes the reference. Try this instead: def foo(bar) bar.replace 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}" – pguardiario Aug 18 '12 at 10:31
  • 3
    @pguardiario: Your code has absolutely nothing whatsoever to do with passing by reference or passing by value. It would print exactly the same thing regardless of whether Ruby is pass-by-reference or pass-by-value. The only thing your code proves is that Ruby is not a purely functional language, which I don't think anybody would dispute anyway. – Jörg W Mittag Aug 18 '12 at 10:34
  • 2
    @pguardiario: The thing about "pass-by-reference" vs. "pass-by-value" is that pass-by-reference means you're directly referring to the caller's memory space, such that reassigning the variable would change the variable in the caller. This doesn't happen. `foo`'s variable `bar` is an independent variable that simply has the same *value* as the caller's `baz`. It just so happens that in this case the value is an object reference. But in terms of calling convention, it's considered pass-by-value. – Chuck Aug 19 '12 at 17:06
  • @Chuck, I disagree. foo's bar is a variable that *references* the original object. Otherwise the original object couldn't be affected from inside the method. That's why I say pass by reference. Though I will concede that it may depend on how you look at it. – pguardiario Aug 19 '12 at 23:55
  • 18
    @pguardiario: I think it's really just a question of definitions. You're using a definition of "pass-by-reference" that you've personally come up with, while Jörg is using the traditional computer science definition. Of course, it is none of my business to tell you how to use words — I just think it's important to explain what the term *normally* means. In traditional terminology, Ruby is pass-by-value, but the values themselves are references. I totally understand why you and the OP like to think of this as pass-by-reference — it's just not the traditional meaning of the term. – Chuck Aug 20 '12 at 18:22
  • 2
    @Chuck, I agree that it's a question of definitions but I didn't make them up. Pass by value means a copy is sent to the method and it's clear that this isn't what is happening. – pguardiario Aug 20 '12 at 23:20
  • @pguardiario - it sounds like a copy IS sent to the method: a copy of the reference. – Riley Lark Nov 21 '12 at 15:18
  • 2
    In C++, "pass by value" means the function gets a copy of the variable and any changes to the copy don't change the original. That's true for objects too. If you pass an object variable by value then the whole object (including all of its members) get copied and any changes to the members don't change those members on the original object. (It's different if you pass a pointer by value but Ruby doesn't have pointers anyway, AFAIK.) – David Winiecki May 02 '14 at 03:58
  • 2
    In C++, "pass by reference" means the function gets access to the original variable. It can assign a whole new literal integer and the original variable will then have that value too. – David Winiecki May 02 '14 at 04:00
  • 4
    Ruby, Python, Java, JavaScript, and C#, use pass by value (in the C++ sense) _if the argument is not an object_. If the argument is an object, then "pass by object reference" (to use Python's terminology) is used: any of the object's members can have new values assigned to them and the original object will remember these changes, but assigning a whole new object to the variable causes the variable to stop referencing the original. Therefore it is not "pass by reference" in the C++ sense. – David Winiecki May 02 '14 at 04:09
  • 7
    Everything in Ruby is an object, so Ruby is neither pass by value nor pass by reference, at least in the sense those terms are used in C++. "pass by object reference" might be a better way to describe what Ruby does. In the end though, the best bet might be not to put too much meaning on any of these terms, and just get a good understanding of the behavior that really happens. – David Winiecki May 02 '14 at 05:10
  • [@DavidWiniecki comment](http://stackoverflow.com/questions/1872110/is-ruby-pass-by-reference-or-by-value#comment35890968_1872159): _if the argument is an object, then "pass by object reference"._ . Not C# which does what [@Chuck comment says](http://stackoverflow.com/users/50742/chuck). C# default is pass by value - the reference variable is copied. That variable is an object's address, not the object. Unless explicitly using the `ref` keyword: `RefMeBaby( ref addressOfBob );`. Using `ref` is extremely rare. – radarbob Aug 22 '16 at 19:10
  • @JörgWMittag Totally disagree with your example, def foo(bar) bar = 'reference' end baz = 'value' puts "Ruby is pass-by-#{foo(baz)}" Execute this and see – Navneet Mar 24 '22 at 06:20
  • 1
    @Navneet: I don't understand what your example is trying to accomplish. You are simply looking at the return value, but *that has nothing to do with pass-by-reference vs. pass-by-value*. Pass-by-reference means that you can *manipulate the variable binding in the caller's context* which is something Ruby cannot do because it is *not* pass-by-reference, it is pass-by-value. I never claimed Ruby cannot return a value. Of course it can. But that is irrelevant to the question of whether it is pass-by-value or pass-by-reference. – Jörg W Mittag Mar 24 '22 at 07:00
  • The semantics of the original distinction between PBR and PBV are insufficient to discuss the behavior of an object-oriented language, wherein passing an object in to a method effectively passes the _value of the pointer to that object_, even if the language in question does not expose pointers to the user. The called method gets its own copy of the pointer, but the pointer still points to the same object, and if that object is mutable, then any mutations made by the callee will be visible to the caller, effectively giving "pass by reference" semantics. – JakeRobb Apr 24 '23 at 20:55
64

Ruby uses "pass by object reference"

(Using Python's terminology.)

To say Ruby uses "pass by value" or "pass by reference" isn't really descriptive enough to be helpful. I think as most people know it these days, that terminology ("value" vs "reference") comes from C++.

In C++, "pass by value" means the function gets a copy of the variable and any changes to the copy don't change the original. That's true for objects too. If you pass an object variable by value then the whole object (including all of its members) get copied and any changes to the members don't change those members on the original object. (It's different if you pass a pointer by value but Ruby doesn't have pointers anyway, AFAIK.)

class A {
  public:
    int x;
};

void inc(A arg) {
  arg.x++;
  printf("in inc: %d\n", arg.x); // => 6
}

void inc(A* arg) {
  arg->x++;
  printf("in inc: %d\n", arg->x); // => 1
}

int main() {
  A a;
  a.x = 5;
  inc(a);
  printf("in main: %d\n", a.x); // => 5

  A* b = new A;
  b->x = 0;
  inc(b);
  printf("in main: %d\n", b->x); // => 1

  return 0;
}

Output:

in inc: 6
in main: 5
in inc: 1
in main: 1

In C++, "pass by reference" means the function gets access to the original variable. It can assign a whole new literal integer and the original variable will then have that value too.

void replace(A &arg) {
  A newA;
  newA.x = 10;
  arg = newA;
  printf("in replace: %d\n", arg.x);
}

int main() {
  A a;
  a.x = 5;
  replace(a);
  printf("in main: %d\n", a.x);

  return 0;
}

Output:

in replace: 10
in main: 10

Ruby uses pass by value (in the C++ sense) if the argument is not an object. But in Ruby everything is an object, so there really is no pass by value in the C++ sense in Ruby.

In Ruby, "pass by object reference" (to use Python's terminology) is used:

  • Inside the function, any of the object's members can have new values assigned to them and these changes will persist after the function returns.*
  • Inside the function, assigning a whole new object to the variable causes the variable to stop referencing the old object. But after the function returns, the original variable will still reference the old object.

Therefore Ruby does not use "pass by reference" in the C++ sense. If it did, then assigning a new object to a variable inside a function would cause the old object to be forgotten after the function returned.

class A
  attr_accessor :x
end

def inc(arg)
  arg.x += 1
  puts arg.x
end

def replace(arg)
  arg = A.new
  arg.x = 3
  puts arg.x
end

a = A.new
a.x = 1
puts a.x  # 1

inc a     # 2
puts a.x  # 2

replace a # 3
puts a.x  # 2

puts ''

def inc_var(arg)
  arg += 1
  puts arg
end

b = 1     # Even integers are objects in Ruby
puts b    # 1
inc_var b # 2
puts b    # 1

Output:

1
2
2
3
2

1
2
1

* This is why, in Ruby, if you want to modify an object inside a function but forget those changes when the function returns, then you must explicitly make a copy of the object before making your temporary changes to the copy.

David Winiecki
  • 4,093
  • 2
  • 37
  • 39
  • 1
    Your answer is the best. I also wanna post a simple example `def ch(str) str.reverse! end; str="abc"; ch(str); puts str #=> "cba"` – Fangxing Jul 06 '17 at 14:25
  • This is the correct answer! This is also very well explained here: https://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value. But what I still don't understand is this: `def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"`. This prints "Ruby is pass-by-value". But the variable inside `foo` is reassigned. If `bar` would be an array the reassignment would not effect `baz`. Why? – haffla Oct 06 '17 at 09:58
  • I don't understand your question. I think you should ask a whole new question instead of asking in comments here. – David Winiecki Oct 12 '17 at 05:27
  • @haffla `def foo(bar) bar = 'reference' end;` is reassigning bar to the string object 'reference'; so bar and baz are no longer referencing the same string object. Add a couple print object_id statements to get a closer look. `def foo(bar) puts "bar before reassign: #{bar.object_id}"; bar = 'reference'; puts "bar after reassign: #{bar.object_id}"; end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"; puts "baz: #{baz.object_id}";` bar before reassign: 7864800 bar after reassign: 7864620 Ruby is pass-by-value baz: 7864800 – aka Jun 30 '21 at 16:21
40

Is Ruby pass by reference or by value?

Ruby is pass-by-value. Always. No exceptions. No ifs. No buts.

Here is a simple program which demonstrates that fact:

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • 15
    @DavidJ.: "The mistake here is that the local parameter is reassigned (pointed to a new place in memory)" – That's not a mistake, that's the *definition* of *pass-by-value*. If Ruby were pass-by-reference, then reassignment to the local method argument binding in the callee would also have reassigned the local variable binding in the caller. Which it didn't. Ergo, Ruby is pass-by-value. The fact that if you change a mutable value, the value changes is completely irrelevant, that's just how mutable state works. Ruby is not a pure functional language. – Jörg W Mittag May 22 '12 at 11:15
  • 7
    Thanks to Jörg to defend the true definition of "pass-by-value". It's clearly melting our brain when the value is in fact a reference, though ruby always pass by-value. – Douglas Feb 19 '13 at 13:00
  • 10
    This is sophistry. The practical distinction between "pass by value" and "pass by reference" is a semantic, not a syntactic one. Would you say that C arrays are pass-by-value? Of course not, even though when you pass the name of an array to a function you are passing an immutable pointer, and only the data to which the pointer refers can be mutated. Clearly value types in Ruby are passed by value, and reference types are passed by reference. – dodgethesteamroller Oct 29 '13 at 00:14
  • 3
    @dodgethesteamroller: Both Ruby and C are pass-by-value. Always. No exceptions, not ifs no buts. The distinction between pass-by-value and pass-by-reference is whether you pass the value the reference points to or pass the reference. C *always* passes the value, *never* the reference. The value may or may not be a pointer, but *what* the value is is irrelevant to whether it is being passed in the first place. Ruby also *always* passes the value, *never* the reference. That value is *always* a pointer, but again, that is irrelevant. – Jörg W Mittag Oct 29 '13 at 00:39
  • In reality, some Ruby implementations actually do not *always* pass a pointer by value. They sometimes pass the value directly by value. However, they only do this for objects which have certain immutability guarantees from the Ruby Language Specification, so that this optimization doesn't change the observable behavior of the program (as all optimizations should). … – Jörg W Mittag Oct 29 '13 at 00:45
  • Since the difference between passing the object directly by value or passing a pointer to the object by value can only be observed when the object is mutated, and those specific objects (`Fixnum`s, `true`, `false`, `nil`, `Symbol`s, `Float`s) *can't* be mutated, it is safe for the compiler/interpreter to pass the object directly by value and not the pointer by value. But that is a performance optimization which doesn't change the observable behavior of the program – any Ruby program would behave exactly identical if pointers to `Symbol`s and `Fixnum`s were passed instead. – Jörg W Mittag Oct 29 '13 at 00:47
  • @JörgWMittag There is no such creature as a "Ruby Language Specification." We can only infer such a thing from Ruby's source code and/or its behavior. – dodgethesteamroller Oct 29 '13 at 01:13
  • @dodgethesteamroller: There are several creatures that one might reasonably call a "Ruby Language Specification". http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579 is one. http://RubySpec.Org/ is another. The consensus of the implementors of the various Ruby Implementations is one, as is Matz's brain. And all of them agree: Ruby is pass-by-value. Period. – Jörg W Mittag Oct 29 '13 at 23:12
  • 53
    This answer, while strictly speaking *true*, is not very *useful*. The fact that the value being passed is always a pointer is *not* irrelevant. It is a source of confusion for people who are trying to learn, and your answer does absolutely nothing to help with that confusion. –  Dec 03 '13 at 23:53
  • 3
    If Ruby is pass-by-value because you always pass the value of a pointer, then a line like `baz = 'reference'` doesn't make much sense. A pointer is not a String. If you were manipulating the value of the reference, you would only be able to assign it to an other pointer. In this case `=` is not the assignment of a pointer, it is saying instantiate a new String and store a pointer to the String in `bar`. Basically, the example above states that we are working with pointers and then uses a String operation to prove it. The String _is_ passed into foo by reference. The pointers are not. – spinlock Jan 28 '14 at 17:52
  • call `bar.gsub!(/value/, 'reference')` within the method. You will see that the outer object is indeed subject to mutation. effectively the only thing passed by value is the reference to the object. – Keith Gaddis Mar 06 '15 at 19:21
  • 2
    @karmajunkie: Yes, and that makes Ruby pass-by-value. It doesn't matter *what* is passed, it matters *how* it is passed, and as you say yourself, the pointer is passed *by value*. Ergo, Ruby is pass-by-value. C is also always pass-by-value, regardless of whether you pass an `int` or an `int*`. Just because you are passing a pointer doesn't change the calling conventions. You can imagine Ruby being like C, except that all methods take and return an opaque `object_t*` pointer. That's still pass-by-value. – Jörg W Mittag Mar 06 '15 at 19:30
  • Am I completely missing something here, or in some circumstances, Ruby is pass-by-reference, like `each do` for example http://ahimmelstoss.github.io/blog/2014/06/11/pass-by-value-vs-pass-by-reference-in-ruby/ – teaforchris Oct 07 '15 at 09:23
  • @cp5w: no, that has exactly nothing to do with pass-by-value vs. pass-by-reference. That's just plain mutation. Ruby is not a purely functional language, if you tell an object to change itself, it changes. If you tell a string to append an `!` to itself, it will have an `!` appended. – Jörg W Mittag Oct 07 '15 at 09:25
  • @JörgWMittag ok this makes sense. This behaviour with `each do` is just a little alien to me as I have only recently moved to Ruby. So it looks like I have to clone an object if I don't want to affect the original (or in my case, where the original is "read only") in an `each do` iteration? – teaforchris Oct 07 '15 at 09:32
  • @cp5w: Yes, that's one of the problems with mutable state, and why so many programmers are adopting purely immutable objects with referentially transparent methods even in non-purely functional languages like Java, or Ruby. (If you read, for example, books like *Effective Java* and *Java Concurrency in Practice*, the entire content of those two books can be pretty much summarized as "use functional programming".) If you have mutable state, you need to define tight contracts about who is allowed to mutate what in which way when or if you can't trust those contracts, you have to copy everything. – Jörg W Mittag Oct 07 '15 at 09:51
  • 1
    This is an unhelpful example. If the content of the function in this answer were `bar.replace 'reference'` then the output would be `Ruby is pass-by-reference` – Toby 1 Kenobi Dec 09 '15 at 01:26
  • @Toby1Kenobi: Yes, there are of course many ways to get this to print the wrong thing by modifying it to print the wrong thing. However, what *your* example *would* show is *not* pass-by-reference but rather shared mutable state, which is not the question here. Nobody (and certainly not me) claims that Ruby is a pure functional language. Of course, it has shared mutable state, and when you mutate shared state that mutation is visible everywhere. If I cut my hair, my hair is gone, regardless if you reference me has "Jörg" like my colleagues or "son" like my father. – Jörg W Mittag Dec 09 '15 at 02:10
  • 1
    @JörgWMittag I thought your example was trying to show that the function makes a copy of the string parameter so that when you change the string in the function the original string is not changed. That is why I made the comment above. Now I understand more, I see that what you are showing is that the function makes a copy of the reference to the string so that when you reassign the reference the original reference is not reassigned. If you had made this clear in your answer this would have saved a lot of confusion, probably for other people too. – Toby 1 Kenobi Dec 09 '15 at 08:33
  • Could you please explain this printing Ruby is pass-by-reference: `def foo(bar) bar[0..-1] = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"` – Saleh Rastani Aug 01 '16 at 21:02
  • @SalehRastani: you are mutating the object, not changing the reference. Mutating objects is perfectly allowed in Ruby, Ruby is not a purely functional language like Haskell. This has nothing to do with pass-by-reference vs. pass-by-value, it's simple mutation. – Jörg W Mittag Aug 01 '16 at 21:04
26

Ruby is pass-by-value in a strict sense, BUT the values are references.

This could be called "pass-reference-by-value". This article has the best explanation I have read: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/

Pass-reference-by-value could briefly be explained as follows:

A function receives a reference to (and will access) the same object in memory as used by the caller. However, it does not receive the box that the caller is storing this object in; as in pass-value-by-value, the function provides its own box and creates a new variable for itself.

The resulting behavior is actually a combination of the classical definitions of pass-by-reference and pass-by-value.

Ari
  • 990
  • 12
  • 12
  • "pass reference by value" is the same phrase I use to describe Ruby's argument passing. I think it's the most accurate and succinct phrase. – Wayne Conrad Aug 22 '16 at 16:07
  • This article helped me appreciate that Ruby is pass by reference of the value: https://launchschool.com/blog/object-passing-in-ruby – Pablo Oct 09 '20 at 15:06
17

There are already some great answers, but I want to post the definition of a pair of authorities on the subject, but also hoping someone might explain what said authorities Matz (creator of Ruby) and David Flanagan meant in their excellent O'Reilly book, The Ruby Programming Language.

[from 3.8.1: Object References]

When you pass an object to a method in Ruby, it is an object reference that is passed to the method. It is not the object itself, and it is not a reference to the reference to the object. Another way to say this is that method arguments are passed by value rather than by reference, but that the values passed are object references.

Because object references are passed to methods, methods can use those references to modify the underlying object. These modifications are then visible when the method returns.

This all makes sense to me until that last paragraph, and especially that last sentence. This is at best misleading, and at worse confounding. How, in any way, could modifications to that passed-by-value reference change the underlying object?

Community
  • 1
  • 1
Dominick
  • 437
  • 5
  • 16
  • 1
    Because the reference isn't getting modified; the underlying object is. – dodgethesteamroller Oct 29 '13 at 00:10
  • 1
    Because the object is mutable. Ruby is not a purely functional language. This is completely orthogonal to pass-by-reference vs. pass-by-value (except for the fact that in a purely functional language, pass-by-value and pass-by-reference always yield the same results, so the language could use either or both without you ever knowing). – Jörg W Mittag Sep 19 '14 at 09:14
  • 2
    A good example would be if instead of a variable assignment in a function, you look at the case of passing a hash to a function and doing a merge! on the passed hash. The original hash ends up modified. – elc Jul 20 '15 at 16:59
15

Is Ruby pass by reference or by value?

Ruby is pass-by-reference. Always. No exceptions. No ifs. No buts.

Here is a simple program which demonstrates that fact:

def foo(bar)
  bar.object_id
end

baz = 'value'

puts "#{baz.object_id} Ruby is pass-by-reference #{foo(baz)} because object_id's (memory addresses) are always the same ;)"

=> 2279146940 Ruby is pass-by-reference 2279146940 because object_id's (memory addresses) are always the same ;)

def bar(babar)
  babar.replace("reference")
end

bar(baz)

puts "some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-#{baz}"

=> some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-reference

Brett Allred
  • 3,459
  • 26
  • 30
  • This is the only correct answer and presents some nice gotchas: Try a = 'foobar' ; b = a ; b[5] = 'z', both a and b will get modified. – Martijn Feb 10 '14 at 12:55
  • 2
    @Martijn: your argument is not entirely valid. Let's go through your code statement by statement. a = 'foobar' creates a new reference pointing to 'foobar'. b = a creates a second reference to the same data as a. b[5] = 'z' changes the sixth character of the value referenced by b to a 'z' (the value which is coincidentally also referenced by a gets changed). That's why "both get modified" in your terms, or more precisely, why "the value referenced by both variables gets modified". – Lukas_Skywalker May 28 '14 at 13:07
  • 2
    You are not doing anything with the reference in your `bar` method. You are simply modifying the object that the reference *points* to, but not the reference itself. They only way to modify references in Ruby is by assignment. You cannot modify references by calling methods in Ruby because methods can only be called on objects and references are not objects in Ruby. Your code sample demonstrates that Ruby has shared mutable state (which is not under discussion here), it does however nothing to illuminate the distinction between pass-by-value and pass-by-reference. – Jörg W Mittag Feb 15 '15 at 17:13
  • 1
    When someone asks whether a language is "pass-by-reference" they usually want to know when you pass something to a function and the function modifies it, will it be modified outside the function. For Ruby the answer is 'yes'. This answer is helpful in demonstrating that, @JörgWMittag's answer is extremely unhelpful. – Toby 1 Kenobi Dec 09 '15 at 01:33
  • @Toby1Kenobi: You are of course free to use your own personal definition of the term "pass-by-value" which is different from the common, widely-used definition. However, if you do so, you should be prepared for people to be confused, especially if you neglect to disclose the fact that you are talking about a very different, in some aspects even opposite notion than everybody else does. In particular, "pass-by-reference" is *not* concerned with whether or not the "something" that is passed can be modified, but rather with *what* that "something" is, in particular, whether it is the reference … – Jörg W Mittag Dec 09 '15 at 02:19
  • … *itself* that is being passed (pass-by-reference) or whether the *value* that the reference *points to* is being passed. In Ruby, it's the latter. Ergo, Ruby is pass-by-value. Now, it just so happens that the value is a pointer to a shared mutable object, and that when you mutate this object, other pieces of code that also have a pointer to this object can observe these modifications, but that has nothing to do with pass-by-reference vs. pass-by-value. That's just how shared mutable state works. Ruby is not a pure functional language, and nobody ever claimed that is was. – Jörg W Mittag Dec 09 '15 at 02:21
  • @JörgWMittag, sorry I spoke from ignorance. David Winiecki's answer has given me more understanding. I never knew that in C++ pass-by-reference when you reassigned a new value to the reference in the function the original reference would also be reassigned. I suppose this is the key difference between references and pointers in C++ that I never understood before. I thought Ruby's behavior was the same as pass-by-reference in C++, but it's not. – Toby 1 Kenobi Dec 09 '15 at 08:23
  • I like this answer because, in combination with [JörgWMittag's answer](http://stackoverflow.com/a/10330589/1157054), it shows how silly it is to use pass-by-value and pass-by-reference in the C++ sense of the terms when talking about Ruby. Both this example and Jörg's are perfectly valid examples that demonstrate Ruby exhibiting traits from both passing styles, so practically speaking neither definition really fits. – Ajedi32 Aug 22 '16 at 16:51
9

Parameters are a copy of the original reference. So, you can change values, but cannot change the original reference.

Rael Gugelmin Cunha
  • 3,327
  • 30
  • 25
3

Try this:--

1.object_id
#=> 3

2.object_id
#=> 5

a = 1
#=> 1
a.object_id
#=> 3

b = 2
#=> 2
b.object_id
#=> 5

identifier a contains object_id 3 for value object 1 and identifier b contains object_id 5 for value object 2.

Now do this:--

a.object_id = 5
#=> error

a = b
#value(object_id) at b copies itself as value(object_id) at a. value object 2 has object_id 5
#=> 2

a.object_id 
#=> 5

Now, a and b both contain same object_id 5 which refers to value object 2. So, Ruby variable contains object_ids to refer to value objects.

Doing following also gives error:--

c
#=> error

but doing this won't give error:--

5.object_id
#=> 11

c = 5
#=> value object 5 provides return type for variable c and saves 5.object_id i.e. 11 at c
#=> 5
c.object_id
#=> 11 

a = c.object_id
#=> object_id of c as a value object changes value at a
#=> 11
11.object_id
#=> 23
a.object_id == 11.object_id
#=> true

a
#=> Value at a
#=> 11

Here identifier a returns value object 11 whose object id is 23 i.e. object_id 23 is at identifier a, Now we see an example by using method.

def foo(arg)
  p arg
  p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23

arg in foo is assigned with return value of x. It clearly shows that argument is passed by value 11, and value 11 being itself an object has unique object id 23.

Now see this also:--

def foo(arg)
  p arg
  p arg.object_id
  arg = 12
  p arg
  p arg.object_id
end

#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
#=> 12
#=> 25
x
#=> 11
x.object_id
#=> 23

Here, identifier arg first contains object_id 23 to refer 11 and after internal assignment with value object 12, it contains object_id 25. But it does not change value referenced by identifier x used in calling method.

Hence, Ruby is pass by value and Ruby variables do not contain values but do contain reference to value object.

Alok Anand
  • 3,346
  • 1
  • 20
  • 17
3

It should be noted that you do not have to even use the "replace" method to change the value original value. If you assign one of the hash values for a hash, you are changing the original value.

def my_foo(a_hash)
  a_hash["test"]="reference"
end;

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"
zishe
  • 10,665
  • 12
  • 64
  • 103
Don Carr
  • 321
  • 2
  • 2
  • Another thing I found. If you are passing a numeric type, all numeric type are immutable, and thus ARE pass by value. The replace function that worked with the string above, does NOT work for any of the numeric types. – Don Carr Mar 28 '14 at 21:18
2
Two references refer to same object as long as there is no reassignment. 

Any updates in the same object won't make the references to new memory since it still is in same memory. Here are few examples :

    a = "first string"
    b = a



    b.upcase! 
    => FIRST STRING
    a
    => FIRST STRING

    b = "second string"


a
    => FIRST STRING
    hash = {first_sub_hash: {first_key: "first_value"}}
first_sub_hash = hash[:first_sub_hash]
first_sub_hash[:second_key] = "second_value"

    hash
    => {first_sub_hash: {first_key: "first_value", second_key: "second_value"}}

    def change(first_sub_hash)
    first_sub_hash[:third_key] = "third_value"
    end

    change(first_sub_hash)

    hash
    =>  {first_sub_hash: {first_key: "first_value", second_key: "second_value", third_key: "third_value"}}
Ayman Hussain
  • 255
  • 2
  • 2
2

Lots of great answers diving into the theory of how Ruby's "pass-reference-by-value" works. But I learn and understand everything much better by example. Hopefully, this will be helpful.

def foo(bar)
  puts "bar (#{bar}) entering foo with object_id #{bar.object_id}"
  bar =  "reference"
  puts "bar (#{bar}) leaving foo with object_id #{bar.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
bar (value) entering foo with object_id 60
bar (reference) leaving foo with object_id 80 # <-----
bar (value) after foo with object_id 60 # <-----

As you can see when we entered the method, our bar was still pointing to the string "value". But then we assigned a string object "reference" to bar, which has a new object_id. In this case bar inside of foo, has a different scope, and whatever we passed inside the method, is no longer accessed by bar as we re-assigned it and point it to a new place in memory that holds String "reference".

Now consider this same method. The only difference is what with do inside the method

def foo(bar)
  puts "bar (#{bar}) entering foo with object_id #{bar.object_id}"
  bar.replace "reference"
  puts "bar (#{bar}) leaving foo with object_id #{bar.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
bar (value) entering foo with object_id 60
bar (reference) leaving foo with object_id 60 # <-----
bar (reference) after foo with object_id 60 # <-----

Notice the difference? What we did here was: we modified the contents of the String object, that variable was pointing to. The scope of bar is still different inside of the method.

So be careful how you treat the variable passed into methods. And if you modify passed-in variables-in-place (gsub!, replace, etc), then indicate so in the name of the method with a bang !, like so "def foo!"

P.S.:

It's important to keep in mind that the "bar"s inside and outside of foo, are "different" "bar". Their scope is different. Inside the method, you could rename "bar" to "club" and the result would be the same.

I often see variables re-used inside and outside of methods, and while it's fine, it takes away from the readability of the code and is a code smell IMHO. I highly recommend not to do what I did in my example above :) and rather do this

def foo(fiz)
  puts "fiz (#{fiz}) entering foo with object_id #{fiz.object_id}"
  fiz =  "reference"
  puts "fiz (#{fiz}) leaving foo with object_id #{fiz.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
fiz (value) entering foo with object_id 60
fiz (reference) leaving foo with object_id 80
bar (value) after foo with object_id 60
konung
  • 6,908
  • 6
  • 54
  • 79
1

Ruby is interpreted. Variables are references to data, but not the data itself. This facilitates using the same variable for data of different types.

Assignment of lhs = rhs then copies the reference on the rhs, not the data. This differs in other languages, such as C, where assignment does a data copy to lhs from rhs.

So for the function call, the variable passed, say x, is indeed copied into a local variable in the function, but x is a reference. There will then be two copies of the reference, both referencing the same data. One will be in the caller, one in the function.

Assignment in the function would then copy a new reference to the function's version of x. After this the caller's version of x remains unchanged. It is still a reference to the original data.

In contrast, using the .replace method on x will cause ruby to do a data copy. If replace is used before any new assignments then indeed the caller will see the data change in its version also.

Similarly, as long as the original reference is in tact for the passed in variable, the instance variables will be the same that the caller sees. Within the framework of an object, the instance variables always have the most up to date reference values, whether those are provided by the caller or set in the function the class was passed in to.

The 'call by value' or 'call by reference' is muddled here because of confusion over '=' In compiled languages '=' is a data copy. Here in this interpreted language '=' is a reference copy. In the example you have the reference passed in followed by a reference copy though '=' that clobbers the original passed in reference, and then people talking about it as though '=' were a data copy.

To be consistent with definitions we must keep with '.replace' as it is a data copy. From the perspective of '.replace' we see that this is indeed pass by reference. Furthermore, if we walk through in the debugger, we see references being passed in, as variables are references.

However if we must keep '=' as a frame of reference, then indeed we do get to see the passed in data up until an assignment, and then we don't get to see it anymore after assignment while the caller's data remains unchanged. At a behavioral level this is pass by value as long as we don't consider the passed in value to be composite - as we won't be able to keep part of it while changing the other part in a single assignment (as that assignment changes the reference and the original goes out of scope). There will also be a wart, in that instance variables in objects will be references, as are all variables. Hence we will be forced to talk about passing 'references by value' and have to use related locutions.

0

Yes but ....

Ruby passes a reference to an object and since everything in ruby is an object, then you could say it's pass by reference.

I don't agree with the postings here claiming it's pass by value, that seems like pedantic, symantic games to me.

However, in effect it "hides" the behaviour because most of the operations ruby provides "out of the box" - for example string operations, produce a copy of the object:

> astringobject = "lowercase"

> bstringobject = astringobject.upcase
> # bstringobject is a new object created by String.upcase

> puts astringobject
lowercase

> puts bstringobject
LOWERCASE

This means that much of the time, the original object is left unchanged giving the appearance that ruby is "pass by value".

Of course when designing your own classes, an understanding of the details of this behaviour is important for both functional behaviour, memory efficiency and performance.

Tomm P
  • 761
  • 1
  • 8
  • 19