Ruby is strictly pass-by-value. Always. But sometimes those values are poointers.
Here's a couple of links:
- Java is Pass-by-Value, Dammit! (Scott "JavaDude" Stanchfield)
- Parameter passing in Java (Jon Skeet)
- Does Java pass by reference?
- Java, pass-by-value, reference variables
Note that while all of these say "Java", they should really say "Smalltalk and its descendants", which includes Java, Ruby and a ton of other languages.
I think most of the confusion stems from two problems:
- Ruby passes references by value. But the word "reference" in that sentence is not the same as the word "reference" in "pass-by-reference". Maybe it is clearer when we disambiguate: let's replace "pass-by-reference" with "pass-by-variable" and "reference" with "pointer" (note that these are "good" well-behaved poointers, not the "bad" ones from C):
- Fortran is pass-by-variable
- Ruby is pass-by-value and the values it passes are mostly poointers
- The references (poointers) that Ruby passes point to mutable objects. Therefore, while you cannot change the reference, you can mutate the objects that the reference points to. The problem here is that Ruby (like most imperative object-oriented languages) confuses the concepts of identity, state and value. You can learn more about that problem and how to fix it here (Note that while they say "Clojure", the concepts that are presented are universal and could be applied equally well to OO):
- Persistent Data Structures and Managed References - Clojure's Approach to Identity and State - Rich Hickey - QCon London 2009
- Are We There Yet? - A deconstruction of object-oriented time - Rich Hickey - JVM Language Summit
BTW: I deliberately misspelt "poointers" with an OO for object-orientation to make it clear that I am not talking about raw memory addresses, I am talking about opaque references to objects (and for obvious reasons I do not want to use the word "reference"; if you know a better word that is neither "pointer" nor "reference", I'd love to hear it).