super.clone() puzzlement

J

J. Davidson

Mark said:
Doesn't compile. Check your cut and paste, I found at least one other
syntax error in the code.

What cut and paste? I typed that directly into my news program. I
wouldn't be surprised if it had a typo or two.
 
M

Mark Space

J. Davidson said:
What cut and paste? I typed that directly into my news program. I
wouldn't be surprised if it had a typo or two.

I knew that actually, I was just giving you the opportunity to correct
it. The "typo" I pointer out obviates your argument however. Not the
best way to be taken seriously, imo.
 
J

J. Davidson

Mark said:
The "typo" I pointer out obviates your argument however. Not the
best way to be taken seriously, imo.

I beg your pardon?

I don't think I've done anything that makes me deserve your scorn.

And I don't want any arguments.

Since you apparently do, you shall have to find someone else to have
them with. I won't be posting any further to this post.

- jenny
 
R

RedGrittyBrick

J. Davidson said:
I beg your pardon?

I don't think I've done anything that makes me deserve your scorn.

And I don't want any arguments.

Since you apparently do, you shall have to find someone else to have
them with. I won't be posting any further to this post.

Hello Jenny,

In order to avoid this sort of reaction, when I type untested code into
a usenet/newsgroup posting I usually add the comment "Untested" at the end.

