Why not cloneable by default?

T

Thomas G. Marshall

Chris Uppal coughed up:
Thomas said:
Does anyone know why the java designers didn't make every object
shallow-cloneable by default?

I'm coming late to this thread, but FWIW I think this is simply an
error in the Java design. Remember that it comes from the same
timeframe as 'synchronized' StringBuffer [...]

Huh, you've raised my interest in this example. To what are you referring
re: StringBuffer? (I honestly don't know---sounds intriguing)...

and many other design errors (or sub-optimalities).

I think an argument could be made that clone() /shouldn't/ be exposed
by default, on the grounds that the semantics of copying are
complicated and context-dependent (so one size doesn't fit all), and
that the clone() peroration should therefore be something you
opt-into when (and only when) you have understood what copying means
for some object.

The problem with that argument is that it (or something more-or-less
similar) could also apply to Object.equals() and in fact all of the
other methods of Object (except maybe toString()).

Well put.
 
A

Antti S. Brax

(e-mail address removed) wrote in comp.lang.java.p
Antti S. Brax coughed up:

That doesn't answer the question. Having a Object.clone() is something that
/all/ subclasses could use, not just Object.

That answers to the exception throwing part in "Why does
java.lang.Object provide a clone method which doesnt do
anything beside throwing an exception?".

When you've defined a subclass that implements Cloneable
the rest of the answer becomes obvious.
There is a layer of protection that they felt necessary here, but it has
nothing to do with no reason to clone Object (non subclassed) instances.

The idea is that if Object was defined Cloneable then every
object in Java would have to be cloneable or explicitely
defined as "not cloneable". Programmers would forget to mark
their objects as not cloneable and not bother to maker sure
cloning wouldn't break something and Java would become just
as insecure and error prone as C is.
 
J

John C. Bollinger

Alexander said:
Of course, but why does it provide the method at all?

Because in order to successfully clone an object of any class (as
cloning is defined in Java), you need to be able to get at the internals
of the Object class. Since doing so is quite appropriately reserved for
class Object itself, clone() must be provided by Object if any other
class is to use / expose it.

[...]
I'd have assumed this is obvious! Just as ALL other such implementations
are done in Java.

Each class which wants to support cloning should implement
java.lang.Cloneable which would introduce clone() and then you can know
for sure that each class derived from java.lang.Cloneable supports cloning.

Cloning is a peculiar beast in Java. It could have been implemented as
you describe, but it could not in that case have been defined quite the
same way as it is now. There are certainly some aspects of the chosen
design that are very convenient, but agreed, the design is a bit funky.
 
T

Tim Tyler

Antti S. Brax said:
The idea is that if Object was defined Cloneable then every
object in Java would have to be cloneable or explicitely
defined as "not cloneable". Programmers would forget to mark
their objects as not cloneable and not bother to maker sure
cloning wouldn't break something and Java would become just
as insecure and error prone as C is.

A lot of Java's security arises not from preventing programmer error -
but from making it impossible for programmer error (or a malicious
programmer) to damage the user's system - by permitting execution to
take place in a sandbox.

It takes a lot of effort to make something as insecure as C/C++ is ;-)
 
C

Chris Uppal

Thomas said:
[...] 'synchronized' StringBuffer [...]

Huh, you've raised my interest in this example. To what are you referring
re: StringBuffer? (I honestly don't know---sounds intriguing)...

Oh, I was just thinking of the performance problems that used to be caused by
the fact that java.lang.StringBuffer is internally synchronised. You probably
remember those days, just didn't recognise my rather too elliptic reference to
them ;-)

Anyway, for anyone who doesn't remember the old days: Given that
StringBuffer's thread-safety is almost never needed (very very few
StringBuffers are accessed by multiple threads, and probably none are without
an additional layer of mutex protection), and given that they tend to be
heavily used (to the point where their efficiency can determine that of the
application) and given that synchronisation had a fairly high overhead, the
internal synchronisation came to be seen as a fairly major mistake. It's not
an issue now -- machines are faster, JVMs are faster, the synchronisation
primitives have much less overhead, and (as of Java 5) the StringBuffer class
is essentially obsolete anyway -- but it was quite a notorious "feature" at the
time. I remember an early Java experience paper about implementing the first
(known) pure-Java HTTP server; the authors spent (what in retrospect seems)
about half the paper lamenting the "StringBuffer problem" which prevented their
implementation beating the performance of Apache -- at least until they'd
completely re-written the String handling...

No big deal; I just wanted to include at least /one/ example to bolster a
sentence containing the words "and many other design errors", and that was the
first that came to mind.

