Topic: standard 'clone' method?


Author: hoshi@sra.co.jp (Hoshi Takanori)
Date: 08 Feb 1995 02:03:23 GMT
Raw View
In article <russgold-0102952353040001@slip-19.netaxs.com> russgold@netaxs.com (Russell Gold) writes:

> My apologies if this has already been suggested, but I would like to see
> some kind of standard 'clone' function for all classes:

Your `clone' function must be virtual, and if every class have one,
every class has a virtual function.  This may cause another problem.

hoshi




Author: deef@teleport.com (Derek Foster)
Date: 7 Feb 1995 21:22:14 -0800
Raw View
In <D3GKJC.MnG@world.std.com> tob@world.std.com (Tom O Breton) writes:

>russgold@netaxs.com (Russell Gold) writes:

>It's trivial to do in a header as well. It's easy to write:

>#define         clone_method( type )\
>        type*   virtual type::clone( void ) { return new type( *this ); };

>As a macro, it invites collisions. A real but minor nuisance.

Also, it is quite easy to forget to include the 'clone_method' invocation
in a derived class, which is very difficult to detect, and may provide
surprising results at runtime, since the base class' cloning function will
be used, 'slicing' off the derived parts. Dangerous.

I'm not sure whether the language allows this, but something along the
lines of:

#define         clone_method( type )\
        type*   virtual type::clone() const = 0; \
        type*   virtual type::clone() const { return new type( *this ); };

would be better, declaring the function pure virtual, but defining it
anyway, so that all derived classes are forced to redefine the function.

>Alternatively, it could be a template, which appears to lose the
>advantage of not associating the "wrong" type with the class, though I
>could be mistaken.

Unfortunately, it also loses the ability to clone a class when given only a
pointer to its base, which is what the original poster was after.

Derek Riippa Foster
--
deef@teleport.com  Public Access User --- Not affiliated with TECHbooks
Public Access UNIX and Internet at (503) 220-1016 (2400-14400, N81)




Author: tob@world.std.com (Tom O Breton)
Date: Thu, 9 Feb 1995 05:23:09 GMT
Raw View
deef@teleport.com (Derek Foster) writes:
> Also, it is quite easy to forget to include the 'clone_method' invocation
> in a derived class, which is very difficult to detect, and may provide
> surprising results at runtime, since the base class' cloning function will
> be used, 'slicing' off the derived parts. Dangerous.

Yes, I realized after I posted that what I said would not protect
against the biggest error, inheriting the method.

There are schools of thought that say that the non-abstract part of a
hierarchy should only be 1 level deep, which would eliminate that
problem. Not that that's my solution -- IMO composition is still useful.


> I'm not sure whether the language allows this, but something along the
> lines of:
>
> #define         clone_method( type )\
>         type*   virtual type::clone() const = 0; \
>         type*   virtual type::clone() const { return new type( *this ); };
>
> would be better, declaring the function pure virtual, but defining it
> anyway, so that all derived classes are forced to redefine the function.

The language doesn't allow it, but I think something along those lines
would be the most general and sleekest solution: Something very like the
pure specifier that means "you derived classes must override this one
but this class can still be constructed."

Perhaps the syntax:

        type*   virtual type::clone() const = 1;

This should put no further burden on parsing, and minimal burden on
typechecking since it mostly piggybacks on the pure virtual mechanism.

I would not want it to force _all_ derived classes to redeclare, since
sometimes you might want to stop part-way up the hierarchy.

> Unfortunately, it also loses the ability to clone a class when given
> only a pointer to its base, which is what the original poster was after.

How so?

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: dak@cae.ca (Pierre Baillargeon)
Date: Tue, 7 Feb 1995 14:40:41 GMT
Raw View
Matt Austern (matt@physics2.berkeley.edu) wrote:
: In article <russgold-0102952353040001@slip-19.netaxs.com> russgold@netaxs.com (Russell Gold) writes:

: > My apologies if this has already been suggested, but I would like to see
: > some kind of standard 'clone' function for all classes:

: It won't happen.

: The reason it won't happen is that this functionality would only be
: possible for polymorphic classes---i.e., classes that have dynamic
: type information.

Not at all...

: As it stands, classes that have no virtual functions may be treated
: specially; it's possible to optimize them so that they have no more
: overhead than C structs.  Forcing every class to be a polymorphic
: class would make that optimization impossible.

The clone function does not have to be virtual (especially in the way
defined in the original post), if the type of the object is known at
compile time at the clone call, it can be compiled statically.  No
overhead here.




Author: Alan@doughnut.demon.co.uk (Alan Bellingham)
Date: Fri, 3 Feb 1995 21:19:43 +0000
Raw View
In article <MATT.95Feb1223956@physics2.berkeley.edu>
           matt@physics.berkeley.edu "Matt Austern" writes:

> In article <russgold-0102952353040001@slip-19.netaxs.com> russgold@netaxs.com
>  (Russell Gold) writes:
>
> > My apologies if this has already been suggested, but I would like to see
> > some kind of standard 'clone' function for all classes:
>
> It won't happen.
>
> The reason it won't happen is that this functionality would only be
> possible for polymorphic classes---i.e., classes that have dynamic
> type information.
>
> As it stands, classes that have no virtual functions may be treated
> specially; it's possible to optimize them so that they have no more
> overhead than C structs.  Forcing every class to be a polymorphic
> class would make that optimization impossible.

Agreed.

However, remember the example of the destructor. Once you have one
in the hierarchy, all lower level ones become virtual, even those
generated by the compiler. A compiler generated clone() should be
treated the same way - virtual only if so required.

>
[snip]
>

As I see it, there is a better reason *not* to include a standard
clone() method. (It could be argued that this is a reason for
abolishing the default copy constructor and assignment methods).

It wouldn't solve the real problem.

What all these functions do is similar:

   Derived::op()
   {
      Base::op() ;
      member0::op() ;
      member1::op() ;
      ...
      membern::op() ;
   }

Strangely enough, object serialisation also tends to do this. What
would be useful would be something like this:

   Derived::op()
   {
      for_all(this::member.op())
   }

Assignment would be:

   Derived::operator = ( Derived& other )
   {
      for_all(this::member.operator = (other::member))
   }

(this is a pseudo-syntax - hence lack of return types, etc)

Use of templates would allow the user to get the compiler to generate
default methods for assignment, cloning, serialisation and others such.

I leave it to those more experienced than me to consider this in more
detail. If there is already a way of doing this, I would be most
interested.

Alan Bellingham
--
Alan@doughnut.demon.co.uk            "But now it's an avalanche we ride
ACCU: Association of C & C++ Users            Head over heels into Eden
+44-(0)1763-262629                                     Laughing inside"





Author: tob@world.std.com (Tom O Breton)
Date: Sat, 4 Feb 1995 04:30:48 GMT
Raw View
russgold@netaxs.com (Russell Gold) writes:

[ proposes that cloning an object onto the same dynamic type be built-in ]

> The current language definition does not support an easy way to make a
> copy of aList.  While it would always be possible to supply the clone
> method for every class manually, it seems trivial enough (and useful
> enough) that it ought to be provided automatically.


It's trivial to do in a header as well. It's easy to write:

#define         clone_method( type )\
        type*   virtual type::clone( void ) { return new type( *this ); };


If one does it "in the language", one can't associate the "wrong" clone
function with a derived class. However, that's taken care of above, by
including the scope specifier. Also, it's a mixed blessing anyways --
more predictability, less flexibility. So that's not a real advantage.

The above macro is a bit of a cheat -- it should really have to be 2
macros, one declares, one defines. It is a small extra effort, but IMO
so small as not to matter much.

As a macro, it invites collisions. A real but minor nuisance.


Alternatively, it could be a template, which appears to lose the
advantage of not associating the "wrong" type with the class, though I
could be mistaken.

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: russgold@netaxs.com (Russell Gold)
Date: Wed, 01 Feb 1995 23:53:04 -0500
Raw View
My apologies if this has already been suggested, but I would like to see
some kind of standard 'clone' function for all classes:


Proposed syntax:
^^^^^^^^^^^^^^^

AClass *anObject = originalObject-> clone();
 or
AClass *anObject = originalObject. clone();

where originalObject is type AClass or a subtype of AClass


Semantics:
^^^^^^^^^

the 'clone' method allocates a new object of the same dynamic type as the
object on which it is invoked, and uses its copy constructor to initialize
it.  That is,  it is effectively implemented as:

AClass *AClass::clone() const { return new Aclass( *this ); };


Rationale:
^^^^^^^^^^

There are many times when it is desirable to create an exact copy of a
list of heterogeneous objects.  The copy constructor is useless here, as
only the static type of the object(s) are known to the compiler.  For
example:


given:

class AClass {
    :
    };


class BClass: public AClass {
    :
    };

class CClass: public AClass {
    :
    };


AClass  *aList[5];

aList[0] = new BClass;
aList[1] = new BClass;
aList[2] = new CClass;
   etc.

The current language definition does not support an easy way to make a
copy of aList.  While it would always be possible to supply the clone
method for every class manually, it seems trivial enough (and useful
enough) that it ought to be provided automatically.
------------------------------------------------------------------------
Russell Gold                     | "... society is tradition and order
russgold@netaxs.com (preferred)  | and reverence, not a series of cheap
russgold@aol.com                 | bargains between selfish interests."
russgold@boeing.com              |




Author: matt@physics2.berkeley.edu (Matt Austern)
Date: 02 Feb 1995 06:39:56 GMT
Raw View
In article <russgold-0102952353040001@slip-19.netaxs.com> russgold@netaxs.com (Russell Gold) writes:

> My apologies if this has already been suggested, but I would like to see
> some kind of standard 'clone' function for all classes:

It won't happen.

The reason it won't happen is that this functionality would only be
possible for polymorphic classes---i.e., classes that have dynamic
type information.

As it stands, classes that have no virtual functions may be treated
specially; it's possible to optimize them so that they have no more
overhead than C structs.  Forcing every class to be a polymorphic
class would make that optimization impossible.

I admit that having a standard clone() operation would be useful.  (It
would be even more useful if every type were a descendent of some base
type, like Object or ANY.)  It would impose overhead, though, and the
overhead would apply to programs that didn't use it as well as
programs that did use it.  That's exactly the sort of thing that the
C++ community is unwilling to tolerate.

Note that I'm stating no judgment about whether or not the C++
community's attitude towards efficiency is correct; I'm simply stating
what that attitude is.  There are other object-oriented languages out
there, though.  For some projects, Eiffel or Smalltalk may be a better
choice than C++.
--

                               --matt




Author: Doug Judd <djudd@ads.com>
Date: 2 Feb 1995 17:32:04 GMT
Raw View
russgold@netaxs.com (Russell Gold) wrote:
>
> My apologies if this has already been suggested, but I would like to see
> some kind of standard 'clone' function for all classes:
>
> [...]
>
> There are many times when it is desirable to create an exact copy of a
> list of heterogeneous objects.  The copy constructor is useless here, as
> only the static type of the object(s) are known to the compiler.  For
> example:
>
> [...]

How about a somewhat involved copy constructor that uses RTTI?

- Doug

 o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o
 Doug Judd
 Advanced Decision Systems (Booz-Allen & Hamilton, Inc.)
 1500 Plymouth St., Mountain View, CA 94043-1230
 djudd@ads.com, (415) 960-7450

------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------