I have a class where I was using the Array#shift
instance method on an instance variable. I thought I made a "copy" of my instance variable but in fact I hadn't and shift
was actually changing the instance variables.
For example, before I would have expected to get ["foo", "bar", "baz"]
both times given the following:
class Foo
attr_reader :arr
def initialize arr
@arr = arr
end
def some_method
foo = arr
foo.shift
end
end
foo = Foo.new %w(foo bar baz)
p foo.arr #=> ["foo", "bar", "baz"]
foo.some_method
p foo.arr #=> ["bar", "baz"]
result:
["foo", "bar", "baz"]
["bar", "baz"]
But as shown my "copy" wasn't really a copy at all. Now, I'm not sure if I should be calling what I want a "copy", "clone", "dup", "deep clone", "deep dup", "frozen clone", etc...
I was really confused about what to search for and found a bunch of crazy attempts to do what seems like "making a copy of an array".
Then I found another answer with literally one line that solved my problem:
class Foo
attr_reader :arr
def initialize arr
@arr = arr
end
def some_method
foo = [].replace arr
foo.shift
end
end
foo = Foo.new %w(foo bar baz)
p foo.arr #=> ["foo", "bar", "baz"]
foo.some_method
p foo.arr #=> ["foo", "bar", "baz"]
output:
["foo", "bar", "baz"]
["foo", "bar", "baz"]
I understand that Array#replace
is an instance method being called on an instance of Array
that happens to be an empty array (so for example foo = ["cats", "and", "dogs"].replace arr
will still work) and it makes sense that I get a "copy" of the instance variable @arr
.
But how is that different than:
foo = arr
foo = arr.clone
foo = arr.dup
foo = arr.deep_clone
Marshal.load # something something
# etc...
Or any of the other crazy combinations of dup
and map
and inject
that I'm seeing on SO?