Implementing ICloneable


I was doing a little work on the Design Guidelines
document tonight and I noticed this section that we added recently.  
I thought I’d post it here for your comments.    Where are you
using ICloneable today?  Do you agree with this suggestion?


 


style="mso-fareast-font-family: Verdana; mso-bidi-font-family: Verdana"> style="mso-list: Ignore">1.1 Implementing
ICloneable
color=#808080>


size=2>The ICloneable interface contains a single Clone method, which is
used to create a copy of the current object.


face="Courier New" color=#ff00ff size=2>public interface ICloneable
{


color=#ff00ff> style="mso-tab-count: 1">    object
Clone();


face="Courier New" color=#ff00ff size=2>}


style="MARGIN: 3pt 0in 3pt 0.25in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1"> style="COLOR: red; FONT-FAMILY: 'Wingdings 2'; mso-fareast-font-family: 'Wingdings 2'; mso-bidi-font-family: 'Wingdings 2'"> style="mso-list: Ignore">? style="FONT: 7pt 'Times New Roman'">     
Do not implement
ICloneable


size=2>There are two general ways to implement ICloneable, either as a deep, or
non-deep copy. Deep-copy copies the cloned object and all objects referenced by
the object, recursively until all objects in the graph are copied. A non-deep
copy (referred to as ‘shallow’ if only the top level references are copied) may
do none, or part of a deep copy.


face=Verdana> style="COLOR: windowtext; mso-bidi-font-family: Arial">Because the interface
contract does not specify the type of clone performed, different classes have
different implementations. A consumer cannot rely on ICloneable to let
them know whether an object is deep-cloned or not.


style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: #e9fdf3; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 0.25in; BORDER-LEFT: windowtext 1pt solid; MARGIN-RIGHT: 0in; PADDING-TOP: 1pt; BORDER-BOTTOM: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt">

style="BACKGROUND: #e9fdf3; MARGIN: 6pt 0in 0pt; mso-add-space: auto"> size=2> style="FONT-WEIGHT: normal">Note: If you need a cloning
mechanism, define your own Clone, or Copy methodology, and ensure that you
document clearly whether it is a deep or shallow copy. An appropriate pattern
is:


style="BACKGROUND: #e9fdf3; MARGIN: 0in 0in 6pt; mso-add-space: auto"> style="FONT-SIZE: 10pt; FONT-FAMILY: Courier">public
<type> Copy(); "urn:schemas-microsoft-com:office:office"
/>


style="MARGIN: 3pt 0in 3pt 0.25in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1"> style="COLOR: red; FONT-FAMILY: 'Wingdings 2'; mso-fareast-font-family: 'Wingdings 2'; mso-bidi-font-family: 'Wingdings 2'"> style="mso-list: Ignore">? style="FONT: 7pt 'Times New Roman'">     
Do not use
ICloneable in public APIs

Comments (10)

  1. David Nicholson says:

    Well, I need copy functionality for my objects, so I implement ICloneable. However I write applications, not libraries, so my decision doesn’t affect anyone else.

    It seemed obvious to me that the definition was loose, so I would be wary about calling Clone on something I didn’t author. If I used a third party class I would consult the documentation, and would expect their implementation not to change in a breaking way.

    I’m not sure that everybody inventing their own equivalent helps much.

    I experience a similar confusion over Equals, but maybe that’s just me.

  2. Isn’t (wasn’t?) the point of ICloneable that the semantics are left to the type’s author? You want a clone of my object – and I decide what being a clone is. Of course the problem with a weak contract is that given an arbitrary object reference, I can’t discover the semantics of the implementation. The documentation doesn’t help when you’re discovering interfaces programmatically. IMO, It would be more helpful if there were two interfaces – one that implied shallow copies, and one that implied deep copies. In Eiffel, clone means shallow, and deep_clone is obvious.

  3. David Nicholson says:

    OK, forget the documentation! My problem with the author’s decision is that I have cases where I really want a deep copy. I start with an object, create a copy, the user modify the copy, then I want to diff the two objects. So I want some interface to be deep_copy.

    I just find it frustrating that the only interface we have (although weak) is now considered a bad idea.

  4. kitg says:

    David, this is a great note. And the idea of two separate interfaces (shallow/deep) to track this is still a possibility.

    The problem is that a single interface, for which we didn’t define the contract resulted in disparate implementations. The ‘ICloneable’ nature of an object tells you nothing about what the Clone does, meaning that accepting an ICloneable object (unless you can guarantee you know the contract of each object) is all but useless. If I then take that object and call Clone on it, what do I get? I have no idea. Too many valid implementations, with different definitions of the contract have shipped for us to justify enforcing a guideline at this point.

    Consider that if you did implement ICloneable, expecting all implementations to be deep, then if someone passes you a collection (such as ArrayList) you’re in trouble.

  5. David Nicholson says:

    I guess the only thing you can closely define is a deep copy. This should mean that my new object contains _no_ references to the old one.

    As the guideline above points out, there are enless variations on a non-deep copy, so maybe a loose ICloneable would do for that. Then we need a new interface that is deep.

    Personally I think a clone that is anything other than shallow (i.e. a simple ref assignment) or deep (i.e. everything) is a nightmare. What use is a partial copy where the contained objects are copied or not based on the class author’s choice?

  6. Chris Burrows says:

    I agree with Nick. I’m for one like to make things specific. Wouldn’t it be better, rather than just using documentation to state what a method does actually use a name that describes what it is doing? If it’s a deep copy have a method called deepcopy (or something similar), if it’s not then call the method it shallowcopy. Copy in my opinion can be to easily miss interpreted. If a method describes what it is doing the better as it leads to easier understanding of what a program is doing.

  7. Frank Hileman says:

    It’s a little too late to get rid of ICloneable now. It is implemented all over the Framework. I have used it once, to do a clone of every object in an array, but I could count on it only because I knew that every object was some primitive (int, double, etc). I always assumed the word "clone" meant "deep copy". This is what the convention has been in other languages and libraries.

  8. Pete says:

    The docs for Object.MemberwiseClone say that you should use ICloneable if a shallow copy is not appropriate. To me that is saying that ICloneable should be a deep copy.

  9. Kelly White says:

    As I&#39;ve mentioned earlier, I have a long commute to and from work each day. Each day as I ride the

  10. Ho seguito il webcast &quot; Disegno Architetturale: gli idiomi e le linee guida di desing per il .NET