3

Short version of the question: What is a proper way to implement object cloning with deep copy, using generally accepted OOP principles?


I ran into this while looking into the Prototype Design Pattern in the GoF Design Patterns book, but I think it applies to general object cloning.

Wouldn't it be, each class has to properly implement its own instance method of deep_copy, because each class has its own way to "going through" all elements, such as left and right for a binary tree, and sometimes, an object A having 2 other references to 2 other objects: B and C, may mean A own B and C, and therefore B and C should also be cloned, while in some cases, such as a node object in a graph, A having a reference to B and C just means it is pointing to B and C and DO NOT own B, C (other nodes in the graph may also point to B and C).

There is a way to clone, which is serialize it and unserialize it (which should be same as data marshalling?) but it doesn't handle the case when the object doesn't own another object, or in the case of a node in a graph, can you serialize and unserialize, and get back a cloned node that points to the proper nodes in the graph as the original node object does?

Another complication may arise, if object A has an instance variable foo, and it has a data structure that reference object B twice, so we really should not clone B twice. Or, if foo reference it once in its data structure, but another instance variable bar also reference B, then also we should not clone B twice but once. And if A doesn't own B, then we should not clone B at all.

But let's say we ignore the complication above:

Then roughly speak, all classes in your application should implement its own method of deep_copy, and it roughly is this:

# Pseudo code:

class SomeClass
  def deep_copy
    new_object = self.clone()  # to have all the instance variables and 
                               # methods cloned, but just a shallow copy, and 
                               # also, all the inheritance, access to
                               # class variables, methods, and inheritance 
                               # hierarchy should be properly set up

    for all objects that is referenced by my instance variables
      if I own the object (by the design of my class), then
        # rely on polymorphism to make a proper deep_copy of this object
        new_object.this_instance_variable = self.this_instance_variable.deep_copy() 
      end
    end

    return new_object
  end
end

and depending on whether the primitive types are object or not, it may just say: if I own the object, but it is primitive, then don't clone it. Or in case the primitive types (like Fixnum, 1, 2, 3) are objects too, as in Ruby, then just let it clone it (because you don't want to do type checking to see whether it is clone-able), but in the self.clone line, it will raise an exception to say that this type is not for cloning, and in that case, just catch the exception and return the same object without cloning it (which is the base case of the recursion).

But the key point is, using generally accepted OOP principles, every class in your app has to have the deep_copy implemented, and its contract (the interface contract) is that it will indeed return a clone of "myself" together with deep copies of objects that I own (recursively). And it may be difficult because a lot of times, we define a class, and we don't really implement a deep_copy. If our app has 12 classes, and we need a clone with deep copy, then we actually have to implement such clone with deep copy for all 12 classes (or for all classes that may need to participate in the deep copy). Is the above correct, or are there some corrections according to OOP principles?

  • One correction: there is no point in implementing a deep_copy for immutable classes (especially in languages with a garbage collector). When doing a deep copy for a class with an immutable member, you can just pass a reference of the member info the copy. – Doc Brown Jan 3 '16 at 22:36
2

You have got the gist of it.

It should be noted that, depending on the language you use, there might be existing conventions for which function performs a deep copy of an object.
In many languages, your deep_copy function would be called clone. In C++, this is also the territory of the copy-constructor.

0

Exactly as Bart explained. By convention in C++ or Java this is done with either a clone() instance method or a copy constructor. Indeed, it could be good practice, for code that you plan to release, to provide both.

public class Foo
{
    private Bar m_bar ;
    private Baz m_baz ;

    // copy constructor
    public Foo( Foo that )
    { // other classes might use either pattern
        this.m_bar = that.m_bar.clone() ;
        this.m_baz = new Baz( that.m_baz ) ;
    }

    // simply reuse copy constructor implementation
    public Foo clone()
    {
        return new Foo( this ) ;
    }
}
  • so if adding an instance variable to class, then will have to update the constructor code (which you would normally do) and the copy constructor code (which you might forget to do)? I suppose in C++ or Java, there might be no, or harder to come up with, generic clone that works no matter how you define your class else where? – 太極者無極而生 Jan 4 '16 at 7:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.