BTW, Thomas, I've just noticed that you started this thread cross-posted to
c.l.j.advocacy. I've no complaints, but I am curious to know why you choose to
include an advocacy group ?

-- chris
 
B

Bent C Dalager

Cloning is a peculiar beast in Java. It could have been implemented as
you describe, but it could not in that case have been defined quite the
same way as it is now. There are certainly some aspects of the chosen
design that are very convenient, but agreed, the design is a bit funky.

Can you point at a good reason why I should have to use reflection to
get to the clone() method of an object of unknown type? This seems to
me to be the most unfortunate side effect of the current clone
implementation.

That is, I cannot do:

Object ob = ....;
if (ob instanceof Cloneable)
{
Object clone = ((Cloneable) ob).clone(); //doesn't compile
// do something with the clone
}

In stead I have to use reflection to get to the clone method. This
seems needlessly complicated and error-prone.

It is also somewhat ironic in that using a virtual clone() method is
_supposed_ to avoid one of the annoying drawbacks of using copying
constructors; namely that of having to know the run-time type of the
object to be cloned when writing the code. The only obvious way to
avoid having to use reflection to clone an object in Java is just
that; to know the run-time type of the object to clone as you write
the code. (Of course, copying ctors have more serious flaws than this,
but still.)


I like to think that there is some reason I am not aware of that this
is a useful feature :)

Cheers
Bent D
 
T

The Ghost In The Machine

In comp.lang.java.advocacy, Thomas G. Marshall
<[email protected]>
wrote
These are grossly oversimplified statements, and do not reflect an
understanding of the issue.

Especially since clone(), like all methods not tagged 'final',
is overridable in a subclass.

One can envision walking a collection and having some clone methods
fail and some succeed. (With the new collections there might
be safer typechecking but I'd frankly have to look. Of course
if the list has all its elements from a clone()able
class or base class an exception may not need to be caught.)
 
T

Tor Iver Wilhelmsen

Chris Uppal said:
No big deal; I just wanted to include at least /one/ example to
bolster a sentence containing the words "and many other design
errors", and that was the first that came to mind.

There is also Observer/Observable, never used for much and "scrapped"
in 1.1 for the new delegate event model (which is an implementation of
the Observer pattern).
 
T

Tor Iver Wilhelmsen

John C. Bollinger said:
Because in order to successfully clone an object of any class (as
cloning is defined in Java), you need to be able to get at the
internals of the Object class. Since doing so is quite appropriately
reserved for class Object itself, clone() must be provided by Object
if any other class is to use / expose it.

Counterpoint: System.arrayCopy() was not moved from System to Arrays
when that class was introduced in 1.1. Sun could just as easily have
added System.shallowCopy(Object) instead of having clone() in Object.
 
J

John C. Bollinger

Bent said:
Can you point at a good reason why I should have to use reflection to
get to the clone() method of an object of unknown type? This seems to
me to be the most unfortunate side effect of the current clone
implementation.

Because Object.clone() is protected, you mean? If you give me a good
reason why you should be enabled to invoke clone() at will on an object
of unknown type, then I'll freely admit that having to use reflection to
do so is indeed very unfortunate.
That is, I cannot do:

Object ob = ....;
if (ob instanceof Cloneable)
{
Object clone = ((Cloneable) ob).clone(); //doesn't compile
// do something with the clone
}

In stead I have to use reflection to get to the clone method. This
seems needlessly complicated and error-prone.

But in what context do you actually need to do that? If all you know
about an object is that it is Cloneable, then what business do you have
clone()ing it, and what use do you have for the clone? I can think of
one or two answers to that, but usually (I assert) the answers are
"none" and "none".
It is also somewhat ironic in that using a virtual clone() method is
_supposed_ to avoid one of the annoying drawbacks of using copying
constructors; namely that of having to know the run-time type of the
object to be cloned when writing the code. The only obvious way to
avoid having to use reflection to clone an object in Java is just
that; to know the run-time type of the object to clone as you write
the code. (Of course, copying ctors have more serious flaws than this,
but still.)

Whether a class provides for instances to be cloned is controlled in
Java with finer granularity than just yes / no. By implementing
Cloneable but leaving the clone() method protected, a class can restrict
cloning to only subclasses and other classes in the same package. This
can be a good thing. On the other hand, any class or interface that in
fact exposes a public clone() method provides the benefit that you
describe for itself and all its subtypes. That there is no standard
interface by which to describe this (e.g. WidelyCloneable) is a separate
issue.

You do not need to know the specific runtime type of an object to
clone() it, but you do need to know _something_ about its type. The
argument then reduces to whether knowing that the type is Cloneable
ought to be enough. It might perhaps have been better if it were, but I
am not convinced one way or the other.
 
B

Bent C Dalager

