views:

452

answers:

5

I'm maintaing an older Java code base (jvm 1.4) that seems to use cloning as an alternative to object instantiation, I'm guessing as a performance optimization. Here's a contrived example:

public class Foo {
  private SomeObject obj; // SomeObject implements Cloneable
  public Foo() {
    obj = new SomeObject();
    obj.setField1("abc"); // these fields will have the same value every time
    obj.setField2("def");
  }
  public void doStuff() {
    SomeObject newObj = obj.clone(); // clone it instead of using a factory method
    // do stuff with newObj
  }
}

The usual caveats about premature optimization notwithstanding, was this actually a recommended idiom at some point?

+3  A: 

Presumably they wanted a copy. Perhaps they want to pass it to another function, and can't be sure that that function won't change it. It's a way of making sure that the method doStuff() is const with respect to the state of the Foo object it's called on.

Lou Franco
Bumping this up +1 'cause (after looking at the code) it's appears as or more likely to apply than my more esoteric answer.
MarkusQ
Note that this is the primary purpose of cloning (assuming my professors knew what they were talking about).
Chris
+1: Yup, it seems here `.clone()` is the Javaish way of pass-by-value.
Steve Schnepp
Yes, but the question asks why the code author chose to use clone() instead of alternative ways to create a copy such as through a copy constructor or factory method.
Derek Mahar
@Derek Mahar: A properly-designed clone method will return an object of the same type as the original. Neither a copy constructor nor a factory method can do either of those things unless a type supports an overridable function to return a factory that will return objects of its own type.
supercat
+1  A: 

It may be a performance optimization, depending on how much work is done in the constructors.

It's more likely used because the semantics are different. Cloning provides a way to implement "prototype semantics" (like in javascript, self, etc.) in a language that doesn't normally tend that way.

MarkusQ
How so? I though prototype semantics just meant you could alter the behaviour of the constructor or other fields or methods at runtime.
sk
Cloning lets you set initial values, etc. and (by using delegates) change behavior as well. It is kind of a kludge, but you don't generally full blown Self-style semantics, just a little of the juice, so it often works in practice.
MarkusQ
A: 

If the SomeObject constructor does expensive work, such as grabbing something from a database or parsing something, or reading something from a file then the clone would make sense to avoid doing the work.

If the constructor does nothing then there really is no need to use clone.

Edit: added code to show that clone does not have to do the same work as the constructor:

class Main
    implements Cloneable
{
    private final double pi;

    public Main()
    {
        System.out.println("in Main");
        // compute pi to 1,000,000,000 decimal palaces
        pi = 3.14f;
    }

    public Object clone()
    {
        try
        {
            return (super.clone());
        }
        catch(final CloneNotSupportedException ex)
        {
            throw new Error(); // would not throw this in real code
        }
    }


    public String toString()
    {
        return (Double.toString(pi));
    }

    public static void main(String[] args)
    {
        final Main a;
        final Main b;

        a = new Main();
        b = (Main)a.clone();

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

The Main construtor is called once, the computing pi is performed once.

TofuBeer
if you are going to mark something down at least comment on what you feel is inaccurate about it!
TofuBeer
If the copy constructor did expensive work, then clone would have to do the same.
Tom Hawtin - tackline
clone bypasses the constructor - how do you get it would have to do the same?
TofuBeer
@Tom, yes you could do it with a copy constructor instead of calling super.clone... but if it did expensive work instead of a simple copy AND the work wasn't required then it would be poorly coded.
TofuBeer
+1  A: 

One reason to invoke clone() instead of the copy constructor or a factory method is that none of the other options may be available.

Implementing clone() to perform a shallow object copy (deep copy is more involved) is trivial compared to implementing a copy constructor or a factory method to perform the same operation. To implement clone(), a class need simply implement the Cloneable interface and override method clone() with one that invokes super.clone() which usually invokes Object.clone(). Object.clone() copies every property of the original object into the corresponding property of the duplicate, thus creating a shallow copy.

Though implementing clone() is straightforward, it is still easy to forget to implement Cloneable. Consequently, a potential risk of using clone() to duplicate an object is that if the class of that object does neglect to implement Cloneable and clone() invokes Object.clone() either directly or indirectly, it will throw CloneNotSupportedException.

See this code example and a previous discussion on the poor design of the Cloneable interface.

Derek Mahar
A: 

Am I missing the answer that they probably want to have referential access to the object path underneath through the multiple "instances?"

Xepoch
Woops, that's what you get when you forget to click "answer" for a long time. Nothing to see here :)
Xepoch