Calling by Reference - Two Questions

M

Mike Stephens

I know I'm not the first person to get stumped by how to get Ruby to
change an object in a method.

I want to do:

method a1 or a1.method

I can do

a1 = method a1

but amongst other things that creates a new object.

a1 = [1,2]
puts " #{a1} # 12

def myswap1(a2)
a3 = [0,0]
a3[0] = a2[1]
a3[1] = a2[0]
a2 = a3
end

myswap1 a1
puts " #{a1} " # 12

Ruby passes in a1, so at the start of the method a2 is the same
reference as a1. However when I assign a1 = a3, a1 becomes a different
reference and disappears when the method terminates.

So my first question is why won't Ruby let me do this:

a1 = [1,2]

public
def myswap5
a3 = [0,0]
a3[0] = self[1]
a3[1] = self[0]
self = a3
end

a1.myswap5 # gives error message: Can't change the value of self

My second question is from this:

a1 = [1,2]

def myswap6(a2)
a2.reverse!
end

myswap6 a1
puts " #{a1}" #21

What magic is reverse! using, and how can I avail myself of it?
 
A

Abinoam Jr.

I think I didn't understand your question correctly, sorry (My english
skills are not so good).
But, see bellow and tell me if this is what you want.

def myswap(arr)
[arr[1], arr[0]]
end

def myswap!(arr)
arr[0], arr[1] =3D arr[1], arr[0]
end

def myswap2!(arr)
arr[0], arr[1] =3D arr[1], arr[0]
arr
end

a =3D [2, 5]

myswap a # =3D> [5,2] (new object)
myswap! a # =3D> [5,2] (a now is changed; note that the returned array is n=
ot a)
myswap2! a # =3D> [5,2] (a now is changed; the returned array is "a"
(same object_id) )

Abinoam Jr.
 
M

Mike Stephens

Well, that is bizarre.

In 1.8.6 I get:

def myswap(arr)
[arr[1], arr[0]]
end

def myswap!(arr)
arr[0], arr[1] = arr[1], arr[0]
end

def myswap2!(arr)
arr[0], arr[1] = arr[1], arr[0]
arr
end

a = [2, 5]
puts " start #{a} #{a.object_id} " #start 25 27431650

myswap a # => [5,2] (new object)
puts " myswap #{a} #{a.object_id} " myswap 25 27431650

myswap! a # => [5,2] (a now is changed; note that the returned array
isnot a)
puts " myswap! #{a} #{a.object_id} " myswap! 52 27431650

myswap2! a
puts " myswap2! #{a} #{a.object_id} " myswap2! 25 27431650


I have no idea why myswap! works and myswap2! doesn't.
 
G

Gary Wright

Well, that is bizarre.
=20
In 1.8.6 I get:
=20
def myswap(arr)
[arr[1], arr[0]]
end
=20
def myswap!(arr)
arr[0], arr[1] =3D arr[1], arr[0]
end
=20
def myswap2!(arr)
arr[0], arr[1] =3D arr[1], arr[0]
arr
end
=20
a =3D [2, 5]
puts " start #{a} #{a.object_id} " #start 25 27431650
=20
myswap a # =3D> [5,2] (new object)
puts " myswap #{a} #{a.object_id} " myswap 25 27431650
=20
myswap! a # =3D> [5,2] (a now is changed; note that the returned array
isnot a)
puts " myswap! #{a} #{a.object_id} " myswap! 52 27431650
=20
myswap2! a
puts " myswap2! #{a} #{a.object_id} " myswap2! 25 27431650
=20
=20
I have no idea why myswap! works and myswap2! doesn't.


They both work. Remember that myswap!(a) changed the array to [5,2] and =
so myswap2! changes it back to [2,5].

Gary Wright=
 
A

Abinoam Jr.

They both work. =A0Remember that myswap!(a) changed the array to [5,2] an=
d so myswap2! changes it back to [2,5].
Gary Wright

Exactly.

One more thing, in the first try with myswap the returned value is
being ignored.
myswap a # =3D> [5,2] (new object)
puts " myswap #{a} #{a.object_id} " myswap 25 27431650

Assign the returned value to a variable.

b =3D myswap a

Now b is the "swap" of a and they have different object_ids.

Abinoam Jr.
 
M

Mike Stephens

Interesting.

I'm trying to see the pattern here. Ruby doesn't change arr's object if
it is refering to elements already present. However (I can only test
this in tryruby at this moment) it does change the object and therefore
lose the change if I do:

def myswapx(arr)
arr[2] = 3
end

So what's the rule?
 
J

Jesús Gabriel y Galán

Interesting.

I'm trying to see the pattern here. Ruby doesn't change arr's object if
it is refering to elements already present. However (I can only test
this in tryruby at this moment) it does change the object and therefore
lose the change if I do:

def myswapx(arr)
=A0arr[2] =3D 3
end

So what's the rule?

The rule is how Ruby handles variables and objects. A local variable
holds a reference to an object. When you call a method passing that
variable, the reference gets copied into a new local variable, that is
only accessible in the method:

def m variable_local_to_method_m

end

a =3D [1,2,3]
m(a)

Here, variable_local_to_method_m and a reference the same object, the
array [1,2,3], but within the method you cannot make a reference a
different object, because what gets passed to the method is a copy of
the reference.

If the object has mutable method, calling those methods through the
variable_local_to_method_m will result in the object changing its
state, which is obviously visible outside the method, when you access
the object through variable a. For example:

irb(main):001:0> class Item
irb(main):002:1> def initialize
irb(main):003:2> @count =3D 0
irb(main):004:2> end
irb(main):005:1> def increment
irb(main):006:2> @count +=3D 1
irb(main):007:2> end
irb(main):008:1> end
=3D> nil
irb(main):009:0> def m item
irb(main):010:1> item.increment
irb(main):011:1> end
=3D> nil
irb(main):012:0> a =3D Item.new
=3D> #<Item:0xb73f5ab8 @count=3D0>
irb(main):013:0> m a
=3D> 1
irb(main):014:0> a
=3D> #<Item:0xb73f5ab8 @count=3D1>

As you can see, when we call the increment method using the item
variable inside the method m, the object changes its @count instance
variable. Both item and a reference the same object, so after the
method, a still references the same object which has a different state
now.

In your example the array [1,2,3] is the object whose reference is
being passed to methods. An array is a mutable object, and so when you
call a method like []=3D you are changing the object that is referenced
by the outside variable a.

Jesus.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top