Name: mf23781 Date: 12/09/97
Name: tb29552 Date: 03/12/2000
Get the Class object, examine the interfaces it implements to see if
it implements Cloneable(), if so do a dynamic method call on the
(Review ID: 102333)
Oh, yes, this is certainly possible. It is *really*, ugly.
So it should be documented as a workaround, but it should not deter
us from fixing the problem. This is in the "workaround as painful
as needles under your fingernails" realm.
Cloneable doesn't define a public clone() operation, making it practically
useless. For obvious reasons, we'll never be able to add a public clone
operation to Cloneable, but we will be able to make a new interface that
extends Cloneable and does what Cloneable should have done. What to call this
new interface is open to debate (Clonable? Copyable? Herbert?)
At any rate, I believe that this should definitely be implemented in the
next major release after 1.2.
You know, I just thought of something. The "obvious" reason we can't
add clone() to Cloneable is that adding new methods to interfaces is
an incompatible change. The reason adding new methods is incompatible
is that is makes concrete classes suddenly abstract.
But in this case that wouldn't happen -- existing classes *all* have
a clone method. No such class would be abstract. This may be an
exception to the incompatible change-ness of adding methods to interfaces.
We at least ought to consider this, because if we *can* add it to
Cloneable it fixes a problem with existing systems, whereas if we add
a new interface we only fix new code written by highly-informed people.
The downside I see is that we will public-ify the clone method of any
existing class that both implements Cloneable but doesn't declare clone
as public. I have always found it hard to imagine the value of such
a thing, and so I doubt this is a serious issue in deep principle. But
others may disagree.
In any case, this is clearly the ideal fix, and our instincts that it
isn't possible are probably wrong.
Unfortunately, this does not work; the clone method in Object is protected, not public. All methods in interfaces are inherently public. Thus, a class that currently implements Cloneable but has no public clone method would break. In practice, I doubt that there are many such classes out there, but there are almost certainly a few.
It is worth noting that adding methods to interfaces breaks source compatibility, and not binary compatibility. In this instance, we might consider intentionally breaking source compatibility, knowing that the odds of a problem are low.
Ah, yes, if I inherit a public method from an interface that is satisified
by an inherited method of the same signature from my superclass, but with
more restricted access, I must redeclare the more restricted access method
that statisfies it as public -- it is not made public by inference. I had
forgotten that point, and so assumed that the protected method would be
made public by virtue of inheriting a public method of the same signature.
Sigh, at least in this case. It could have solved it so much nicer.
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
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.
A new SR opened for this report suggests that only classes
failing to support the contract of Cloneable would encounter
a source incompatibility. This is incorrect. A Cloneable class
with a protected (not public) clone method would be faithfully
honoring its contract, but would no longer compile.
###@###.### 11/3/04 21:42 GMT