The implementation of Object.clone() prevents guaranteed type-safe (both compile- and runtime) code from compiling. The following class will not compile:

public class SafeCloner {

    public Object cloneOrNull(Cloneable in) {
        try {
            return in.clone();
        } catch(CloneNotSupportedException) {
            return null;
        }
    }

}

(Yes I know that strictly speaking this isn’t type-safe. That’s what this article is about: why it should be.)

It will compile if you cast in to Object and make SafeCloner a member of the java.lang package. (This is a bug, not a feature — a specification bug that Java has had since the very beginning.) But it won’t run, since at runtime no additions to the java.lang package are accepted. I’m rather relieved, actually. I ended up hacking something together via reflection, but the java.lang hack was unbelievably dirty.

(Other people, more professional than I, have noted the same problem in different contexts, to do with designing classes for inheritance.)

Details

There are actually two different monumentally flawed design decisions involved here. The first is the semantic ambiguity in the protected visibility: protected methods on a class A are accessible to (a) subclasses of A, and also (b) classes in the same package as A. So Object.clone() can be called by anything in the java.lang package, but only subclasses outside it. I’ll probably write at greater length elsewhere exactly what is wrong with this idea, but that’s not the focus of this article. The other problem is the confusion between runtime and compile-time checking that is built into the Cloneable/clone() system of the Java libraries.

Cloneable provides type checking

The Java interface system is intended for compile- and runtime type checking. We have an interface Cloneable made for this purpose. In what follows, I’ll distinguish type-safety from “instance-safety”, which is what exceptions like ArithmeticException are for. In general type-safety can be guaranteed, while instance-safety cannot. Java divides type checking into compile time (static) and runtime (dynamic, strictly speaking “class checking”), with casting and ClassCastException the simplest example of the latter. (The generics feature of Java 1.5 moves a lot of the dynamic checking back to compile time, but is not sigificant for this particular problem.)

CloneNotSupportedException provides runtime instance checking

The documentation for Object.clone() states (referring to CloneNotSupportedException):

Subclasses that override the `clone` method can also throw this exception to indicate that an instance cannot be cloned. This is no longer type checking, but instance checking, and is thus distinct from the exceptions thrown by mistakenly casting an object to Cloneable. (Casts are needed because Java is — for acceptable reasons — not strongly enough typed to guarantee runtime type safety at compile-time. The CloneNotSupportedException comment above indicates an intended usage more similar to ArithmeticException, in case a particular instance of a generally cloneable class cannot be cloned.)

So far we have a nice clean division into type checking (compile- and runtime) via the interface, and instance checking via the exception. No complaints.

Object.clone() subverts both

And then the bombshell hits. Contrary to all rational expectation, clone() is not required by Cloneable. It is defined on Object, and it is protected.

Again from the documentation (this time for Cloneable):

By convention, classes that implement this interface should override `Object.clone` (which is protected) with a public method. “By convention.” This leaves us with three methods for marking your class (or instance) as being cloneable: implement Cloneable (for type checking), avoid throwing CloneNotSupportedException (for instance checking) and make sure clone() is public.

Now the only time this is useful is at compile time, and we already have perfectly good type checking through the interface mechanism. So what is going on here?

The only answer I’ve managed to come up with is that perhaps the designers expected that many classes would wish to restrict access to their clone methods. In that case, you can’t put clone() in the interface, because this will force it to be public. But they still wanted to enforce type-safety, so the Object.clone() implementation requires that it be called on an instance of a Cloneable class. (This explanation has huge holes, but so does every other I’ve come up with. It may simply be a case of confusion. For instance, I don’t see why a separate exception is needed which performs exactly the same function as a cast to Cloneable in the first line of Object.clone(). But the biggest question is, if your class has no public clone() method, in what sense is it Cloneable?)

Anyway, this is where the problem hits. Every class implementing Cloneable (“by convention”) has a public clone() method. But precisely because this is a convention, there’s no way to inform the compiler that this is the case. And so the SafeCloner class given above fails to compile, because clone() is not required by Cloneable. (Casting in to Object also doesn’t work, because Object.clone() is protected.)

But why would you want to?

This problem is not purely academic, it turned up in some code I was writing. I’ve pared it down to its minimal expression here for clarity.

The original requirement was a Set that sent events when objects were added or removed. This would be implemented as a wrapper around an original Set, generating the events and handing on the processing to the backing instance.