A lot of people active in comp.lang.java.programmer are somewhat abrupt
or blunt at times - I'm pretty sure it is not intended to cause offence.
(http://www.catb.org/~esr/faqs/smart-questions.html#keepcool)

Just my ¤0.02 worth.


You probably know already, but if you separate your signature with the
traditional separator of hyphen hyphen space on a line by itself, most
people's newsreader software will handle it specially. E.g. politely
omitting it from quoted responses.
 
L

Lew

Hello Jenny,

In order to avoid this sort of reaction, when I type untested code into
a usenet/newsgroup posting I usually add the comment "Untested" at the end.

A lot of people active in comp.lang.java.programmer are somewhat abrupt
or blunt at times - I'm pretty sure it is not intended to cause offence.
(http://www.catb.org/~esr/faqs/smart-questions.html#keepcool)

In this case it looks like the problem was that Mark Space politely
pointed out that there was a problem with Jenny's posted code that
"obviated [her] argument", by which I gather it rendered her example
moot. Jenny's response was dismissive, stating the obvious fact that
she had taken no care to transcribe her code accurately and somehow
regarding that as not a problem. Mark Space didn't express any
"scorn" that I can detect; he simply provided the assessment that her
dismissiveness toward an error that undid her point was not likely to
engender helpful responses. Jenny's hostile reaction to that comment
only further harms her ability to elicit useful responses from the
forum.
 
M

Mark Space

J. Davidson said:
Since you apparently do, you shall have to find someone else to have
them with. I won't be posting any further to this post.

Meh. As you like. But if you're going to be so sensitive about coding
mistakes, I don't see how you're going to be able to have any
discussions at all here.
 
T

Tom Anderson

I beg your pardon?

I don't think I've done anything that makes me deserve your scorn.

And I don't want any arguments.

Since you apparently do, you shall have to find someone else to have
them with. I won't be posting any further to this post.

I assume that what Mark meant is that the errors in your code were not
merely superficial, but conceal the fact that it cannot be made to work
even when corrected.

Or rather, i assumed that - once i fixed them, the code compiled, and a
quick test showed it worked.

Mark, in what way did the typo you "pointer" out (helo McKean's Law!)
obviate any arguments? I'm not sure i understand.

Jenny, you can sort-of-simplify your approach like this:

abstract class Baz<T extends Baz<T>> {
protected abstract T copy(T object) ;
protected abstract T self() ;
public T clone() {
return copy(self()) ;
}
}

class Qux extends Baz<Qux> {
private int field;
public Qux(int field) {
this.field = field ;
}
protected Qux copy(Qux object) {
return new Qux(object.field) ;
}
protected Qux self() {
return this ;
}
}

You have to implement two abstract methods, one utterly trivial and one
very simple, but you don't have to define the anonymous class, have a
special interface for it, or have a copier instance attached to every
cloneable instance (although you could singletonify that in your scheme).

This approach intrigues me because the gaping hole i thought i'd
indentified turns out not to work. If you try to write a class that looks
like:

class Xyzzy extends Foo<Foo> {
private int field;
public Xyzzy (int x) {
super(new Copier<Foo> () {
public Foo getCopy (Foo object) {
return SOME INSTANCE OF FOO OR A SUBCLASS OF FOO ;
}
});
field = x;
}
public int getX () {
return field;
}
}

The compiler tells you that "type parameter Foo is not within its bound".
This, i assume, is because an unqualified Foo is not a Foo<T extends
Foo<T>>. You could write:

class Xyzzy extends Foo<Foo<Foo<Foo<Foo<Foo<Foo<you get the idea>>>>>>>

if you had a transfinite text editor, and it would work, but since you
don't, you can't, and it won't.

None of these approaches stop you writing subclasses of the bound classes
(your Bar, my Qux) which don't implement the required plumbing, though -
if you had a class Plugh extends Bar, then new Plugh().clone() would
return a Bar (by static type and runtime class).

tom
 
M

Mark Space

Tom said:
I assume that what Mark meant is that the errors in your code were not
merely superficial, but conceal the fact that it cannot be made to work
even when corrected.

Or rather, i assumed that - once i fixed them, the code compiled, and a
quick test showed it worked.

Mark, in what way did the typo you "pointer" out (helo McKean's Law!)
obviate any arguments? I'm not sure i understand.

Jenny, you can sort-of-simplify your approach like this:

abstract class Baz<T extends Baz<T>> {
protected abstract T copy(T object) ;
protected abstract T self() ;
public T clone() {
return copy(self()) ;
}
}

class Qux extends Baz<Qux> {
private int field;
public Qux(int field) {
this.field = field ;
}
protected Qux copy(Qux object) {
return new Qux(object.field) ;
}
protected Qux self() {
return this ;
}
}

You have to implement two abstract methods, one utterly trivial and one
very simple, but you don't have to define the anonymous class, have a
special interface for it, or have a copier instance attached to every
cloneable instance (although you could singletonify that in your scheme).

This approach intrigues me because the gaping hole i thought i'd
indentified turns out not to work. If you try to write a class that
looks like:

class Xyzzy extends Foo<Foo> {
private int field;
public Xyzzy (int x) {
super(new Copier<Foo> () {
public Foo getCopy (Foo object) {
return SOME INSTANCE OF FOO OR A SUBCLASS OF FOO ;
}
});
field = x;
}
public int getX () {
return field;
}
}

The compiler tells you that "type parameter Foo is not within its
bound". This, i assume, is because an unqualified Foo is not a Foo<T
extends Foo<T>>. You could write:

class Xyzzy extends Foo<Foo<Foo<Foo<Foo<Foo<Foo<you get the idea>>>>>>>

if you had a transfinite text editor, and it would work, but since you
don't, you can't, and it won't.

None of these approaches stop you writing subclasses of the bound
classes (your Bar, my Qux) which don't implement the required plumbing,
though - if you had a class Plugh extends Bar, then new Plugh().clone()
would return a Bar (by static type and runtime class).

tom
 
M

Mark Space

(First, apologies for the previous blank response. Pilot error, again.)

Tom said:
I assume that what Mark meant is that the errors in your code were not
merely superficial, but conceal the fact that it cannot be made to work
even when corrected.

Well first, I don't think you've really addressed the problem either.
Given your code, this does not clone correctly.

class Qux2 extends Qux {
private final String blet = "bargle";
public Qux2() {
super( 42 );
}
}

// example snipette of not working:
Qux2 myQ = new Qux2();
Qux myOtherQ = myQ.clone();

Calling clone on a derived type of Qux doesn't return a clone of the
derived type, it returns a Qux. By contrast, with the default clone()
implementation, it does work correctly.

Example:

class Wvy implements Cloneable {
private final int field;
public Wvy( int field ) {
this.field = field;
}
@Override
public Wvy clone() {
try {
return (Wvy) super.clone();
}
catch( CloneNotSupportedException ex ) {
throw new AssertionError(); // can't happen
}
}
}


class Wvy2 extends Wvy {
private final String blet = "bargle";
public Wvy2() {
super(42);
}
}

// Example snipette of correctly working:
Wvy2 myW = new Wvy2();
Wvy2 myOtherW = (Wvy2)myW.clone();
System.out.println( "myOtherW: " + myOtherW );

Does indeed clone the Wvy2 object, not the parent class. I don't know
what Jenny intended, but your example isn't working.


Second, please lets all take a step back here and think about what is
going on. Derek's original question was "Hey, clone() is a little
counter-intuitive." But the frameworks that you and Jenny are
postulation are far more counter intuitive than clone. Look at the lines
of code I have in Wvy to implement it: one return statement, surrounded
by a try catch that can't happen. Look at what you have: 7 lines of
boiler plate abstract class, and per class: two methods that must be
overridden, and a required constructor. Jenny's was more. That's not a
workable alternative, imo. It's silly.

And my alternative suggestion: Look at a copy constructor. How
complicated is that? To modify your code to use a copy constructor,
this is what I'd have to do:

class Qux {
private final int field;
public Qux( Qux q ){
this.field = q.field;
}
}

Dear Lord, people! It's one frigging line! I mean seriously, did
neither of you see this? It's dead simple too, anyone reading that
would instantly understand it. And I made the field final to illustrate
that this works with final fields.

Both your and Jenny's posts are classic examples of baroque,
overly-ornamented, gold-plated, poor design, and that's ignoring the
fact that neither really works (Jenny's at all, it doesn't compile, and
yours breaks the clone() contract).

Really, I don't see how you could not expect to get called on these
errors, either of you. Clone() is counter-intuitive, but it's not nearly
bad enough to warrant the code you posted, even ignoring the actual errors.
 
Z

zaphod beeblebrox

Mark said:
It's silly.

And my alternative suggestion: Look at a copy constructor. How
complicated is that?

Dear Lord, people! It's one frigging line! I mean seriously, did
neither of you see this? It's dead simple too, anyone reading that
would instantly understand it.

Both your and Jenny's posts are classic examples of baroque,
overly-ornamented, gold-plated, poor design

Clone() is counter-intuitive, but it's not nearly bad enough
to warrant the code you posted, even ignoring the actual errors.

My God. I'd heard somewhere that comp.lang.java.programmer was one of
the rudest places outside of the alt hierarchy and decided to come see
for myself if that was true. I load the headers, view the single
most-recent post in the newsgroup, and bam!

Actually, I've seen alt groups with less derision flying about.
A lot of people active in comp.lang.java.programmer are somewhat
abrupt or blunt at times - I'm pretty sure it is not intended to
cause offence.

I'd hate to see this place if that ever changed --- it might even give
alt.flame a run for its money.

At least the first step has apparently already been taken --- that would
be admitting that there is a problem. :)

I wonder what an office full of you guys would look like.

Wait, why wonder? I happen to have a crystal ball handy:

Day 1: project makes inches of progress, with more time spent insulting
each other than coding.
Day 2: someone's harsh and careless criticisms make some lady programmer
burst into tears and take the rest of the day off
Day 33: boss pokes nose in, finds out that zero milestones have been
reached, small thermonuclear explosion ensues, EMP wipes
computers, back to square 1 --- all three completed lines of code
are lost along with the backup tapes. Offsite backup? You'd been
in the middle of arguing about where in the world to put it when
the boss blew his stack.
Day 41: Lady programmer quits, two other good programmers quit, boss
hires three bad programmers to replace them
Day 61: All three get fired. Net negative productivity.
Day 77: Boss tears out last hair on head, quits. New boss is worse than
the old boss.
Day 78: New boss pulls out inaugural clump of hair. This isn't like
trying to herd cats, it's like trying to herd fucking tornadoes.
Day 147: New boss beginning to resemble a version of Captain Picard with
anger-management issues. First deadline slipping.
Day 312: Project hopelessly late. Bickering has reached the point of
occasional fisticuffs, hurled coffee-cups (usually full of
cold, B-grade coffee), and general abuse. First fatality as
a carpooling group of angry programmers goes off the road into
a tree during a heated debate over which class is responsible
for deallocating foobars.
Day 908: Half of you are now being paid $40 an hour to bicker full-time.
Two of you are dead, one having finally snapped and blown the
other away with a sawed-off before eating it himself.
Day 1,719: The new boss snaps, begins building a mysterious contraption,
stops management. Treacle-like progress screeches to a halt.
Day 1,722: The boss unveils his new invention.
Day 1,723: Janitor arrives to find the place deserted and piles of dust
here and there.
Day 1,729: A coroner's inquest concludes that everyone was disintegrated
by thalaron weapon. Fourth milestone deadline comes and goes.
The project consists of three complete classes, a skeleton of
a fourth one, and a metric ton of UML diagrams scribbled over
in red ink. Corporate HR decides to hire replacements from
comp.lang.python instead of comp.lang.java.
Day 1,730: Microsoft unveils competing product, grabs the entire market.
Corporate VP product development pulls plug.
Day 1,730: Someone finds a security hole in competing product.
Day 1,742: Eighty million computers infected and counting.
Day 1,745: Most of planetary population dead of acute spam poisoning.
Civilization in ruins. Roving bands of warring tribes.
Day 545,907: Some idiot reinvents agriculture and the whole cycle begins
again.
 
T

Tom Anderson

My God. I'd heard somewhere that comp.lang.java.programmer was one of the
rudest places outside of the alt hierarchy and decided to come see for myself
if that was true. I load the headers, view the single most-recent post in the
newsgroup, and bam!

Hey, that's nothing - you should check out the thread where Lew and i are
discussing proper J2EE deployment techniques. We've almost got that one to
the point where we arrange to meet up and hit each other with beer bottles
to settle it once and for all.

Oh, and:
Day 1,729: A coroner's inquest concludes that everyone was disintegrated
by thalaron weapon. Fourth milestone deadline comes and goes.
The project consists of three complete classes, a skeleton of
a fourth one, and a metric ton of UML diagrams scribbled over
in red ink.

Green ink, actually.

And you're obviously an idiot, of course.

tom
 
T

Tom Anderson

Well first, I don't think you've really addressed the problem either. Given
your code, this does not clone correctly.

class Qux2 extends Qux {
private final String blet = "bargle";
public Qux2() {
super( 42 );
}
}

// example snipette of not working:
Qux2 myQ = new Qux2();
Qux myOtherQ = myQ.clone();

Calling clone on a derived type of Qux doesn't return a clone of the
derived type, it returns a Qux.

Yes - as i pointed out in my post. It only works for the immediate
children of the base type.
By contrast, with the default clone() implementation, it does work
correctly.

Quite true. We were talking about ways to do cloning without using the
built-in clone.
Second, please lets all take a step back here and think about what is
going on. Derek's original question was "Hey, clone() is a little
counter-intuitive." But the frameworks that you and Jenny are
postulation are far more counter intuitive than clone. Look at the lines
of code I have in Wvy to implement it: one return statement, surrounded
by a try catch that can't happen. Look at what you have: 7 lines of
boiler plate abstract class, and per class: two methods that must be
overridden, and a required constructor. Jenny's was more. That's not a
workable alternative, imo. It's silly.

I work on a daily basis with a system that requires more boilerplate than
that!

But seriously, i was treating this more as an intellectual exercise - how
can you write a class that forces its subclasses to provide ways to copy
themselves?
And my alternative suggestion: Look at a copy constructor. How complicated
is that? To modify your code to use a copy constructor, this is what I'd
have to do:

class Qux {
private final int field;
public Qux( Qux q ){
this.field = q.field;
}
}

Dear Lord, people! It's one frigging line!

Cool.

So how do you use that to make copies of Baz subclasses without knowing
what class they are?

Let me put it this way - how would you implement:

public Baz clone(Baz obj) {
// your code goes here
}

Where Baz has subclasses, potentially not all known at the point at which
you write this code? Which was the whole point of this exercise.
Both your and Jenny's posts are classic examples of baroque,
overly-ornamented, gold-plated, poor design, and that's ignoring the
fact that neither really works (Jenny's at all, it doesn't compile, and
yours breaks the clone() contract).

Oh yeah, which brings us back to the original point: how do Jenny's typos
obviate her argument? They're minor, and if you fix them (or overlook them
if you're only running this in your mental JVM), her solution successfuly
makes copies.
Really, I don't see how you could not expect to get called on these errors,
either of you.

I didn't make any errors. You've misunderstood the intent of my post, and
i suspect of Jenny's.

Also, your solution doesn't work.

Also, you're funny-looking, and i heard you have the lurgey.

tom

PS The last line was a joke.
 
L

Lew

Tom said:
Hey, that's nothing - you should check out the thread where Lew and i
are discussing proper J2EE deployment techniques. We've almost got that
one to the point where we arrange to meet up and hit each other with
beer bottles to settle it once and for all.

I thought it was to meet up and *buy* each other bottles of beer. Man, did I
ever misunderstand that.

But if you're ever in my neck of the woods, Tom, meet me and I'll buy you a beer.
 
M

Mike Schilling

Lew said:
I thought it was to meet up and *buy* each other bottles of beer.
Man, did I ever misunderstand that.

But if you're ever in my neck of the woods, Tom, meet me and I'll
buy
you a beer.

In a platic cup.
 
Z

zaphod beeblebrox

Tom said:
PS The last line was a joke.

I hope this is also true of the post that called me an idiot.

So is Usenet. Particularly comp.lang.java.programmer.

The misspelling of "occurrences" being just one of them.
 
M

Mark Space

Tom said:
Where Baz has subclasses, potentially not all known at the point at
which you write this code? Which was the whole point of this exercise.

Well, I thought the point of this exercise was to get something that
actually works properly. So far no one's come up with anything to force
any particular semantics on a programmer. The closest I've seen is the
default clone() implementation, which at least does (shallowly) copy
child classes.

The comment about copy constructors was meant as an alternative to
clone(), not a drop in replacement.

I didn't make any errors. You've misunderstood the intent of my post,
and i suspect of Jenny's.

Possibly. "Idle banter" seems to describe it, not anything seriously
related to programming. And I mean that seriously, I think the two you
were just making chit-chat while I was looking for some sort of rigorous
solution.

Thinking about this a bit more, I think your solution simplifies to:

class Baz3 {
private final int field;
Baz3( Baz3 b ) { field = b.field; }
public Baz3 clone() { return new Baz3( this ); }
}


That abstract base class just not needed at all.

My conclusion: There is no "good" solution. Implement clone()
correctly, and document exactly what the semantics are so future child
classes can implement them correctly. Or make the class final.
 
T

Tom Anderson

All part of the bottlefight masterplan!
In a platic cup.

:)

I was chatting to a pub landlord a few months ago. I'd stopped off at his
pub on a bike ride, to get a drink. I said i wanted to drink it outside,
and expected him to give me a plastic glass. He didn't - i got real glass.
I asked him about this, and he said he thought it was better to use glass
than plastic. Partly because he doesn't like plastic cups himself, but
also because they're actually *more* dangerous in fights - you can easily
break a plastic cup to make some flimsy but really quite sharp shards,
with which you could cut someone or poke an eye out, but since bar glasses
are made of toughened glass, if you smash one of those, it just fragments
into a thousand pieces, none of which are any use as weapons (unless your
enemy is a bicycle tyre). This idea of breaking a glass or bottle and
using it as a weapon is, apparently, purely a figment of Hollywood's
imagination.

tom
 
T

Tom Anderson

I hope this is also true of the post that called me an idiot.

I don't know. Did i write that one? Were you an idiot at the time?
So is Usenet. Particularly comp.lang.java.programmer.

That reminds me of another sig.
The misspelling of "occurrences" being just one of them.

If i ever find the author of the post i quoted that from, i'll be sure to
tell them.

tom
 
T

Tom Anderson

Tom said:
Where Baz has subclasses, potentially not all known at the point at
which you write this code? Which was the whole point of this exercise.

Well, I thought the point of this exercise was to get something that
actually works properly. [...] The comment about copy constructors was
meant as an alternative to clone(), not a drop in replacement.

How is it an alternative? Here's the situation:

abstract class Foo {
public Foo clone() {
// ?
}
}

class Bar extends Foo {
private int x ;
public Bar(int x) {
this.x = x ;
}
}

class Baz extends Foo {
private float y ;
public Baz(float y) {
this.y = y ;
}
}

The goal is to implement Foo.clone() such that it returns a copy of the
objects it's called on. You can add anything you like to any of the
classes to do this.

This is the problem that was under discussion. I don't see how copy
constructors help here.
Possibly. "Idle banter" seems to describe it, not anything seriously related
to programming. And I mean that seriously, I think the two you were just
making chit-chat while I was looking for some sort of rigorous solution.

I'd certainly be interested to see your rigour applied to the above
problem.
Thinking about this a bit more, I think your solution simplifies to:

class Baz3 {
private final int field;
Baz3( Baz3 b ) { field = b.field; }
public Baz3 clone() { return new Baz3( this ); }
}

That abstract base class just not needed at all.

Not if you only have one class to clone, no. But that's not the case.

tom
 

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,786
Messages
2,569,625
Members
45,320
Latest member
icelord

Latest Threads

Top