Search code examples
javajava-8clonecloneabledefault-method

Why no default clone() in Cloneable in Java 8


Cloneable in Java is inherently broken. Specifically, my biggest problem with the interface is it expects a method behavior that doesn't define the method itself. So if traversing through a Cloneable list you must use reflection to access its defined behavior. However, in Java 8, we now have default methods and now I ask why there isn't a default clone() method in Cloneable.

I understand why interfaces cannot default Object methods, however, this was an explicit design decision and so exceptions can be made.

I sort of envision deprecating Object.clone() and changing its interior code to something like:

if(this instanceof Cloneable) {
    return ((Cloneable) this).clone();
}
else {
    throw new CloneNotSupportedException();
}

And moving on whatever magic makes clone() do its thing as a default method in Cloneable. This doesn't really fix that clone() can still easily be implemented incorrectly, but that's another discussion in of itself.

As far as I can still this change would be completely backwards compatible:

  1. Classes that currently override clone() but didn't implement Cloneable (WHY?!) would still be technically okay (even if functionally impossible, but this is no different then it was before).
  2. Classes that currently override clone(), but did implement Cloneable would still function the same on its implementation.
  3. Classes that don't currently override clone(), but did implement Cloneable (WHY?!) would now follow a specification, even if it's not completely functionally correct.
  4. Those that used reflection and referred to Object.clone() would still functionally work.
  5. super.clone() would still be functionally the same even if it's referencing Object.clone().

Not to mention this would solve a huge problem that Cloneable is. While tedious and still easy to implement incorrectly, it would solve a huge object oriented problem with the interface.

The only problem I can see with this is those that implement Cloneable aren't obligated to override clone(), but this is no different than it was before.

Has this been discussed internally, but never came to fruition? If so, why? If it's for the reason that interfaces cannot default Object methods, wouldn't it make sense to make an exception in this case since all objects inheriting Cloneable are expecting clone() anyway?


Solution

  • Your question is somewhat broad and more of a discussion, but I can shed some light on this matter.

    In Effective Java™, Joshua Bloch gives quite the rundown on the situation. He opens with a bit of history behind Cloneable

    The Cloneable interface was intended as a mixin interface for objects to advertise that they permit cloning. Unfortunately, it fails to serve this purpose. Its primary flaw is that it lacks a clone method, and Object’s clone method is protected. You cannot, without resorting to reflection, invoke the clone method on an object merely because it implements Cloneable.

    and continues with the reasoning

    [Cloneable] determines the behavior of Object’s protected clone implementation: if a class implements Cloneable, Object’s clone method returns a field-by-field copy of the object... This is a highly atypical use of interfaces and not one to be emulated. Normally, implementing an interface says something about what a class can do for its clients. In the case of Cloneable, it modifies the behavior of a protected method on a superclass.

    and

    If implementing the Cloneable interface is to have any effect on a class, the class and all of its superclasses must obey a fairly complex, unenforceable, and thinly documented protocol. The resulting mechanism is extralinguistic: it creates an object without calling a constructor.

    There are a lot of details that go into this, but to note just one problem:

    The clone architecture is incompatible with normal use of final fields referring to mutable objects.

    I think this is enough to reason against having a default method in the interface do the cloning. It would be extremely complicated to implement it correctly.