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.
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.
The dup() is an inbuilt method in Ruby returns the number itself.
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.
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.
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
andMarshal.load
is to create deep copies of objects:def deepcopy(o) Marshal.load(Marshal.dump(o)) end
[…]
… the binary format used by
Marshal.dump
andMarshal.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.
Forget marshalling. The deep_dive gem will solve your problems.
https://rubygems.org/gems/deep_dive
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With