I got a lot of comments for the previous article, that was explaining how Ruby passes by value, just like Java does.
I thought that showing a simple example implemented in C++, Java and Ruby will clarify the idea. In the following lines, we will make swap functionality in 3 languages, and demonstrate that neither Java nor Ruby passes by reference.
C++
#include <iostream> using namespace std; class Point { private: double x, y; public: Point(double x, double y) { this->x = x; this->y = y; } void print() { cout << "x = " << x << ", y = " << y << endl; } }; // Parameters are passed by reference void swap(Point &p1, Point &p2) { Point temp = p1; p1 = p2; p2 = temp; } int main() { //initializing the points Point val1(5, 10); Point val2(20, 40); //printing their values cout << "Before Passing By Reference" << endl; val1.print(); val2.print(); //swaping, passing by referecne swap(val1, val2); //printing the values again cout << "After Passing By Reference" << endl; val1.print(); val2.print(); }
Output:
$ ./passcpp Before Passing By Reference x = 5, y = 10 x = 20, y = 40 After Passing By Reference x = 20, y = 40 x = 5, y = 10
Java
class Point { private double x, y; public Point(double x, double y) { this.x = x; this.y = y; } public String toString() { return String.format("x = %.2f , y = %.2f", x, y); } public static void swap(Point p1,Point p2){ Point temp = p1; p1 = p2; p2 = temp; } public static void main(String args[]) { //initializing the points Point var1 = new Point(5, 10); Point var2 = new Point(20, 40); //printing their values System.out.printf("Before Passing\n%s\n%s\n", var1, var2); // //swaping, passing by reference value, aka: pass by value swap(var1,var2); //printing the values again System.out.printf("After Passing\n%s\n%s\n", var1, var2); } }
Output:
$ java Point Before Passing By Reference x = 5.00 , y = 10.00 x = 20.00 , y = 40.00 After Passing By Reference x = 5.00 , y = 10.00 x = 20.00 , y = 40.00
Ruby
class Point def initialize(x,y) @x,@y = x,y end def to_s "x = #{@x} , y = #{@y}" end end def swap(p1,p2) p1,p2 = p2,p1 end #initializing the points var1 = Point.new(5,10) var2 = Point.new(20,40) #printing their values puts "Before Passing" , var1, var2 # //swaping, passing by reference value, aka: pass by value swap var1,var2 #printing the values again puts "After Passing" , var1, var2
Output:
$ ruby passruby.rb Before Passing By Reference x = 5 , y = 10 x = 20 , y = 40 After Passing By Reference x = 5 , y = 10 x = 20 , y = 40
As you can notice, in c++ example, passing by reference, will do the swap successfully.
Java and Ruby both don’t pass by reference, instead they pass a copy of the reference, which is a value finally, and so the swap fails, as swapping the copies doesn’t swap the original passed objects.
Please note also that in Java, primitive types are passed by their values directly and no need for any kind of references copies.The same case applies for Ruby, with immediate types(int, char…).
According to the previous 2 facts, we conclude that neither Java nor Ruby passes by reference, instead, both pass by value.
I think that fact that Ruby MRI is using C means they can’t use references, and so they are using pointers, and that explains why swap fails.
I hope that the idea is clear now.
Ruby, pass by value or by reference? - Khaled alHabache’s official blog | April 22nd, 2009 at 12:24 am #
[...] C++ passes by reference, Java and Ruby don’t I got a lot of comments for the previous article, that was explaining how Ruby passes by value, [...]
Carl McDade | April 22nd, 2009 at 2:28 am #
LOL, Erlang does not pass at all!
jds | April 22nd, 2009 at 4:46 am #
@Carl McDade: can you elaborate on your comment about Erlang?
Carl McDade | April 22nd, 2009 at 5:27 am #
I guess it’s a matter of semantics but since Erlang variables are immutable you are not passing its value or a copy or referring to its value. You are “using” the variable just as you would in a mathematical sense. The variable and value it is set at become one and the same.
Shadowfiend | April 22nd, 2009 at 9:08 am #
That is a silly statement. Erlang certainly passes variables. The variable itself may be immutable, but the variable values need still be taken from one place to another, especially when sending messages that need to be placed in a mailbox for another process to consume.
Re: MRI — you can use references in C just fine, you just have to be a little more explicit about them because you use them as pointers. C++ references are basically a thin wrapper around pointers so that you need not worry about dereferencing and null pointers in certain situations. Ruby probably doesn’t use pass by reference because very few OO languages work that way. Most OO languages, including the likes of Javascript, Smalltalk, Java, and others, pass by reference-values (if you will). I suspect this is because functionality such as the above swap function is relatively rare, and the behavior may be unexpected and bug-inducing if it is the default behavior. The other behavior is sufficient for most cases, so they don’t bother introducing extra syntax and semantics for C++-style pass-by-reference.
Carl McDade | April 22nd, 2009 at 9:43 am #
Of course. I was being a little facetious in my first statement. I was reading the code though and was thinking more inlines of the argument “by value” “by reference” being a mute one when it comes to Erlang because of its immutable variables.
Maybe not exactly on topic but interesting.
Carl McDade | April 22nd, 2009 at 9:49 am #
Hmm, using blockquote jumbled the html a bit.
Kadom | April 22nd, 2009 at 10:22 am #
try this in ruby …
def swap a, b
a1, b1 = a.dup, b.dup
a.replace b1
b.replace a1
return [ b, a ]
end
a = “4″
b = “5″
swap a, b
puts a
puts b
khelll | April 22nd, 2009 at 10:32 am #
@kadom, you could do it in easier way, but that is not in our discussion:
Kadom | April 22nd, 2009 at 10:46 am #
actually simpler than that would be a, b = b, a. But if you look at the example i posted you can remove the return and it will still work. The return is not doing the assignment.
ruby does pass by reference, but not the way we are used to it in C and C++. for all intensive purposes it is by value, but look at the code above. If it was by value, then how did the original a, and b that i passed in get changed? Remove the return if you like and run the code. It will be more interesting if you remove the quotes and try it with an actual FixNum, but that is another story.
a.replace and b.replace are happening in the scope of the swap function, and the outer scope a and b are changed.
Tim
Kadom | April 22nd, 2009 at 10:49 am #
try
4
def swap a, b
a1, b1 = a.dup, b.dup
a.replace b1
b.replace a1
end
a = “4″
b = “5″
swap a, b
puts a
puts b
khelll | April 22nd, 2009 at 11:26 am #
@kadom, being able to work on the object doesn’t mean that this is called pass-by-reference,
Ruby and Java passes the value of copied reference, instead of the reference itself.
This is called pass by reference value, or simply pass by value.
Kadom | April 22nd, 2009 at 11:34 am #
then strictly speaking C is pass by value as well. just because i pass the value of a pointer to a thing, does not change that. The terminology of pass by reference means exactly that, you are passing the value of a reference. so in C i can pass a pointer to something, and then since i know where that thing is in memory, i can manipulate it. I can pass a pointer to a pointer if i want to manipulate the pointer. But I always pass a value.
so the question becomes, what was your intent? You can clearly write a ruby swap which changes the content of the passed argument. as you said this is by value reference. Can you elaborate on your distinction?
Kadom | April 22nd, 2009 at 12:05 pm #
For me if i pass a variable and that variable changes in a method call, then i pass by reference. In ruby i pass an object reference if i am passing an object. I do not need to demarcate this in any special manner. In this simpler contrived example, I think you would see the point of that.
http://pastie.org/454984
boo is passed bar and bar is assigned and unchanged. That is what we expect if we pass a copy on the stack of bar. do whatever you like to bar, the calling bar will not change.
in foo however we use the same parameter that we used in boo. We don’t do anything special to it, and when we replace the content of bar, we see that it is changed when we return. This means we had a handle to bar, or a value reference. I do not consider this the same as pass by value since I did not have to change the invocation to get the same behavior. in C if I have *p = 5 and p is some address, if i pass *p to the method i will not change the value of what p is pointing to. I need to pass p, and only then can i modify the content. Thats why I think there is a distinction between pure pass by value and what ruby does.
khelll | April 22nd, 2009 at 12:54 pm #
@Kadom, this is not true as i said before, this is not called passing by reference, as u r not working on a reference, you are working on a copy of a reference(another pointer), this is called pass by reference value, and it’s totally different.
mike | April 22nd, 2009 at 10:45 pm #
Ruby has two kind of objects : immediate values and references.
As their name suggest, immediate values are passed by value and references are passed by reference.
Immediate values are Fixnum, true, nil, false and Symbol.
http://www.rootr.net/rubyfaq-9.html
http://www.ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html
Anyway, your sample doesn’t demonstrate anything. The swa
mike | April 22nd, 2009 at 10:51 pm #
p method doesn’t do anything because in Ruby, assigning a variable never changes the object itself : it only changes the reference.
Here’s a sample the demonstrate Ruby passes strings by reference (and works with any non immediate value) :
def change(obj)
obj << “bar”
end
a = “foo”
change(a)
p a
Result : “foobar”
You can’t do this with Fixnum or Symbol because they don’t have any method to alter themselves.
khelll | April 23rd, 2009 at 12:51 am #
@ mike, please go back to the previous comments, we discussed ur example many times.
This is called pass by reference value, not by reference.
Osama | April 23rd, 2009 at 1:58 am #
long talk short: ruby and java allow you to influence objects’ attributes and does not allow you to influence the object itself when passed to another method.
those 2 lines with the 3 example you gave on c++, java and ruby are more than enough to demonstrate the idea.
simple, short and direct
khelll | April 23rd, 2009 at 2:21 am #
@ osama, simply, the method is passed another pointer rather than the original one, a copy of it, so whatever u do to this copied pointer, the original one will keep pointing to the same place in memory. so when u modify the object inside a method, this modification will be reflected to the passed argument also, cause both pointers are still pointing to the same place in memory, but when u do Object.new or new Object() in Ruby or Java, this will assign the copied pointer to another place in the memory,and that won’t affect the original pointer, and it will keep pointing to same place in memory.
In c++ and as it passes the same pointer(reference), whatever modification u make on an object will be reflected outside.
This is called pass by reference, while the behavior of Ruby and Java is called : pass by reference value or pass by value.
Osama | April 23rd, 2009 at 3:56 am #
@khell لا تخظ المي يا اخي …
the concept you explained “hardly” in your 2 articles can be found everywhere.
mike | April 23rd, 2009 at 4:37 am #
Ok, this is a definition problem then. Because as a programmer, when I pass an object to a Ruby method, I pass a reference to this object.
I know the internal details, but it still makes sense to me to think (when I write Ruby code) that I pass my objects by reference. I really pass a reference, not the object itself.
It may be better to distinguish different kind of references.
You can hardly call what Ruby does a pass by value. Because (as a Ruby programmer), it’s very different than passing a copy of the object like what would be done if you removed the ‘&’ in your C++ code.
Also, everyone should know that the swap method in your Ruby sample does absolutely nothing (except returning [p2,p1]). So, using such a useless method to demonstrate something looks weird.
David Dollar | April 23rd, 2009 at 8:18 am #
Kadom and mike are correct. The example given in this article of Ruby reference passing is invalid as a,b = b,a does not actually change any values.
Ruby does pass by reference for everything except the immediate value classes foundhere. (see 9.3)
A better example of Ruby reference passing is as follows:
def replacer(a,b)
a.replace b
end
foo = "Foo"
bar = "Bar"
puts foo, bar
replacer foo, bar
puts foo, bar
outputs
Foo
Bar
Bar
Bar
Nitko Nigdje | April 23rd, 2009 at 4:19 pm #
@David
The only thing you demonstrated is that in Ruby strings are mutable. This has nothing with pass by reference and pass by value.
khell is right.
What java calls a ‘reference’ corresponds to C++’s ‘pointer’. Both are primitive types which are passed by value. The only real difference between these two is that with one exception (assigning of null) java lacks pointer arithmetic.
What C++ calls ‘reference’ is actually heap allocated object which holds a pointer to a referenced object. So this is heap allocated “a pointer to a pointer” like object (a handle). Now this object is very special in sense that it has a special syntax and semantics. It doesn’t behave like common object. For example it isn’t created by ‘new’ operator, or applying ‘addressOf’ operator on a reference will return address of object pointed in reference, not the address of reference object (thus it is a “reference”). Etc..
In pass by reference call what is passed is an address of reference object. And because of how assign operator works on references, the swap method actually swapped not the passed references but the values stored in those references, thus giving result that objects were “swapped” in calling code. And because all this happens implicitly, hidden from programmer by layers of compiler generated code, this kind of method call is called pass by reference and it exists only in languages with “real” references like C++.
Craig | April 23rd, 2009 at 4:29 pm #
Java passes by value, always, it’s pretty common knowledge. What you are passing to the function is a reference, it passes that reference by value and the function cannot change what that reference it is passed points to (from the callees perspective).
So nothing ground breaking here, at least not for Java developers.
Artur | April 23rd, 2009 at 10:05 pm #
In C++, if you would pass pointers instead and do
Point temp = *p1;
*p1 = *p2;
*p2 = *temp;
You would get the same effect, but you were passing by value, not by reference.
In java, if you would add some kind of .assignFrom method, you could get the same effect like in C++.
I think that you are confusing passing by reference and having default byte-wise assignement operator.
I think that a lot better example would be to use Point * val1 = new Point(5,10) in C++ (to make it same as java version) and then pass &val1 to method, showing that you can pass references to variables, effectively accessing calling method stack. Currently, you are just replacing contents of the objects, which is perfectly possible in java, just with different call, not ‘=’.
Albert Blaho | April 24th, 2009 at 12:52 am #
In C++, you pass a reference but than, you working with _values_ (the “reference” in C++ is just a pointer that i automatically dereferenced). In Java and Ruby example, you pass a reference as well an in the body, you work with references.
khelll | April 24th, 2009 at 1:42 am #
@Artur, the problem is not in Java’s ‘=’ operator, otherwise I could also have the same result as c++ references if I did this in java instead of simple assignment:
but even doing this won’t affect the passed arguments, which will keep having their original values.
Artur | April 24th, 2009 at 2:27 am #
Equivalent of C++ code in java is
public static void swap(Point p1,Point p2){
Point tmp = new Point(p1);
p1.setLocation(p2);
p2.setLocation(tmp);
}
Only magic part about C++ is that it has automatic byte-wise assignement operator. When you are doing p2=p1 in c++ you are not swapping the references, you are swapping the contents of the objects. Java just lacks operator overloading to achieve the same, nothing to do with value versus reference.
If you think it is not a difference, consider doing this with maps of million elements. According to your logic, it should be instant operation (as you are just swapping the ‘references’) – but in reality, it will copy the entire map around 3 times (not while passing to the method, but while doing = assignment).
You should compare reference to the pointer in C++ versus pointer in java – this would do pure swap.
khelll | April 24th, 2009 at 3:17 am #
@ Artur, what you are saying regarding values is true. However I’m not discussing swapping references, you can even do:
And you will notice that the references are the same, just the values are swapped.
I’m just saying that(and if you notice the comment and java example just before your last comment), even if u made new values, the passed arguments won’t change cause what is passed is the value of copied reference, not the reference itself.
I hope the idea is clear now.
khelll | April 24th, 2009 at 4:22 am #
I just was reading my rss feed and found this post, seriously speaking, i hope it will help you all to get what i was trying to do in 2 consequent posts.
Good luck
PeterReilly | April 24th, 2009 at 2:07 pm #
two words : copy constructor
Samuel Gyger | April 24th, 2009 at 10:20 pm #
Thank you for this information. I remember this with the following idea.
C++
void swap(int* p1, int* p2){
int* temp;
temp = p1;
p1 = p2;
p2 = temp;
}
int i1 =10, i2 = 20;
int* p1,p2;
p1= &i1; p2 = &i2;
swap(p1,p2);
You could try this, this would not swap the pointers in the outer code, because the pointers are local copies in the swap function.
Samuel Gyger | April 24th, 2009 at 10:20 pm #
Oh a small mistake, there must be a star in front of p2.
Anthony Williams | May 7th, 2009 at 7:11 am #
Just because similar-looking code has different semantics in C++ and Java doesn’t mean that “C++ passes by reference but Java doesn’t”.
Java passes by reference because if you modify the properties of the passed element then the original is modified, as can be seen if you define swap as so:
public static void swap(Point p1,Point p2){
double tempx = p1.x;
double tempy = p1.y;
p1.x = p2.x;
p1.y = p2.y;
p2.x = tempx;
p2.y = tempy;
}
If you pass by value in C++ you cannot modify the original.
Object references in Java behave like pointers in C++, so you can assign the references around as much as you like (which is what your swap does) without affecting the referenced values. The difference with C++ is that C++ references (rather than pointers) cannot be reassigned, so assignment affects the referenced object rather than changing the reference.
Video Technology | May 28th, 2009 at 12:56 am #
Wow! Thank you! I always wanted to write in my site something like that. Can I take part of your post to my blog?
Valera10 | May 8th, 2010 at 3:36 am #
итальянские рецепты