Because Object.clone() is protected, you mean? If you give me a good
reason why you should be enabled to invoke clone() at will on an object
of unknown type, then I'll freely admit that having to use reflection to
do so is indeed very unfortunate.

The issue came up when I was writing a GUI support library that
intended to, among other things, automate copy/paste and drag/drop of
tree nodes between different trees. This was intended to work on any
tree that followed a set of contract requirements that would differ
depending on which features you needed.

To achiece this, I wanted to implement a piece of code that could make
copies of a tree node with an arbitrary user object (using
DefaultMutableTreeNode-based nodes). The contract was such that if the
user object was either Cloneable or Serializable, a copy/paste
operation would default to creating a copy of the user object in the
new node. If it was neither, then the new tree node would retain the
same user object reference as the original node.

Since cloning a user object about which the only thing I knew was that
it was Cloneable would involve reflection, however, I ended up
defining an interface Copyable or somesuch that contained a public
clone() in stead.

An alternative would have been to require the client code to provide a
cloner method for its user objects.

Both solutions seem like they should be unnecessary.
But in what context do you actually need to do that? If all you know
about an object is that it is Cloneable, then what business do you have
clone()ing it, and what use do you have for the clone? I can think of
one or two answers to that, but usually (I assert) the answers are
"none" and "none".

In addition to knowing that it is Cloneable, I may also know the
context in which it was used and I may know what it is other pieces of
code are expecting me to do with it. This may be enough to give me a
need to clone it if at all possible.

Cheers
Bent D
 
J

John C. Bollinger

Tor said:
Counterpoint: System.arrayCopy() was not moved from System to Arrays
when that class was introduced in 1.1. Sun could just as easily have
added System.shallowCopy(Object) instead of having clone() in Object.

I have always considered arrayCopy()'s presence on System to imply that
it may make use of underlying implementation details of the VM to
perform its task more efficiently. I would not make the same inference
if the method were on the Arrays class instead.

As for the hypothetical System.shallowCopy(), I agree that System would
be a reasonable place to place a method of that description, and
acknowledge that such a method would relieve the erstwhile necessity of
a protected Object.clone() to enable cloning. It would not, however,
enable classes to exert the same degree of control over their
clonability that the current arrangement does. As I wrote elsewhere in
this thread, the current implementation provides finer-grained control
than just cloneable / not cloneable, and I assert that there is some
value in that. Enough value to support the current implementation over
all alternatives? I'm not certain, but I have yet to see a
comprehensive description of an alternative implementation that I would
prefer.
 
T

Thomas G. Marshall

Chris Uppal coughed up:

....[rip]...
BTW, Thomas, I've just noticed that you started this thread
cross-posted to c.l.j.advocacy. I've no complaints, but I am curious
to know why you choose to include an advocacy group ?


Honestly, two reasons.

1. Advocacy is chartered for support and criticism of the java system at
large, as listed below. This means different things to different people,
but a design flaw or questionable restrictions seems to fall at least
somewhat into that category.

2. I feel bad for that group, since it seems to be lacking posts of late.

For yucks, here is the official (java) list with explanations as of
15-Mar-05, as posted monthly in news.announce.newgroups post "List of Big
Eight Newsgroups":

comp.lang.java.3d 3D Graphics API's for the Java language.
comp.lang.java.advocacy Support for and criticism of the Java System.
comp.lang.java.announce Announcements re the Java System. (Moderated)
comp.lang.java.beans Java software components (JavaBeans).
comp.lang.java.corba Topics relating to Java and CORBA.
comp.lang.java.databases Databases, java.sql, JDBC, ODBC.
comp.lang.java.gui GUI toolkits and windowing: AWT, IFC etc.
comp.lang.java.help Set-up problems, catch-all first aid.
comp.lang.java.machine JVM, native methods, hardware.
comp.lang.java.programmer Programming in the Java language.
comp.lang.java.security Security issues raised by Java.
comp.lang.java.softwaretools IDEs, browsers, compilers, other tools.





--
"This creature is called a vampire. To kill it requires a stake
through its heart." "I shall drive my staff deep into its rump."
"No no, this creature is from a dimension where the heart is in the
chest." "....Disgusting."

Demons discussing "Angel", a good vampire from our dimension visiting
theirs.
 
V

Vincent Cantin

No. /never need/ is *radically* different to /never should be/. If most
objects *should* *never* *be* cloned, then you would be right---we would
be forced to turn off specifically every class we make.

But "never need to be cloned" per se does not matter in the least.

Singletons *should never be cloned*.
 
T

Thomas G. Marshall

Vincent Cantin coughed up:
Singletons *should never be cloned*.

