Why is Cloneable not deprecated?
Asked Answered
D

3

146

It is commonly understood that Cloneable interface in Java is broken. There are many reasons for this, which I will not mention; others already did it. It is also the position of Java architects themselves.

My question is therefore: why has is not been deprecated yet? If the core Java team have decided that it is broken, then they must also have considered deprecation. What are their reasons against doing so (in Java 8 it is still not deprecated)?

Drawl answered 16/10, 2014 at 7:48 Comment(32)
This question is not "primarily opinion-based", as many apparently feel entitled to judge. Those who have nothing more than an opinion on the reasons are simply not qualified to answer. However, it is true that you only stand a remote chance of getting an authoritative answer here. It is also true that your question is not about a solvable problem you have, so it it's at least borderline off-topic.Kavanagh
Here's another link on the subject, which also contains a reference to the link provided by the OP.Schiro
Shouldn't deprecation be used only for thing that are replaced by something better and/or going to be removed? Cloneable even if broken may simply not fall in this category.Herron
"interface is broken and actually useless" - useless? There are certain circumstances when "cloneable" just works and copy constructors don't give any vantage..Clime
@MarkoTopolnik I agree that there are some people out there in the world who could provide an authoritative answer, but I don't believe that's the test we apply here. The closure reason states "answers to this question will tend to be almost entirely based on opinions". I suspect that will be the case here, unless we get very lucky.Agonist
Here is my guess as to the reason would be: deprecating something means that a decision has been made to remove it from a future version of Java. However, Cloneable has very deep penetration into the JDK and removing it would entail such massive changes that the damaage would outweigh the damage it is currently making.Kavanagh
Here is "How and When" to deprecate from Oracle ... (docs.oracle.com/javase/6/docs/technotes/guides/javadoc/…) Cloneable interface might fall in the "buggy, or highly inefficient" case but its very open to opinions.Herron
@Duncan I still don't consider it fair to pass judgement on the question based on my assumptions about the lack of discipline on the answerers' part. If a user does not know the reason being asked about, (s)he is not entitled to abuse the answering facility to present his/her opinion on the matter.Kavanagh
@Duncan I agree with Marko Topolnik. Even if there would be some primary based opinions, then this is what downvoting answers is for. I see no reson why this question shouldn't be reopened.Drawl
@MarkoTopolnik I was one of the "closers" as I thought this question is purely polemic. Thanks to your comment, I see the other side now. Like, "What reasons do Oracle people have not to deprecate Cloneable?". I hope you also see that it's easy to fall on the "polemic" side here.Blear
@Blear Yes, exactly---and you can bet they have thoroughly considered that option and by implication must have strong reasons not to deprecate it. Their own criticism of Cloneable is widely known.Kavanagh
@MarkoTopolnik I appreciate reopening the question then but don't have high hopes for clarification unless someone insider comes around.Blear
@MarkoTopolnik this question is totally "primarily opinion-based" - OP throws an opinion that some method is "broken and actually useless" and then asks a "loaded" question that implies both that this opinion is true and that the question proposition is the only way to deal with it.Hygrophilous
related Java: Rationale of the Cloneable interfaceZircon
@Zircon I'd say it is not just related, it is a duplicate.Blear
@Blear well, the question is strictly different, but the answers can be copied here.Zircon
@Zircon None of the answers in that question answers why Cloneable is not deprecated yet.Drawl
@Drawl second answer: this is a design flaw in earlier versions of Java that they are not intending to fix in the Cloneable interface as to do so would break compatibility with some existing code and that's exactly what EJP answered you here.Zircon
@Narmer, Oh, right. But this is still just one answer.Drawl
@OlegEstekhin That Cloneable is broken is not an opinion, it is a medical fact.Blear
More to the point, the Oracle team themselves have proclaimed it broken. Therefore they must have a specific reason why they have not also deprecated it.Kavanagh
If you feel that Cloneable should be deprecated, please file an issue here: bugreport.java.com You might then also start a discussion on one of the OpenJDK mailing lists: mail.openjdk.java.net/mailman/listinfoCupulate
Not only is Cloneable broken, it's broken beyond repair. Maybe that's got something to do with it.Rianon
Even though Cloneable is broken, it makes it possible for code to achieve semantics which are not achievable any other way [e.g. making it possible for a cloneable class to have proper derivatives without requiring them to override clone unless they add members that require deep cloning]. In retrospect, a better approach would have been for Java to include a CloneableBaseObject which derived from Object and implemented a clone member via "JVM magic", and suggest that types which should be cloneable should derive from that, but the horse has long since left the barn.Salve
The only way I could see Cloneable being deprecated would be if some "JVM magic" was used to make it so that every type which inherited from Object and implemented Cloneable would be deemed to instead inherit from CloneableBaseObject, which itself implemented Cloneable. Under such a scenario, Object.clone() could simply throw an exception, while the override in CloneableBaseObject would behave as Object.clone() does now when in those cases where it may legitimately be used. Ideally, there would also be a slight change to the rules about checked exceptions...Salve
...such that the declaration of ClonableBaseObject.Clone would specify that it used to throw a clone-not-supported exception, such that code which called clone on an object derived from CloneableBaseObject would be allowed to catch the exception (even though it would never be thrown) but would not be required to do so.Salve
@MarkoTopolnik: Things should not be deprecated unless nearly every user would be able to switch to something which is, at least for that user, just as good in every way. Some code uses Cloneable in ways that would be difficult to mimic any other way.Salve
@Salve Code uses the clone facility, which is distinct from all the treacherous curves built into the cloning mechanism as a whole. A different mechanism, based on the same low-level object copying, but fixing stuff such as final field mutation and the awkwardness of shoving the cloneability semantics into the type system would probably be achievable.Kavanagh
@MarkoTopolnik: New mechanisms could be added, but migration to them would involve a chicken-and-egg problem. In general, when something is migrated, it should be possible to independently modify each individual class which uses it so that it will use something else instead, without affecting other code related to the class which was modified. Some "JVM magic" might make it possible to make migrate away from cloneable, but that would have to be in place before it would be reasonable to even consider deprecation.Salve
@MarkoTopolnik: Also, I would posit that the fundamental problem isn't the inclusion of cloneability semantics in the type system, but rather the type system's lack of distinction between storage locations that identify sharable objects versus those which identify objects to which no independent references should ever exist. Such distinctions may not be important to the Runtime, but programmers must make them in order to write correct programs. Languages that can express such distinctions can allow 99% of the code needed for cloning and equivalence can be handled automatically.Salve
@Drawl Thank you for awarding the bounty!Chatterjee
See also: Why is clone() not in the Cloneable interface?Chatterjee
D
124

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.

