Re: super.clone() puzzlement



Mark Space wrote:
Where I think copy constructors are better:

1. Semantics better defined that clone().

2. Able to use final fields which hold objects with internal state. (In other words, if you need to do a deep copy with clone, you can't use a final field for that variable. With a copy constructor, you can use a final field just fine.)

3. Easier for programmers to understand and get right.

This doesn't mean copy constructors are always better, but you should consider them. If your design can make do with just copy-ctors and forgo clone(), then you probably should.

Why not have your cake and eat it too?

private (or whatever) Foo (Foo toCopy) {
this.fieldX = toCopy.fieldX;
this.fieldY = toCopy.fieldY;
this.fieldZ = toCopy.fieldZ.clone();
this.fieldW = new Bar(toCopy.fieldW);
}

public Foo clone () {
return new Foo(this);
}

Doesn't work to properly copy Foo subclasses though.

But maybe this does:

public interface Copier<T> {
T getCopy (T object);
}

public abstract class Foo<T extends Foo<T>> {
private Copier<T> copier;

protected Foo (Copier<T> copier) {
this.copier = copier;
}

@SuppressWarnings("unchecked");
public T clone () {
return copier.getCopy((T)this);
}
}

public class Bar extends Foo<Bar> {
private int field;

public Bar (int x) {
super(new Copier<Bar> () {
public Bar copy (Bar object) {
return new Bar(object.field);
}
});
field = x;
}

public int getX () {
return field;
}
}

One "curiously recurring template pattern", one @SuppressWarnings("unchecked"), and one subclass that can copy itself.

Of course, this may still run into problems if you make subclasses of subclasses. At least the type parameters can get hairy. Even then you could just dump the generics and leave clone to return Object and callers to cast.

public abstract class Baz <T extends Baz> extends Foo<T>, perhaps?

I seem to remember this kind of thing eventually confusing the compiler. The 1.5 compiler anyway. Maybe 1.6 is better able to deal with this sort of thing.

Oh, and as for someone else's suggestion of a ValueCopier, you could make a generic ValueCopier for everything Serializable. Simplest is to use File.createTemporaryFile, ObjectOutputStream, and ObjectInputStream. Disk I/O is avoided by using ByteArrayOutputStream wrapped with ObjectOutputStream, along with ByteArrayInputStream. It might also be possible to use nio channels to create a sort of pipe. The lack of multiple inheritance in Java makes it tricky but you can make a class that contains an ArrayList<Byte> and has getInputStream and getOutputStream methods that furnish inner class instances, one which appends to the ArrayList at one end, and the other that consumes from the other end and blocks if need be. You'd need to fiddle around with synchronized, wait, and notify, and might want to use ArrayDeque instead of ArrayList. The advantage over ByteArray streams is in memory use if copying a very large object, assuming your ValueCopier<Serializable> spawned a parallel thread to writeObject while the main thread did the readObject and you got all your synchronization ducks in a row on your DequeStream, or whatever you called it.

Now look what I've done. I've found a use in Java for the "curiously recurring template pattern", which someone just said didn't work in Java; I've found a real use for concurrency on single-core machines for a task that doesn't involve network or disk I/O; and I've gone and solved some other problems.

I thought I might even have found a need for @SuppressWarnings("unchecked") that doesn't involve interfacing to nongeneric legacy code, but I guess I haven't really, since clone isn't generic and Object isn't generic. (Imagine if they'd had Object parametrized by the run-time class of the actual object, like Foo is above; Java might have been very different and not just in the clone method.)

- jenny
.



Relevant Pages

  • Re: copy constructor question
    ... mark wrote: ... That problem doesn't arise in Java, ... programmers in C++ also use copy constructors to explicitly ... and there is a way to deal with it: the clone() method. ...
    (comp.lang.java.programmer)
  • Re: AspectJ: solution to Javas repetitiveness?
    ... clone this object, clone its every field. ... Even C++ creates copy constructors with this semantics for you. ... I worked with an extraordinarily smart fellow a year ago, who came to Java ...
    (comp.lang.java.programmer)
  • Re: 1352 NUL bytes at the end of a page? (was Re: Assertion `s && s->tree failed: The sag
    ... >> tests to the script to see if things are really slowing down with current kernels, ... > Are you sure the IDE disks are in DMA mode? ... time bk clone -qlr40514130hBbvgP4CvwEVEu27oxm46w testing-2.6 foo ...
    (Linux-Kernel)
  • Re: Annoying 1.5 warnings
    ... Clone is a broken API in the context of Java 1.5, ... collections APIs take. ...
    (comp.lang.java.programmer)
  • Re: Programming
    ... c# is a clone of java (not by the api but by syntax.. ... it being expressed how things are being implemented in the clr. ... a major diffrence in the syntax.. ...
    (comp.lang.java.programmer)