# Why this behaviour?

Discussion in 'Ruby' started by Daniele Antani, Jan 9, 2008.

1. ### Daniele AntaniGuest

Hello to all,

i can't understand the follow behaviour:

class Player
attr_accessor :hand
def initialize(hand)
@hand = hand
end
end

def roba(player)
p2 = Player.new(player.hand)
change p2
print "p2 = "
p p2
print "player = "
p player
end

def change(player)
player.hand.push(3)
end

p1 = Player.new([2, 3, 4])
roba p1

__END__

output is:
p2 = #<Player:0xb7c4919c @hand=[2, 3, 4, 3]>
player = #<Player:0xb7c491c4 @hand=[2, 3, 4, 3]>

Why the change affects both objects? I want to copy the first object and
work on the copy without affecting the original.

Thanks
--
Posted via http://www.ruby-forum.com/.

Daniele Antani, Jan 9, 2008

2. ### Jano SvitokGuest

On Jan 9, 2008 3:35 PM, Daniele Antani <> wrote:
> Hello to all,
>
> i can't understand the follow behaviour:
>
> class Player
> attr_accessor :hand
> def initialize(hand)

This copies reference to the array, use #dup to create a copy (note
that it's not recursive):
- @hand = hand
+ @hand = hand.dup

> end
> end
>
> def roba(player)
> p2 = Player.new(player.hand)
> change p2
> print "p2 = "
> p p2
> print "player = "
> p player
> end
>
> def change(player)
> player.hand.push(3)
> end
>
>
> p1 = Player.new([2, 3, 4])
> roba p1
>
> __END__
>
> output is:
> p2 = #<Player:0xb7c4919c @hand=[2, 3, 4, 3]>
> player = #<Player:0xb7c491c4 @hand=[2, 3, 4, 3]>
>
>
> Why the change affects both objects? I want to copy the first object and
> work on the copy without affecting the original.
>
> Thanks
> --
> Posted via http://www.ruby-forum.com/.
>
>

Jano Svitok, Jan 9, 2008

3. ### Karl von LaudermannGuest

On Jan 9, 9:35 am, Daniele Antani <> wrote:
> Hello to all,
>
> i can't understand the follow behaviour:
>
> class Player
> attr_accessor :hand
> def initialize(hand)
> @hand = hand
> end
> end
> Why the change affects both objects? I want to copy the first object and
> work on the copy without affecting the original.

Both Player objects contain a reference to the same array. What you
want is this:

class Player
attr_accessor :hand
def initialize(hand)
@hand = hand.clone
end
end

Karl von Laudermann, Jan 9, 2008
4. ### Sebastian HungereckerGuest

Daniele Antani wrote:
> I want to copy the first object and
> work on the copy without affecting the original.

Then do that. dup copies an object. Assignment does *not* copy.

HTH,
Sebastian
--
Jabber:
ICQ: 205544826

Sebastian Hungerecker, Jan 9, 2008
5. ### Jesús Gabriel y GalánGuest

On Jan 9, 2008 3:35 PM, Daniele Antani <> wrote:
> Hello to all,
>
> i can't understand the follow behaviour:
>
> class Player
> attr_accessor :hand
> def initialize(hand)
> @hand = hand
> end
> end
>
> def roba(player)
> p2 = Player.new(player.hand)
> change p2
> print "p2 = "
> p p2
> print "player = "
> p player
> end
>
> def change(player)
> player.hand.push(3)
> end
>
>
> p1 = Player.new([2, 3, 4])
> roba p1
>
> __END__
>
> output is:
> p2 = #<Player:0xb7c4919c @hand=[2, 3, 4, 3]>
> player = #<Player:0xb7c491c4 @hand=[2, 3, 4, 3]>
>
>
> Why the change affects both objects?

Because both players point to the same array object
in their @hand variables. To see what I mean try this:

irb(main):028:0> p = Player.new([2,3,4])
=> #<Player:0xb7c16044 @hand=[2, 3, 4]>
irb(main):029:0> p.hand.object_id
=> -606031798
irb(main):030:0> p2 = Player.new(p.hand)
=> #<Player:0xb7c00b40 @hand=[2, 3, 4]>
irb(main):031:0> p2.hand.object_id
=> -606031798

So when you push an element in the array,
both hands point to the same array and you see
the change in both player objects.

> I want to copy the first object and
> work on the copy without affecting the original.

You can dup the array in the initialize:

def initialize(hand)
@hand = hand.dup
end

Hope this helps,

Jesus.

Jesús Gabriel y Galán, Jan 9, 2008