Is Ruby pass-by-value or pass-by-reference?

I am mainly a java developer. I have been working in ruby ​​for about a year. Unlike java, Ruby is a purely object-oriented programming language. There is doubt. Is this passing by value or passing by reference? Java works like a pass-by-value: "When passing primitives, I see that the value is duplicated and passed to the method. But incase of Objects, the link is duplicated and passed to the method. The link contains the location of the object on the heap. When the method is called, only the location of the object is transferred, therefore, no duplicate objects are created. The same object is modified. "

But when I tried the below ruby ​​code snippet, I got the same results as I got in Java: "Numbers work like a primitive (like in Java) while calling a method while the array works like perfect links like in Java" . Now I am confused. If everything in ruby ​​is an object, then why is the number of objects duplicated during a method call?

class A def meth1(a) a = a+5 puts "a inside meth1---#{a}" end def meth2(array) array.pop puts "array inside meth2---#{array}" end end obj1 = A.new aa=5 obj1.meth1(aa) puts "aa-----#{aa}" arr = [3,4,5] obj1.meth2(arr) puts "arr---#{arr}" 

Results:

inside met1 --- 10

aa ----- 5

array inside meth2 --- 34

arr --- 34

+4
source share
4 answers

Ruby uses pass-by-value, or rather, a special case of pass-by-value, where the passed value is always a pointer. This special case is also sometimes called call sharing, call sharing or shame.

This is the same convention used by Java (for objects), C # (default for reference types), Smalltalk, Python, ECMAScript / JavaScript, and more or less every object-oriented language ever created.

Note: for all existing implementations, Ruby Symbol s, Fixnum and Float actually passed directly by value, and not with an intermediate pointer. However, since these three are immutable, in this case there is no observed behavioral difference between passing by value and sharing a call over an object, so you can greatly simplify your mental model by simply considering everything as a split call sign. Just interpret these three special cases as internal compiler optimizations that you don't need to worry about.

Here is a simple example that you can follow to define an agreement on passing arguments to Ruby (or any other language after translating it):

 def is_ruby_pass_by_value?(foo) foo.replace('More precisely, it is call-by-object-sharing!') foo = 'No, Ruby is pass-by-reference.' return nil end bar = 'Yes, of course, Ruby *is* pass-by-value!' is_ruby_pass_by_value?(bar) p bar # 'More precisely, it is call-by-object-sharing!' 
+18
source

See below, Object_id will answer all your questions:

 class A def meth1(a) p a.object_id #=> 11 a = a+5 # you passed a reference to the object `5`,but by `+` you created a new object `10`. p a.object_id #=> 21 end def meth2(array) p array.object_id #=> 6919920 array.pop p array.object_id #=> 6919920 end end obj1 = A.new aa=5 obj1.meth1(aa) p aa.object_id #=> 11 arr = [3,4,5] obj1.meth2(arr) p arr.object_id #=> 6919920 

So, it is true that in your code, object reference is passed, by value . Note + create a new object, so the reference to 10 made locally for the method in which it was changed.

+6
source

It is passed by value in both cases, for example Java. The difference is that both elements in your tests are objects, while in Java one of them would be primitive and the other an object. But whether something is primitive or the object is not related to passing compared to passing by reference. Passing by value compared to passing by reference is related to the fact that the called method can execute with variables in the calling context that are passed to it.

Let both languages ​​and objects be ignored, and just look at what pass-by-value and pass-by-reference mean. I will use pseudocode in the undefined syntax B / Java / C / C ++ / C # / D:

 Function Foo(arg) { arg = 6 } declare variable a a = 5 Foo(a) output a 

If a is passed by value, the output is 5. If a is passed by reference (the variable reference a is pointed to Foo ), the result is 6, because Foo works with a using the variable reference.

Please note that there is a significant difference between your two tests.

In your first test, you assign a completely new value to a :

 a = a + 5 

You do not change the version of a passed to this method, you use this value to assign a new value to a .

In the second test, you simply modify the array :

 array.pop 

Not for example:

 array = ...put something entirely new in `array`... 

In your test, since you just change what the object reference points to, rather than changing the link, you certainly see this modification. But if you assigned a new array , this change would not be obvious in the calling context.

+6
source

Ruby, like Java, is pass-by-value ... With a trick: the passed "value" (in the case of objects) refers to a pointer link, so any modification of the value of an object must be performed internally by this method on the same object as in defiant context.

Now, for your examples, you need to know that FixNum are “immediate” objects that have only meaning - the link in this case is not a pointer, but the object itself (it is still an object, with methods, etc., therefore this is not a primitive, as in Java).

In your example, you are actually reassigning the new object to the pointer "a", which in all cases will not be displayed anywhere, just like:

 my_name = "John" my_name = "Robert" 

actually assigns a new pointer to the link. Since there is no way to change the FixNum value in Ruby, this is not the case that might work.

The situation with the array is what you are likely to expect: you have an object, you are modifying the state of the object and returning the changed state.

+4
source

Source: https://habr.com/ru/post/1479876/


All Articles