2

as a way to spice up my C++ programming homework, I've decided to instead of typing the C++ from the book onto my computer, instead reforming it in Ruby. Yes it's a bit silly, but I'm bored.

Anyway, I'm having trouble converting this kind of function to Ruby

void swap(int &a,int &b){
  int c=b;
  b=a;
  a=c
}

What would be the equivalent ruby code inside a function ?

Earlz
  • 62,085
  • 98
  • 303
  • 499

2 Answers2

6

Ruby is strictly pass-by-value. Always. But sometimes those values are poointers.

Here's a couple of links:

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:

  1. 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
  2. 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):

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).

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • It is true in, in the same way that Java and Javascript are pass by value. – Marc-André Lafortune Apr 16 '10 at 05:15
  • @Earlz: this is just a disagreement on terminology between different language communities. objects in Java behave the same way, and they call it pass-by-value – newacct Apr 16 '10 at 05:16
  • Seems to me it'd be better for everyone if we started saying "pass by sharing", or some other term of choice distinct from value and reference, since clearly it's neither. From wikipedia on "call by sharing" (http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing) "For example, in the Java community, they say that Java is pass-by-value, whereas in the Ruby community, they say that Ruby is pass-by-reference, even though the two languages exhibit the same semantics." – Cascabel Apr 16 '10 at 05:43
  • "sometimes those values are poointers" when are they not? – user102008 Aug 11 '11 at 08:38
  • @user102008: `Symbol`s and `Fixnum`s are so-called *immediate values*, i.e. they are passed directly. But actually, I have changed my mind about this, since I wrote the above paragraph: while it is true that in all existing Ruby implementations, they are passed as immediate values, it is also true that they are immutable, which means that you cannot actually *tell* whether they are passed immediately or via a poointer. So, you might just as well say that everything in Ruby is pass-by-sharing, and ignore the special case as an internal performance optimization detail of the Ruby implementation. – Jörg W Mittag Aug 11 '11 at 09:35
1

In Ruby, arguments are passed by value. So the following method will never have any effect:

def doesnt_swap(a, b)
  c = a
  a = b
  b = c
end

On the other hand, mosts objects are references, for examples strings, so you could write

def swap_strings(a, b)
  c = a.dup
  a.replace(b)
  b.replace(c)
end

This would swap the string values of the two arguments.

Integers are immediates, so there is no equivalent to replace; you can't write swap_integers.

Anyways, in Ruby, you swap by writing a, b = b, a

Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
  • 1
    Is there no way of "boxing" integers or anything like that to force it to pass by reference? – Earlz Apr 16 '10 at 04:50
  • @Earlz: If the integers are members of some object, you can swap the values of the object's instance variables. You cannot access local variables in another scope. – Chuck Apr 16 '10 at 04:56
  • @Earlz: well, there is (using a SimpleDelegator), but you'll never ever see that in Ruby. – Marc-André Lafortune Apr 16 '10 at 05:03
  • 2
    I think the terminology you want to use is that strings are "mutable", hence its contents can be altered; whereas number types are "immutable" – newacct Apr 16 '10 at 05:14
  • @newacct: indeed, I rephrased my answer accordingly. – Marc-André Lafortune Apr 16 '10 at 05:17
  • 2
    Nothing stops one from passing integers in, e.g., an array; the array being mutable, the function could then replace that integer with a different value. This, however, is seldom optimal design, and it certainly isn't idiomatic Ruby. If a function needs to communicate several values to its caller, it can always return multiple values (`return [line, remaining_elements]`). – Wayne Conrad Apr 16 '10 at 05:30
  • Nothing except the poor performance resulting from creating new objects too many times. But then again, if I need to seriously worry about such things, this might be a hint I need to reconsider my choice of technologies. – rr- Dec 10 '14 at 18:51