Now it is sort of built in to the idea here that nothing can be added to the backing instance without going through the wrapper. Compare for instance the java.util.Collections static method unmodifiableCollection(Collection c). This gives you an unmodifiable view of the input collection c, but any later modifications to c still show up in the “unmodifiable” collection returned. In the same way, after creating a WatchableSet w (my admittedly poorly chosen name) from some Set s, w can unexpectedly change its contents without sending events, if s gets modified.

So the idea was to take a copy of the incoming Set, and use that as the backing instance. If we’re dealing with sorted sets, this becomes a bit problematic: the sort order depends on a Comparator, and this should most definitely be preserved. Thankfully, almost all the Collections classes are Cloneable, and I was willing to accept default behaviour with a big warning in the API for the ones that weren’t.

So I wanted more-or-less the same as SafeCloner above, except that the compile-time requirement of Cloneable input would be replaced by a runtime cast. If either the cast or the clone() failed, the fallback position is to use the copy constructor required for all Collection classes and make a new HashSet. (This simply reads the elements out of the input set and into the new backing instance. So the class always preserves elements into the backing store, and usually preserves ordering as well. An alternative fallback is to keep the input as backing store, guaranteeing the right sort order, but this subverts the whole intention by making the client keep its sticky fingers off the backing instance afterwards, which I wanted to avoid, and makes it even more complicated because this requirement only holds in certain unusual cases.)

Then the problem hit. Because the only possible input type for this constructor is Set. But Set doesn’t guarantee a public clone() method. Neither does Cloneable. Neither does anything useful.

What went wrong?

The problem is, quite unexpectedly, that Java does things too correctly for clone() to fit in. A clone method is fundamentally problematic for a language that enforces the inheritance of published interfaces (in the general sense: “I have these methods,” rather than the specific Java sense of the word).

One of the few places that Java really plays by the book is in the way inheritance affects visibility. If A extends B means “every A is a B,” then any method available on a B should also be available on an A. This is the sort of formal simplication that makes for a clean type theory, but doesn’t always match real-world coding requirements (before Java 1.5, the add() method of javax.swing.JFrame was made effectively private by adding a private enablement check, for instance).

You might have noticed that constructors in Java aren’t inherited the way other methods are. This is a classic example of the failure of this abstraction: a construction method for B does not guarantee the same construction method will successfully produce an A. And cloning suffers precisely the same problems.

The constructor problem was solved by building it into the language, but it’s obviously too late for this to happen for clone(). Instead, the libary designers have chosen to provide the fewest possible inheritable guarantees, so that ambivalent cases don’t end up publishing an interface they (or their subclasses) can’t adhere to.

However this design ignores the existence of runtime checking, which seems perfectly suitable for this problem. We already have a CloneNotSupportedException, and on those unfortunate occasions where B is cloneable but A is not (recall A extends B), A.clone() throws the exception and that is that.

More generally, there is a conceptual problem here with the notion of an “interface”. A Java interface should be an interface in the general sense: a published list of methods that are guaranteed to be applicable. It is not necessarily a guarantee about the effect of calling those methods, and this distinction shows up pretty clearly in this case.

The only sensible published interface for Cloneable is public Object clone(). Anything else makes nonsense of the very word “interface”. (Actually the only sensible interface is public same_class clone() but this is a whole different language quibble.)

Doing it properly

This could actually be retrofitted to the existing libraries without affecting any existing code. Here’s what we need:

package java.lang;
public interface ReallyCloneable extends Cloneable { Object clone(); }

That’s it. And every class that used to implement Cloneable and has a public clone() method now implements ReallyCloneable instead. Everything works the way it used to. And new code can use ReallyCloneable and compile-time check against a public clone(), while those hypothetical private cloners are still implementing only Cloneable and providing no public guarantees.

It’s so simple I almost expect to be told that it’s already been done.

Doing it badly: A dirty hack that solves the problem

And finally, the part of the whole story that actually makes me feel unclean.

We’re going to hack together a little reflection-based class that can do our cloning for us. It’s very small, very simple, and very ugly.

import java.lang.reflect.*;

public class Cloner {
    public static Object doClone(Object o) throws CloneNotSupportedException {
        try {
            Method cloneMethod = o.getClass().getMethod("clone",null);
            return cloneMethod.invoke(o,null);
        } catch(Exception e) {
            Throwable ex = new CloneNotSupportedException("Unsuccessful clone()");
            ex.initCause(e);
            throw ex;
        }
    }
}

Now I’m going to go and wash.