stevenspiel
stevenspiel

Reputation: 5999

inheriting and copying class variables

This is a contrived example to emulate what is going on in another project. I'm sure I'm just misunderstanding some basic function of classes, but I don't know where to look to find the answer.

If I set an instance variable @empty = [] in the parent class, then I want to use the original instance variable, as well as a variation of the instance variable in a child class, I'm getting an issue where the original instance variable is no longer accessible in its original form.

class Parent
  def initialize
    @empty = []
  end

  def fill
    @empty << "foo" #interestingly, changing the << to = fixes it, but that's not a possibility on my project
  end
end

class Child < Parent
  def initialize
    super
    @should_still_be_empty = @empty #trying to "make a copy" of the original
  end

  def show_original_variable
    @should_still_be_empty
  end

end

child = Child.new
child.fill #=> ["foo"], which is what it should return
child.show_original_variable #=> ["foo"], I want it to return []


UPDATE:

After playing around a little more, I noticed that this happens within the same classes, as well. Why?

class Child 
  def initialize
    @original_empty = []
    @copy_of_empty = @original_empty
  end

  def fill
    @copy_of_empty << "foo"
  end

  def show_empty
    @original_original_variable
  end

end

child = Child.new
child.fill #=> ["foo"]
child.show_original_variable #=> ["foo"], but I want it to be empty

Upvotes: 1

Views: 60

Answers (2)

FMc
FMc

Reputation: 42411

You question has nothing in particular to do with classes or inheritance. Rather, it deals with more basic issues related to assignment and mutation.

xs = [11,22,33]
ys = xs           # Both variables hold a reference to the same data.

zs = xs.dup       # But zs has a copy (at least a shallow copy).

xs << 44          # If we *mutate* xs, ys changes also.

p xs              # [11, 22, 33, 44]
p ys              # [11, 22, 33, 44]
p zs              # [11, 22, 33]

xs = [4,5,6]      # If we *assign* to xs, ys won't be affected.

p xs              # [4,5,6]
p ys              # [11, 22, 33, 44]

The same behaviors would be observed even if the xs array started out empty (as in your code), but it's a little easier to illustrate with data values present.

If you want @should_still_be_empty to have an independent copy of the underlying data values, you need to do something along these lines:

@should_still_be_empty = @empty.dup

Upvotes: 1

Leo Correa
Leo Correa

Reputation: 19789

Doing @copy = @original stores the reference to the original object in the @copy instance variable.

Using Object#dup will create a shallow copy of the object you're assigning and store it in the instance variable.

class Child 
  def initialize
    @original_empty = []
    @copy_of_empty = @original_empty.dup
  end

  def fill
    @copy_of_empty << "foo"
  end

  def show_empty
    @original_empty
  end

end

child = Child.new
child.fill
#=> ["foo"]
child.show_empty
#=> []

Upvotes: 1

Related Questions