Why is Cloneable not deprecated?

There is a bug submitted in 1997 to Java Bug Database about adding clone() method to Cloneable, so it would no longer be useless. It was closed with resolution "won't fix" and justification was as follows:

Sun's Technical Review Committee (TRC) considered this issue at length and recommended against taking any action other than improving the documentation of the current Cloneable interface. Here is the full text of the recommendation:

The existing Java object cloning APIs are problematic. There is a protected "clone" method on java.lang.Object and there is an interface java.lang.Cloneable. The intention is that if a class wants to allow other people to clone it, then it should support the Cloneable interface and override the default protected clone method with a public clone method. Unfortunately, for reasons conveniently lost in the mists of time, the Cloneable interface does not define a clone method.

This combination results in a fair amount of confusion. Some classes claim to support Cloneable, but accidentally forget to support the clone method. Developers are confused about how Cloneable is supposed to work and what clone is supposed to do.

Unfortunately, adding a "clone" method to Cloneable would be an incompatible change. It won't break binary compatibility, but it will break source compatibility. Anecdotal evidence suggests that in practice there are a number of cases where classes support the Cloneable interface but fail to provide a public clone method. After discussion, TRC unanimously recommended that we should NOT modify the existing Cloneable interface, because of the compatibility impact.

An alternative proposal was to add a new interface java.lang.PubliclyCloneable to reflect the original intended purpose of Cloneable. By a 5 to 2 majority, TRC recommended against this. The main concern was that this would add yet more confusion (including spelling confusion!) to an already confused picture.

TRC unanimously recommended that we should add additional documentation to the existing Cloneable interface to better describe how it is intended to be used and to describe "best practices" for implementors.

So, although this is not directly about deprecated, the reason for not making Cloneable "deprecated" is that Technical Review Comitee decided that modifying existing documentation will be sufficient enough to make this interface useful. And so they did. Until Java 1.4, Cloneable was documented as follows:

A class implements the Cloneable interface to indicate to the Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class.

Attempts to clone instances that do not implement the Cloneable interface result in the exception CloneNotSupportedException being thrown.

The interface Cloneable declares no methods.

Since Java 1.4 (which was released in February 2002) up to current edition (Java 8) it looks like this:

A class implements the Cloneable interface to indicate to the Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class. Invoking Object's clone method on an instance that does not implement the Cloneable interface results in the exception CloneNotSupportedException being thrown.

By convention, classes that implement this interface should override Object.clone (which is protected) with a public method. See Object.clone() for details on overriding this method.

Note that this interface does not contain the clone method. Therefore, it is not possible to clone an object merely by virtue of the fact that it implements this interface. Even if the clone method is invoked reflectively, there is no guarantee that it will succeed.


The short answer to "why isn't Cloneable deprecated?" (or indeed, why isn't X deprecated, for any X) is that there hasn't been much attention paid to deprecating them.

Most things that have been deprecated recently were deprecated because there is a specific plan to remove them. For example, the addPropertyChangeListener and removePropertyChangeListener methods of LogManager were deprecated in Java SE 8 with the intention of removing them in Java SE 9. (The reason is that they unnecessarily complicated module interdependencies.) Indeed, these APIs have already been removed from early JDK 9 development builds. (Note that similar property change listener calls were also removed from Pack200; see JDK-8029806.)

No such similar plan exists to for Cloneable and Object.clone().

A longer answer would involve discussing further questions, such as what one might expect to happen to these APIs, what costs or benefits would accrue the platform if they were deprecated, and what is being communicated to developers when an API is deprecated. I explored this topic in my recent JavaOne talk, Debt and Deprecation. (Slides available at that link; video here.) It turns out that the JDK itself hasn't been very consistent in its usage of deprecation. It's been used to mean several different things, including for example,

  • This is dangerous and you should be aware of the risks of using it (example:Thread.stop(), Thread.resume(), and Thread.suspend()).

  • This is going to be removed in a future release

  • This is obsolete and it's a good idea for you to use something different (example: many of the methods in java.util.Date)

All of these are distinct meanings, and different subsets of them apply to different things that are deprecated. And some subset of them apply to things that aren't deprecated (but that maybe should be deprecated).

Cloneable and Object.clone() are "broken" in the sense that they have design flaws and are difficult to use correctly. However, clone() is still the best way to copy arrays, and cloning has some limited usefulness to make copies of instances of classes that are carefully implemented. Removing cloning would be an incompatible change that would break a lot of things. A cloning operation could be reimplemented a different way, but it would probably be slower than Object.clone().

However, for most things a copy constructor is preferable to cloning. So perhaps marking Cloneable as "obsolete" or "superseded" or something similar would be appropriate. This would tell developers that they probably want to look elsewhere, but it would not signal that the cloning mechanism might be removed in a future release. Unfortunately, no such marker exists.

As things stand, "deprecation" seems to imply eventual removal -- despite the fact that a vanishingly small number of deprecated features have ever been removed -- and so deprecation doesn't seem warranted for the cloning mechanism. Perhaps in the future an alternative marking can be applied that directs developers to use alternative mechanisms instead.

UPDATE

I've added some additional history to the bug report. Frank Yellin, an early JVM implementor and co-author of the JVM specification, made some comments in response to the "lost in the mists of time" comment in the TRC recommendation quoted in the other answer. I've quoted the relevant portions here; the full message is in the bug report.

Cloneable has no methods for the same reason that Serializable doesn't. Cloneable indicates a property of the class, rather than specifically saying anything about the methods that the class supported.

Prior to reflection, we needed a native method to make a shallow copy of an Object. Hence Object.clone() was born. It was also clear that many classes would want to override this method, and that not every class would want to be cloned. Hence Cloneable was born to indicate the programmer's intention.

So, in short. The purpose of Cloneable was not to indicate that you had a public clone() method. It was to indicate that you were willing to be cloned using Object.clone(), and it was up to the implementation to decide whether or not to make clone() public.