Object Assignment and Pointers

I got a little confused about the purpose of objects and pointers in Ruby and encoded this snippet to check my assumptions.

class Foo attr_accessor :one, :two def initialize(one, two) @one = one @two = two end end bar = Foo.new(1, 2) beans = bar puts bar puts beans beans.one = 2 puts bar puts beans puts beans.one puts bar.one 

I assumed that when I assigned bar to beans, it will create a copy of the object, and the modification will not affect the other. Alas, the conclusion shows the opposite.

 ^_^[jergason:~]$ ruby test.rb #<Foo:0x100155c60> #<Foo:0x100155c60> #<Foo:0x100155c60> #<Foo:0x100155c60> 2 2 

I believe that the numbers have something to do with the address of the object, and they are the same for beans and for bar, and when I change the beans, the line also changes, which is not something I expected. It looks like I'm only creating a pointer to an object, not a copy of it. What do I need to do to copy an object on assignment instead of creating a pointer?

Tests with the Array class also show strange behavior.

 foo = [0, 1, 2, 3, 4, 5] baz = foo puts "foo is #{foo}" puts "baz is #{baz}" foo.pop puts "foo is #{foo}" puts "baz is #{baz}" foo += ["a hill of beans is a wonderful thing"] puts "foo is #{foo}" puts "baz is #{baz}" 

This leads to the following result:

 foo is 012345 baz is 012345 foo is 01234 baz is 01234 foo is 01234a hill of beans is a wonderful thing baz is 01234 

It blows my mind. Calling pop on foo also affects baz, so it is not a copy, but concatenating something on foo only affects foo, not baz. So when do I deal with the original object, and when do I deal with a copy? In my own classes, how can I make sure assignment copies and doesn't make pointers? Help this confused guy.

+6
object variable-assignment ruby copy
source share
4 answers

There are many questions in this question. The main thing to know is that assignment never makes a copy in ruby, but methods often return new objects instead of modifying existing objects . For immutable objects such as Fixnums, you can ignore this, but for objects such as arrays or Foo instances, to make a copy, you must do bar.dup .

As for the array example, foo += not combined into the array stored in foo , to do this you would do foo.concat(['a']) . Instead, it creates a new array and assigns it foo . The documentation for the Array class indicates which methods mutate the array in place and which return a new array.

+11
source share

+ and - in Array each returns new arrays filled with the corresponding contents, so foo += [...] does not affect baz is normal. Try the << operator on foo , and the result will be baz , seeing the same change.

I'm not sure how Ruby handles another thing internally, but you can try using one.clone and two.clone in Foo#initialize .

+3
source share

You never deal with a copy. This is the same object in memory, but you simply declare 2 references to it: in the first example: bar and beans point to the same object in memory; and in your second example: foo and baz first point to the same array in memory.

Look at 2 drawings / drawings on the Java tutorial page, which explains the mechanism (it is the same as in Ruby), and only those 2 images that cost more than any explanation in words: http://docs.oracle.com/ javase / tutorial / java / javaOO / objectcreation.html

+2
source share

Basically, a ruby ​​uses a link pointer, so when you change one thing, it also works.

0
source share

All Articles