Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't there a deep copy method in Ruby?

I am working on a solution for technical drawings (svg/ruby). I want to manipulate rectangles, and have an add! method in this class:

class Rect
  def add!(delta)
    @x1+=delta 
    ... # and so on
    self
  end
end

I also need an add method returning a Rect, but not manipulating self:

def add(delta)
  r=self.dup/clone/"copy" # <-- not realy the 3 and no quotes, just in text here
  r.add! delta
end

dup and clone don't do my thing but:

def copy; Marshal.load(Marshal.dump(self)); end

does.

Why does such a basic functionality not exist in plain Ruby? Please just don't tell me that I could reverse add and add!, letting add do the job, and add! calling it.

like image 874
halfbit Avatar asked Jul 28 '13 20:07

halfbit


People also ask

How do you copy an object in Ruby?

Ruby does provide two methods for making copies of objects, including one that can be made to do deep copies. The Object#dup method will make a shallow copy of an object. To achieve this, the dup method will call the initialize_copy method of that class. What this does exactly is dependent on the class.

What is .DUP in Ruby?

The dup() is an inbuilt method in Ruby returns the number itself.

What is Deep_dup?

The #deep_dup method in Rails method returns true . This means that an instance that contains the Object class in its ancestor chain is eligible to deep copy.

What is DUP in Ruby on Rails?

This is what Rails is using with its #dup method on ActiveRecord. It uses #dup to allow you to duplicate a record without its "internal" state (id and timestamps), and leaves #clone up to Ruby to implement. Having this extra method also asks for a specific initializer when using the #clone method.


2 Answers

I'm not sure why there's no deep copy method in Ruby, but I'll try to make an educated guess based on the information I could find (see links and quotes below the line).

Judging from this information, I could only infer that the reason Ruby does not have a deep copy method is because it's very rarely necessary and, in the few cases where it truly is necessary, there are other, relatively simple ways to accomplish the same task:

As you already know, using Marshal.dump and Marshal.load is currently the recommended way to do this. This is also the approach recommended by Programming Ruby (see excerpts below).

Alternatively, there are at least 3 available implementations found in these gems: deep_cloneable, deep_clone and ruby_deep_clone; the first being the most popular.


Related Information

Here's a discussion over at comp.lang.ruby which might shed some light on this. There's another answer here with some associated discussions, but it all comes back to using Marshal.

There weren't any mentions of deep copying in Programming Ruby, but there were a few mentions in The Ruby Programming Language. Here are a few related excerpts:

[…]

Another use for Marshal.dump and Marshal.load is to create deep copies of objects:

def deepcopy(o)
  Marshal.load(Marshal.dump(o))
end

[…]

… the binary format used by Marshal.dump and Marshal.load is version-dependent, and newer versions of Ruby are not guaranteed to be able to read marshalled objects written by older versions of Ruby.

[…]

Note that files and I/O streams, as well as Method and Binding objects, are too dynamic to be marshalled; there would be no reliable way to restore their state.

[…]

Instead of making a defensive deep copy of the array, just call to_enum on it, and pass the resulting enumerator instead of the array itself. In effect, you’re creating an enumerable but immutable proxy object for your array.

like image 96
leifericf Avatar answered Nov 15 '22 23:11

leifericf


Forget marshalling. The deep_dive gem will solve your problems.

https://rubygems.org/gems/deep_dive

like image 23
flajann Avatar answered Nov 15 '22 23:11

flajann