There are all kinds of classes that should never be cloned. What's your
point?



--
Enough is enough. It is /not/ a requirement that someone must google
relentlessly for an answer before posting in usenet. Newsgroups are
for discussions. Discussions do /not/ necessitate prior research. If
you are bothered by someone asking a question without taking time to
look something up, simply do not respond.
 
T

Thomas G. Marshall

John C. Bollinger coughed up:

....[rip]...

[...] If you give me a good
reason why you should be enabled to invoke clone() at will on an
object of unknown type, then I'll freely admit that having to use
reflection to do so is indeed very unfortunate.

Imagine a special collection with a method that takes arbitrary objects, but
copies them before storing them internally. Such a collection would be
useful when you need to store a snapshot of an object's state in a
collection when that object's state is continually in flux.

....[rip]...



--
Enough is enough. It is /not/ a requirement that someone must google
relentlessly for an answer before posting in usenet. Newsgroups are
for discussions. Discussions do /not/ necessitate prior research. If
you are bothered by someone asking a question without taking time to
look something up, simply do not respond.
 
C

Chris Uppal

John said:
Because Object.clone() is protected, you mean? If you give me a good
reason why you should be enabled to invoke clone() at will on an object
of unknown type, then I'll freely admit that having to use reflection to
do so is indeed very unfortunate.

Because the meaning and appropriateness of the copy operation is more usually
determined by the context in which the object appears than by its physical
class.

FWIW (and since it's a while since I last mentioned Smalltalk ;-) in the system
I spend more time with than I do Java, the equivalent of clone() is not
restricted and I've never heard of any problems caused by inappropriate copying
(that could have been solved by class-based restriction).

-- chris
 
T

Tony Morris

Thomas G. Marshall said:
Does anyone know why the java designers didn't make every object
shallow-cloneable by default?

I understand the implications of cloning something overly hefty, and to be
cautious about such things, but it still seems a little overboard to me to
err on the side of turning if off.

Turning it off could easily have been accomplished by implementing something
called:

public interface NotCloneable {}

In fact, I might have allowed two methods, deep within Object:

public Object shallowClone()

and

public Object deepClone()

Now deep cloning is of course fraught with peril, and I am normally very
much in favor of the safety restrictions in the java language, but I'm not
sure this is the kind of thing that java should protect against.

The fundamental flaw in your question is that you have tried to apply logic
to the reasoning of the initial authors of the broken (an understatement)
cloning mechanism built into the language and API.
Kind of like asking why terrorists kill innocent people, or why fat people
keep eating cheeseburgers despite acknowledgement that it will harm them
more.
 
J

John C. Bollinger

Thomas said:
John C. Bollinger coughed up:
[...] If you give me a good
reason why you should be enabled to invoke clone() at will on an
object of unknown type, then I'll freely admit that having to use
reflection to do so is indeed very unfortunate.


Imagine a special collection with a method that takes arbitrary objects, but
copies them before storing them internally. Such a collection would be
useful when you need to store a snapshot of an object's state in a
collection when that object's state is continually in flux.

I acknowledge that such a collection might be useful, but I deny that
such a collection would be safe or appropriate to use in the general
case. Some classes' nature is simply inconsistent with cloning
(singletons / multitons, for instance). Many classes could be safely
cloned, but only if they cooperated. In your example, for instance, if
I want to preserve a state snapshot then the shallow clone provided by
Object.clone() is insufficient for mutable objects that hold references
to other mutable objects.

No, I remain convinced that Java's cloning mechanism is right to give
classes control of whether or not their instances can be cloned, and of
how. There is still plenty of room to debate the details, but I'm not
prepared to support a design that involves a general purpose,
clone-anything-you-want-to mechanism.
 
J

John C. Bollinger

Chris said:
John C. Bollinger wrote:




Because the meaning and appropriateness of the copy operation is more usually
determined by the context in which the object appears than by its physical
class.

I assert that at least sometimes, a class is fundamentally inconsistent
with cloning. As I responded to Thomas, a Singleton / Multiton class
would be an example (though true singletons and multitons are admittedly
rare). I also think that the barriers to using clone() in Java make
programmers put some thought into using it, and that that's a good thing.
FWIW (and since it's a while since I last mentioned Smalltalk ;-) in the system
I spend more time with than I do Java, the equivalent of clone() is not
restricted and I've never heard of any problems caused by inappropriate copying
(that could have been solved by class-based restriction).

I'm trying to think on a general OO level here and to apply it to Java,
so I appreciate your Smalltalk-based observation. I'm not sure that I'm
happy giving much weight to negative anecdotal evidence like that,
however. Do you disagree with my claim that some classes are inherently
inconsistent with cloning?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top