Implementing Clone

Now, before you get too excited, I’m not suggesting that you implement the all-but-deprecated ICloneable interface. Rather, this post is about how best to implement a method that duplicates an object - such a method is commonly named “Clone”.

If you like, you can skip the long-winded commentary below and start reading the recommendations at the bottom.

Some would argue that Copy is a better name than Clone, since it avoids the “smell” of ICloneable, but I think Clone is more discoverable. Obviously the patterns of this post can be used regardless of whether you like Clone, Copy, Duplicate, or Replicate.

Any Clone method should document its semantics if they aren’t obvious; in particular, it should be clear whether a “shallow” or a “deep” clone will be used. (A “deep” clone clones its “children”; a “shallow” clone simply copies the references of its children.)

In some circumstances, it may be useful to add a parameter to Clone that can change the behavior. For example, proposals to improve the ICloneable interface included a parameter that would indicate whether a shallow or deep clone is desired. Adding a parameter to the Clone method should be a simple extension to the patterns described below.

The simplest kind of clonable class is a sealed class, because we don’t need to support derived classes. Even in this simple case, the cleanest approach is to delegate the cloning to a private “copy constructor”:

    public sealed class Vector
    {
        public Vector(int length)
        {
            m_array = new int[length];
        }
        public int Length
        {
            get { return m_array.Length; }
        }
        public int this[int index]
        {
            get { return m_array[index]; }
            set { m_array[index] = value; }
        }
        public Vector Clone()
        {
            return new Vector(this);
        }
        private Vector(Vector v)
        {
            m_array = (int[]) v.m_array.Clone();
        }
        int[] m_array;
    }

Now, suppose we wanted Vector to be an abstract class so that derived classes could decide how the items are stored. Furthermore, we determine that the length needs to be cached in the base class for performance reasons:

    public abstract class Vector
    {
        protected Vector(int length)
        {
            m_length = length;
        }
        protected Vector(Vector v)
        {
            m_length = v.m_length;
        }
        public int Length
        {
            get { return m_length; }
        }
        public abstract int this[int index] { get; set; }
        public abstract Vector Clone();
        int m_length;
    }

The protected “copy constructor” is provided to simplify the Clone override:

    public sealed class ArrayVector : Vector
    {
        public ArrayVector(int length)
            : base(length)
        {
            m_array = new int[length];
        }
        private ArrayVector(ArrayVector v)
            : base(v)
        {
            m_array = (int[]) v.m_array.Clone();
        }
        public override int this[int index]
        {
            get { return m_array[index]; }
            set { m_array[index] = value; }
        }
        public override Vector Clone()
        {
            return new ArrayVector(this);
        }
        int[] m_array;
    }

In the ArrayVector implementation above, I’d like the overridden Clone method to be more type-safe - that is, I’d like it to return an ArrayVector instead of a Vector. Unfortunately, while some languages (e.g. C++) allow overrides to return a more-derived class than the method they override, C# does not. Not to be deterred in my quest for type safety, my preferred pattern is to use CloneCore as the overridable and define Clone as a separate non-overridable method in each concrete class.

    public abstract class Vector
    {
        // ...

        protected abstract Vector CloneCore();
        // ...

    }
    public sealed class ArrayVector : Vector
    {
        // ...

        public ArrayVector Clone()
        {
            return (ArrayVector) CloneCore();
        }
        protected override Vector CloneCore()
        {
            return new ArrayVector(this);
        }
        // ...

    }

Incidentally, if you really want to implement ICloneable:

    public class Vector : ICloneable
    {
        // ...

        object ICloneable.Clone()
        {
            return Clone();
        }
        // ...

    }

##

Okay, enough commentary. Here are the recommendations:

Recommendations

There are three parts to a clonable class: (1) the copy constructor, (2) the CloneCore method, and (3) the Clone method.

The copy constructor is always defined, and does all of the copying, being sure to call the base class copy constructor if available. It is always protected (unless the class is sealed, in which case it is private).

The CloneCore and Clone methods are only implemented on non-abstract classes, and always have the same definitions. (Exception: if the root class is abstract, CloneCore is an abstract method on that class.) The CloneCore method uses the copy constructor to clone the instance. The Clone method calls CloneCore and casts the result to the correct type. If the Clone method overloads a base class method, use the “new” keyword.

Clear? No? Let’s try sample code. Consider the clonable classes Base and Derived, where Derived derives from Base. The Base class should always have a protected copy constructor:

    protected Base(Base x)
    {
        // copy members from x

    }

If Base is abstract, it only has an abstract CloneCore:

    protected abstract Base CloneCore();

If Base is not abstract, it defines both Clone and CloneCore:

    public Base Clone()
    {
        return (Base) CloneCore();
    }
    protected virtual Base CloneCore()
    {
        return new Base(this);
    }

Similarly, the Derived class should always have a copy constructor:

    protected Derived(Derived x)
        : base(x)
    {
        // copy members from x

    }

But if Derived is sealed, it will need to be private:

    private Derived(Derived x)
        : base(x)
    {
        // copy members from x

    }

If Derived is abstract, it is done. If Derived is not abstract, it defines both Clone and CloneCore:

    public new Derived Clone()
    {
        return (Derived) CloneCore();
    }
    protected override Base CloneCore()
    {
        return new Derived(this);
    }

If no ancestors have defined a Clone method (e.g. Base is abstract), you’ll have to omit the “new” keyword from the Derived Clone method.

Whew. It feels like I wrote too much, but I’ll just publish and move on. Hope this is useful!

Posted by Ed Ball on June 09, 2008