Drawl answered 16/10, 2014 at 11:31 Comment(12)
and do you know why the clone method was in Object in the first place?Peonir
@Peonir That's an essential part of the mechanism---it's the method doing the low-level, extralinguistic magic of copying the object image bit for bit.Kavanagh
@MarkoTopolnik can you please elaborate a bit more on the low level, extra linguistic Magic part? Thanks.Cheka
@Cheka That magic is something you can't replicate with a copy constructor: Object#clone() produces an instance of the same class as the original without that class being known at compile time.Kavanagh
Why it's not a default implementation of the clone method in the Clonable interface in Java 8?Rickeyricki
@AVolpe: That wouldn't fix the source incompatibility mentioned in the answer "where classes support the Cloneable interface but fail to provide a public clone method." In particular, classes providing a nonpublic clone method would be broken.Oran
Nice history. Here's a direct link to the bug database. I've added some more history there, and I've quoted parts of it in my answer.Chatterjee
With the new default methods in interfaces they could introduce public clone() without breaking stuff. It could do a shallow copy by default.Lavadalavage
@Lavadalavage Actually, it would break stuff, because default methods are Java 8-specific feature. So, it wouldn't be backwards compatible.Drawl
@Drawl why not? Cloneable interface with default public clone() will work for classes, created for previous versions, because method implementations are linked at runtime.Lavadalavage
It seems that you're right. Didn't know about that.Drawl
Unfortunately, adding a default clone method to Cloneable would break where the class has a non-public clone method already defined - it would be attempting to override a public method with a protected method. But it would work where the class doesn't have a clone method at all. Also see stackoverflow.com/questions/34122010Blynn
C
66

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.

