Skip to content

Instantly share code, notes, and snippets.

@flarnie
Created July 25, 2013 14:24
Show Gist options
  • Save flarnie/6080184 to your computer and use it in GitHub Desktop.
Save flarnie/6080184 to your computer and use it in GitHub Desktop.
A demo of Ruby passing by reference and the way it can mess up duplication of nested objects.
#the outer object
class Pen
attr_accessor :animals
def initialize
# Animals can be in
# one of three rows
# in the pen.
@animals = [[],
[],
[]]
end
def add_animal(animal, row)
@animals[row] << animal
end
end
#the inner object type
class Animal
attr_reader :name, :sounds
def initialize(name)
@name = name
@sounds = []
end
def new_sound(sound)
@sounds << sound
end
def to_s
str = " #{name}:"
sounds.each { |sound| str += " #{sound}" }
str
end
end
#make our first pen with cows that go "moo"
moo_pen = Pen.new
moo_cow = Animal.new("cow")
moo_cow.new_sound("moo")
moo_pen.add_animal(moo_cow, 0)
# Now we've added a cow to row 1 of our pen.
puts moo_pen.animals
#returns
# cow: moo
# What if we want to copy moo_pen and
# teach all the copy_cows to talk
# without making the moo_pen cows
# any smarter?
# FIRST we need a dup method
# which we will first do
# the WRONG WAY:
# Make a 'deep dup' method which
# works on nested arrays.
module MakeCopies
def deep_dup(array)
new_arr = []
array.each do |item|
if item.is_a?(Array)
new_arr << item.dup
else
new_arr << item
end
end
new_arr
end
end
# Then use it to dup the animals array.
class Pen
include MakeCopies
def dup
new_pen = Pen.new
#attempt to 'deep-dup' the animals
old_animals = animals
new_animals = deep_dup(old_animals)
new_pen.animals = new_animals
new_pen
end
end
# Finally, let's copy our moo_pen
# and teach the cows to talk.
experimental_pen = moo_pen.dup
experimental_pen.animals.each do |row|
row.each do |animal|
# Teach it to talk
animal.new_sound("Hello")
end
end
# Test the copy pen to see how it's animals sound:
puts experimental_pen.animals
# Returns
# cow: moo Hello
# BUT look at our original moo_pen:
puts moo_pen.animals
# Returns
# cow: moo Hello
# Do you see what happened?
# Both pens have a talking cow
# Because it is still the same cow.
# Ruby is referencing the same place
# in memory, which was altered
# when we added the sound "Hello".
# I'll post again about the possible solutions
# to properly duping nested objects, which
# my partner and I did eventually figure out.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment