18

I don't understand why they say Ruby passes all parameters by value and at the same time the following code proves the opposite:

class MyClass1
  @var1 = 123

  def get1
    @var1
  end

  def set1=value
    @var1 = value
  end
end

c1 = MyClass1.new
c1.set1 = 444
p c1.get1 # 444

def test1 mc
  mc.set1 = 999
end

test1 c1
p c1.get1 # 999

If it were by value, it would print out 444, not 999.

Community
  • 1
  • 1
Incerteza
  • 32,326
  • 47
  • 154
  • 261

1 Answers1

73

This question confuses people because there is a thing called a reference type and there is a thing called pass-by-reference, but they don't actually have all that much to do with each other.

References and values and values that are references: A (sorta) brief overview

In a pass-by-reference scenario, the parameters of a function are references to the variables that were passed into the function, and modifying the parameters modifies the original variables. This is not what Ruby is. For example, let's look at the following code:

def inc(val)
  val += 1
end

a = 1
inc a
puts a

If Ruby were a pass-by-reference language, this program would print 2, because the val += 1 in inc would increment the value of a. But that isn't what happens. The variable val is not a reference to the variable a — it's an independent variable that is given the same value.

"But wait!" you say. "What if we were dealing with objects? Surely object variables are passed by reference, right?"

Nope.

def change_string(str)
  str << " I can insult you all you want"
  str << " because you'll never see this"
  str << " because I'm going to replace the whole string!"
  str << " Haha you smell bad!"
  str = "What? I didn't say anything." # I'm so sneaky
end

be_nice_to_me = "hello"
change_string(be_nice_to_me)
puts be_nice_to_me

If Ruby were pass-by-reference, you'd never see how mean the change_string method is, because the str = "What, I didn't say anything." would totally replace the value of be_nice_to_me with the string "What? I didn't say anything." But in fact change_string's sins are laid bare for all to see. How is this possible if Ruby doesn't pass by reference?

Well, remember those reference types I talked about earlier? Well, that's what objects are in Ruby. A reference type is a type whose value is a reference to something else. In this case, the variable's value is a reference to the string "hello". When you pass the string, the variable's value — which is a reference — is copied into the variable str. So now they both hold references to the same object, but str is not a reference to be_nice_to_me. So when you modify the object, those changes show up because they're both referring to the same object. But when you modify one variable, the other doesn't see it because neither variable is a reference to the other.

So is Ruby pass-by-reference or pass-by-value? It's pass-by-value, but all the values are references.

Community
  • 1
  • 1
Chuck
  • 234,037
  • 30
  • 302
  • 389
  • 5
    Someone has to say it so I'll do it: `1` is an object (but an immutable one). But yeah, the terminology is a terrible mess of confusion. – mu is too short Apr 03 '14 at 04:46
  • 1
    @muistooshort Agreed 100%. It's funny that the same example Chuck uses here to show Ruby is (his definition of) pass by value, I would use to show that Ruby is (my definition of) pass by reference. I'm going to avoid making blanket statements about pass by value/reference in Ruby in the future, it seems to confuse people more. – Terrance Kennedy Apr 03 '14 at 05:08
  • 2
    @TerranceKennedy: Yeah, and I totally get why you would call it that. Your definition of "pass-by-reference" is way more relevant to the way people program in the real world. But unfortunately we're stuck with half a century of computer science literature and an entire educational system that still uses the old definition, so I think it's important to let people know "If you read the term 'pass-by-reference,' it probably isn't talking about Ruby." – Chuck Apr 03 '14 at 05:53
  • 1
    C# has reference and value types, and pass-by-value and pass-by-reference semantics. If you try out the four combinations, you can easily see that those concepts are completely orthogonal: http://stackoverflow.com/a/12438174/2988 – Jörg W Mittag Apr 03 '14 at 11:48
  • So basically, *reference types* are **pointers**, right? – asymmetric Jul 26 '14 at 12:13
  • @muistooshort, what do you mean by "immutable", what makes it immutable? – Incerteza Dec 02 '14 at 14:48
  • @AlexanderSupertramp: `Fixnum` has no methods that change the receiver. Strings, OTOH, are mutable because you can say things like `s.gsub!(...)` to change the content of a string. – mu is too short Dec 02 '14 at 18:49
  • Why in the first example, does the value of `a` not change? If it is pass by reference value, then doesn't the parameter in the function `inc` refer to the same object? – dhaliman Jul 10 '17 at 04:22
  • @dhaliman: Yes, it refers to the same object — but then you reassign it to refer to a different object on the first and only line of the function. `+=` does not mutate the Fixnum. – Chuck Jul 10 '17 at 16:57