Search code examples
rubymarshallingdeep-copy

Cloning in Ruby via Marshaling not Working


I am self-teaching Ruby for one of my classes and cannot wrap my head around a bug that I've encountered. Note: I am not asking anyone to do my project for me; just wondered if anyone could give me insight on this

The gist:

  • There exists a Set class, which has an array of Subscriber elements
  • The Subscriber class reads in a .csv file and pushes new Subscriber objects to the subscriber array of a Set object
  • I am trying to find the union and intersection of any two sets
  • Using marshaling, I was able to get the union method to work, but following the same design, I can't get the intersection logic to work

The Set class's deepCopy method:

def deepCopy(toCopy)
  Marshal.load(Marshal.dump(toCopy))
end

The Set class's union method (this works):

def union(set2)
  # clone the current set into union set
  unionSet = Set.new
  unionSet.deepCopy(self)

  # iterate through set 2 and append all unique elements to union set
  set2.subscribers.each do |sub|
    if !unionSet.subscribers.include?(sub)
      unionSet.subscribers.push(sub)
    end
  end
  unionSet.printSet
end

The Set Class's Intersection method (this does NOT work):

def intersection(set2)
  intersectionSet = Set.new
  comparisonSet = Set.new
  otherSet = Set.new

  # choose the smallest set for the comparison set
  if @subscribers.size < set2.subscribers.size
    comparisonSet.deepCopy(self)
    otherSet.deepCopy(set2)
  else
    comparisonSet.deepCopy(set2)
    otherSet.deepCopy(self)
  end

  #PROBLEM: Both statements below print nothing and both say they are empty when checked. 
  intersectionSet.printSet
  comparisonSet.printSet

  # iterate through the comparison set and store all commonalities in intersection set
  comparisonSet.subscribers.each do |sub|
    puts "Looking for #{sub}"
    if otherSet.subscribers.include?(sub)
      intersectionSet.subscribers.push(sub)
    end
  end
  intersectionSet.printSet
end
end

This is a pretty basic project, but learning the nuances of Ruby is making it rather difficult. I even tried just cloning self in the intersection method like I did in union, but that didn't work either. This makes me wonder if it some sort of memory issue?


Solution

  • You are not initializing your sets here:

      if @subscribers.size < set2.subscribers.size
        comparisonSet.deepCopy(self)
        otherSet.deepCopy(set2)
      else
        comparisonSet.deepCopy(set2)
        otherSet.deepCopy(self)
      end
    

    The returned value isn't assigned to the sets. It should be something like comparisonSet = self.deepCopy(self). You can see the method call here has redundant info. I suggest you change your #deepCopy to

    def deep_copy  # use snake case as per ruby convention
      Marshal.load(Marshal.dump(self))
    end
    

    Then you can do something like:

    comparison_set = self.deep_copy
    other_set = set2.deep_copy
    

    Your current implementation works with union because the union set starts as an empty set and takes in every subscribers you throw at it.

    By the way, I'm not sure you need to do the copy here. Seems you can do without it. But of course I haven't seen your whole code.