Chatterjee answered 16/10, 2014 at 23:30 Comment(13)
One fine answer you have here sir. I especially like that you don't just throw Object.clone() into the fire just because everyone else wants to, but you're willing to reason and bring up the good things of it.Sea
Indeed, these APIs have already been removed from early JDK 9 development builds. They are to be replaced with Runnable instead: mail.openjdk.java.net/pipermail/core-libs-dev/2014-September/…Zwart
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. I was under the impression with the fix of 6428387, all code paths (clone, new/arrayCopy, Arrays.copyOf) resulted in the same intrinsics. Has anything changed recently?Zwart
Wow, these add/removePropertyChangeListener methods are the first deprecated methods in Java being really removed from the API. And that seems to be the first time that functionality made deprecated in one version is dysfunctional right in the next one either. I guess, there will be exciting times, once the industry will notice… So to put it together, Thread.suspend() remains but highly dangerous methods like add/removePropertyChangeListener are removed.Bregma
@Zwart Interesting, thanks for mentioning the replacement calls that use Runnable. Note that the replacement (or renaming) of an API is essentially a removal and an addition. PropertyChangeListener and Runnable are unrelated in the type system, so any code that used the former can never end up finding the latter; thus it's both a source and binary incompatible change.Chatterjee
@Zwart I don't think array.clone() is necessarily any faster than any alternatives. From the API perspective it's the most concise way to duplicate an array. Arrays.copyOf(array, newlen) comes close, but it requires a length parameter, which is redundant if you're not changing the length.Chatterjee
@Bregma Yes as far as we can see this is the first actual removal of an API since 1.1. Note also that even though we agree that Thread.suspend() and Thread.stop() (no-arg) are dangerous, they probably won't be removed -- or changed to throw an exception unconditionally -- because people actually use them! Presumably they're willing to bear the risk. One of the mitigating factors with the property change listeners is that they were used very rarely, so the impact of removing them is small.Chatterjee
It’s hard to say how much an API is used in practice. After all, the method removal will break any code calling the methods even if the application might not really rely on the notification. It’s important to keep in mind that the bean stuff has been used by code generation tools which might generate listener registration code automatically if a software component happens to support property change events. But honestly, I don’t get the problem that the removal shall solve. Do module borders always have to match packages? All that because it wasn’t named java.lang.PropertyChangeListener?Bregma
@Bregma Sure, it's definitely an incompatibility. The team that did the removal did a survey of a lot of Java source code and found that these APIs were used rarely, say, compared to something like java.util.List. They certainly couldn't have possibly surveyed all Java code, so undoubtedly they've missed some usages, but the number of impacted programs seemed fairly small.Chatterjee
@Bregma There are a couple rules being applied here. One, packages are not split across modules. Two, there should be no circular dependencies among modules. The module graph in JEP 200 shows that the java.desktop module (which contains beans) depends on the java.logging module. The removed APIs created a dependency in the opposite direction, which would have introduced a circularity. Similarly, Pack200 (in package java.util.jar) is part of the java.base module, and that certainly must not depend on java.desktop.Chatterjee
@Stuart Marks: Maybe the decision that java.beans belongs to java.desktop should be questioned. After all, the beans technology has nothing to do with desktop, but is a level deeper than that. (Otherwise, what are enterprise beans then, desktop components running on the server?) The java.beans package as found in older implementations contains default persistence delegates for desktop classes but these classes shouldn’t be there anyway. E.g., the default beaninfo classes for desktop classes are in an implementation-specific package. It’s not clear why this was abandoned for persistence.Bregma
@Stuart Marks: in the picture, even CORBA depends on “desktop”. Or, look at the dependency “java.xml.soap → java.xml.bind → java.activation → java.desktop”. This module graph is driving design decisions about the next Java, seriously?Bregma
@Bregma Conceptually java.beans could be made independent of java.desktop since beans are just a library API for properties. Unfortunately if you dig into the beans API there are lots of dependencies on AWT. The implementation has even more. Certainly it might be possible to extricate them, but doing that seems like a lot more work than, say, disentagling logging from beans. The whole modularization effort is about doing this disentangling; undoubtedly more could be done, but then Jigsaw would take even longer.Chatterjee
S
-2

why it is not deprecated yet?

Because the JCP hasn't seen fit to do so, and may never do so. Ask them. You're asking in the wrong place.

What are the reasons behind keeping this thing in Java API

No-one will ever remove anything from the Java API, because of the backwards compatibility requirement. The last time that happened was the change in the AWT event model between 1.0 and 1.1 in 1996/7.

Scarron answered 16/10, 2014 at 8:49 Comment(10)
They did (effectively) remove Thread.stop(Throwable) by changing its contract to always throw UnsupportedOperationException to the caller (not to the target thread!).Kavanagh
@MarkoTopolink That's not a removal, and it took place around the same time. My point stands.Scarron
What took place around the same time? The removal of Thread.stop(Throwable)'s functionality happened in Java 8. Anyway, the unqualified advice to "ask them" is wrong because today the chief Java architect himself is an active member on Stack Overflow. He just doesn't happen to bother answering anything but Streams-related questions.Kavanagh
Furthermore, OP's question is not about removal, but about deprecation, and clearly deprecation has been happening all along.Kavanagh
@EJP I'm not asking whether Cloneable will be removed from Java API. I'm asking why it's not going to be depracted. And I think this is a perfect place for asking.Drawl
@Drawl it's not. Your asking for random peoples' opinions about something that's not controlled by them. Read the documentation, the release notes, send a complaint to the responsible people at Oracle.Wrier
@Wrier All those upvotes says something opposite. Vox populi, vox dei.Drawl
EJP please see @Stuart_Marks answered this question , he is a one of Java Architects in OracleTalia
@VaheHarutyunyan Thanks for the shout-out, but I'm not a Java architect. I'm an engineer in Oracle's JDK group, which maintains this stuff.Chatterjee
@Drawl You asked, and I quote, 'what are the reasons behind keeping this thing in Java API?' The alternative to keeping is removal.Scarron

© 2022 - 2024 — McMap. All rights reserved.