Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 507
danthonywalker Avatar asked Dec 06 '15 20:12

danthonywalker


1 Answers

My experience is probably far from being mainstream, but I use clone() and support the current design of Cloneable. Probably it would be better to have it as annotation instead, but Cloneable appeared long before the annotations. My opinion is that Cloneable is a low-level thing and nobody should do something like obj instanceof Cloneable. If you are using Cloneable in some business-logic, it's much better to declare your own interface or abstract class which exposes clone() to public and implement it in all of your business-logic objects. Sometimes you will probably want not to expose clone() actually, but create your own method which uses clone() internally.

For example, consider that you have an hierarchy of named objects where name cannot be changed after construction, but you want to allow cloning them with new name. You can create some abstract class like this:

public abstract class NamedObject implements Cloneable {
    private String name;

    protected NamedObject(String name) {
        this.name = name;
    }

    public final String getName() {
        return name;
    }

    public NamedObject clone(String newName) {
        try {
            NamedObject clone = (NamedObject)super.clone();
            clone.name = newName;
            return clone;
        }
        catch(CloneNotSupportedException ex) {
            throw new AssertionError();
        }
    }
}

Here even though you implement Cloneable, you want to use clone(), but don't want to expose it publicly. Instead you provide another method which allows to clone with another name. So having public clone() in Cloneable would unnecessarily pollute the public interface of your classes.

Another case where I use Cloneable is the implementation of Spliterator.trySplit(). See the implementation of simple spliterator which returns given number of constant objects. It has four specializations (for Objects, ints, longs and doubles), but thanks to clone() I can implement trySplit() only once in the superclass. Again, I don't want to expose clone(), I just want to use it by myself.

So to conclude, not having clone() method in Cloneable interface is actually more flexible as it allows me to decide whether I want to have it public or not.

like image 54
Tagir Valeev Avatar answered Oct 30 '22 09:10

Tagir Valeev