Topic: Clone(C++0x)


Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Wed, 27 Jun 2001 17:42:49 GMT
Raw View
In article <877kxyonon.fsf@212.246.110.78>, esa.pulkkinen@kotiposti.net
(Esa Pulkkinen <esa.pulkkinen>) wrote:
>..Very often, defining a clone method like
>"virtual A* A::clone() { return new A(*this); }" is exactly the right
>thing to do. However, there are situations where this does not work
>(and therefore making it the default is not a good thing to do), or
>where this default produces the wrong answer. For example,
>std::locale::facet is a polymorphic class where this default would
>invoke (and require) a method that is not implemented (since that
>class has a private copy constructor that is not defined), possibly
>producing a link-time error.

So in this case my suggestion is that std::locale::facet should instead
have the word "prohibited" on its copy constructor. It will tell the
compiler that the copy constructor does not exist, and for a clone()
operator it should generate either (depending on the choice of the
programmer) a runtime error (by throwing an exception if clone() is
invoked) or a compile time error (preventing the clone function to be
implemented at all). -- I have only the need for the former possibility,
but you say you have need for the second.

>...  Here's an example of the original problem
>with the "This" proposal:
>
>  class X {public: virtual void ReadOther(This *s) {} }; // new feature
>  class Y : public virtual X
>  {int a;  X() : a(0) {}
>   virtual void ReadOther(This *s) { cout << s->a << endl; }
>  };
>
>Now, there is no subtyping anywhere in this example. Any conversion
>from "Y*" to "X*" must not be allowed. This is because the following
>sequence of operations will fail:
>
>X *x = new X;
>X *y = new Y; // This is the conversion Y* -> X*. Assume it was
>              // valid, then:
>
>y->ReadOther(x); // reads member "a" from an object (*x) that does not
>                 // have it. This call will type check, because both
>                 // pointers have type "X*".

The suggestion with "This" that I have in my mind is only on the macro
expansion level. Thus your example above would after expansion look like
  class X {
  public:
    virtual void ReadOther(X *s) {}
  };
  class Y : public virtual X {
  int a;
    X() : a(0) {}
    virtual void ReadOther(Y *s) { cout << s->a << endl; }
  public:
    virtual void ReadOther(Y *s) {} // From X::ReadOther(This*)
  };

There would be a compiler error, due to the attempt to add the same typed
function as both a private and public. Thus, the suggestion in itself does
not change anything that is not already present in C++.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Wed, 27 Jun 2001 17:46:16 GMT
Raw View
Hi,
remove.haberg@matematik.su.se (Hans Aberg) wrote:
> This idea is too complicated for me to follow. You would need to explain
> by an explicit code example.

Don't pick on some ommissions or syntax errors but here is the general
layout (it is typed just from the top of my head - and, yes, it uses a
slightly different approach than the one I outlined in my previous
article because apparently some stuff doesn't work the way I wanted;
however, this one is easier anyway):

  // A small framework to cope with guaranteed clonable objects:
  template <class T> class final;

  class clone_base {
  public:
    virtual ~clone_base() {}
    virtual clone_base* clone() const = 0;
  private:
    template <class T> friend class final;
    struct inaccessible;
    virtual void dummy(inaccessible&) = 0;
  };

  class final_aux {
    final_aux(int) {}
    template <class T> friend class final;
  };

  template <class T> class final: public virtual final_aux, public T {
  public:
    final(): final_aux(0), T() {}
    template <class T1> final(T1 const& t1): final_aux(0), T(t1) {}
    template <class T1, class T2>
    final(T1 const& t1, T2 const& t2): final_aux(0), T(t1, t2) {}
    // add more constructors here

    final<T>* clone() const { return new final<T>(*this); }
  private:
    void dummy(inaccessible&) {}
  };

Basically, the above classes have the effect that any class derived from
'clone_base' is clonable (of course, that is what the virtual function
'clone()' is for) but can only be instantiated via the class template
'final' because this is the only class which can override the abstract
function 'dummy()': 'inaccessible' is, well, inaccessible for all other
classes. Since 'final' also overrides an appropriate 'clone()' function,
it is guaranteed that the most derived class derived from 'clone_base',
namely 'final<T>', overrides the 'clone()' function. The minor caveat is
that you have to write

  final<some_class> object;

instead of

  some_class object;

Also, the number of template arguments usable is limited (in the above
excerpt to a maximum of two arguments but it can be extended).

> But I still feel that those that want to not use such setups should be
> able to do simple dynamic programming in C++. Then dynamic copy
> constructors should be there for relatively easy access when needed.

Here is my viewpoint: The necessary code to have a safe approach using
features of the current standard is definitely acceptable and the imposed
burdon, namely writing 'final<T>' rather than 'T' where instantiating
objects, is reasonable. A change of the standard to achieve the same is
IMO wrong because it make a very special use of the language marginally
more convenient at the cost of considerable complexity due to rules under
which the dynamic constructor takes effect.

I'm not commenting on most of the stuff you wrote basically because it
mainly implied things on my arguments I haven't said! The above paragraph
is my whole point.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Wed, 27 Jun 2001 18:20:09 GMT
Raw View
In article <5b15f8fd.0106270514.386031bf@posting.google.com>,
dietmar_kuehl@yahoo.com (Dietmar Kuehl) wrote:
>  // A small framework to cope with guaranteed clonable objects:
>  template <class T> class final;
>  class clone_base { ...};
>  class final_aux { ... };
>  template <class T> class final: public virtual final_aux, public T { ... };
>
>Basically, the above classes have the effect that any class derived from
>'clone_base' is clonable (of course, that is what the virtual function
>'clone()' is for) but can only be instantiated via the class template
>'final' ... The minor caveat is that you have to write
>  final<some_class> object;
>instead of
>  some_class object;

It is interesting that you are able to sort of trick the template to
achieve this effect. However, every time one is sort of trying to trick a
programming language into doing things it was not designed for, the right
course of action is to find a general mechanism instead by which the
feature can be implemented more conveniently.

So if you think is an important programming technique, it seems me that
you should work it up so that one can hide away the class final, and so
that the user can write simply
  some_class object;

As for caveats with your construction, apart from the inconvenience of
having to add final<...> to every class you use, there are other problems
such as that one may use RTTI to write out the class name. The runtime
user will probable expect that to be say "integer" and not
"final<integer>" or something (as the runtime user will not know about the
language used to implement the runtime system). OK, so you fix this one,
but then there may be other such little surprises that may come around.

So your suggestion seems suitable for some of the comp.lang.c++ newsgroups
as a temporary fix while awaiting the next C++ revision is coming up with
a convenient solution.

>Here is my viewpoint: The necessary code to have a safe approach using
>features of the current standard is definitely acceptable and the imposed
>burdon, namely writing 'final<T>' rather than 'T' where instantiating
>objects, is reasonable.

Well, that is not the case. If you only have worked with simpler types of
polymorphic programming, I agree that one might get such an impression.
But it would not be suitable in a system which has hundreds of classes of
every conceivable type of data.

In addition, there is the question of the two forms
  virtual A* A::clone();       // Calling A::A(A&);
  virtual A* A::clone() const; // Calling A::A(const A&);
The former of these two copy constructors are currently underdeveloped in
C++ in the sense it cannot be used to extend that longevity of references,
and the latter may be required in the case of implementing a conservative
GC system.

Thus, one must give some extra analysis to these two forms of clone operators.

> A change of the standard to achieve the same is
>IMO wrong because it make a very special use of the language marginally
>more convenient at the cost of considerable complexity due to rules under
>which the dynamic constructor takes effect.

I doubt the issue is that complicated. Besides, if the issue would
contrary to expectations turn out to be complicated, that is a sign of
that it should be added to the C++ standard, as it will be essential to
dynamic programming.

Summing it up, I think there might be some interesting and useful
mechanisms that ensures that a derived class of a base class gets certain
instantiations directed by the base class, and which could be added to the
C++ language. -- I do not see exactly how these mechanisms would look like
though.

However, the clone operators fulfill a similar fundamental role to dynamic
programming as the copy constructors do to static programming. I would be
mistake to not add it.

I would compare the situation with the issue of making the destructor
automatically virtual if the class is polymorphic: The absence of such
mechanisms just gives dynamic programmers a hard time.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: kgw-zamboni-news@stiscan.com
Date: Thu, 28 Jun 2001 18:08:22 GMT
Raw View
On Wed, 27 Jun 2001 17:42:49, remove.haberg@matematik.su.se (Hans
Aberg) wrote: WEEKDAY

>In article <877kxyonon.fsf@212.246.110.78>, esa.pulkkinen@kotiposti.net
>(Esa Pulkkinen <esa.pulkkinen>) wrote:
>>..Very often, defining a clone method like
>>"virtual A* A::clone() { return new A(*this); }" is exactly the right
>>thing to do. However, there are situations where this does not work
>>(and therefore making it the default is not a good thing to do), or
>>where this default produces the wrong answer. For example,
>>std::locale::facet is a polymorphic class where this default would
>>invoke (and require) a method that is not implemented (since that
>>class has a private copy constructor that is not defined), possibly
>>producing a link-time error.
>
>So in this case my suggestion is that std::locale::facet should instead
>have the word "prohibited" on its copy constructor. It will tell the
>compiler that the copy constructor does not exist, and for a clone()
>operator it should generate either (depending on the choice of the
>programmer) a runtime error (by throwing an exception if clone() is
>invoked) or a compile time error (preventing the clone function to be
>implemented at all). -- I have only the need for the former possibility,
>but you say you have need for the second.
>

This mess is caused again by implicit declarations.
Implicit declarations (int) caused problems in C and Fortran.
C++ removed implicitly declared variables but introduced
implicitly declared constructors or methods.
Implicit methods and constructor already show up in the "what
is wrong with this program" because they are invoked invisibly.

Rather than declaring the method and then not implementing it,
they should have been declared with the word like "default" indicating
the
compiler would generate the default body.




[...]
--

Remove -zamboni to reply
All the above is hearsay and the opinion of no one in particular

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Fri, 29 Jun 2001 19:04:27 GMT
Raw View
In article <eDcSHHgdulIC-pn2-fp7tTxsJOgx9@zamboni.stiscan.com>,
kgw-zamboni-news@stiscan.com wrote:
>>>..Very often, defining a clone method like
>>>"virtual A* A::clone() { return new A(*this); }" is exactly the right
>>>thing to do. However, there are situations where this does not work
...
>>... my suggestion is [it] should instead
>>have the word "prohibited" on its copy constructor. It will tell the
>>compiler that the copy constructor does not exist,
...
>This mess is caused again by implicit declarations.
>Implicit declarations (int) caused problems in C and Fortran.
...
>Rather than declaring the method and then not implementing it,
>they should have been declared with the word like "default" indicating
>the compiler would generate the default body.

I think that the word "default" implies that it is what generated when not
calling for something else. :-) Also, it will probably difficult to ask
for a change that will break a lot of already existing code.

I think that the reason that the "int" implicit declarations caused a lot
of problems is that it originally was introduced in C not because a
convenience to the user or insights of good language design, but merely
because the typical function stack implementations made is possible.

So I do not think there is anything wrong with defaults, if there are
principles of good language design supporting them.

But on the other hand, if they prove to be a nuisance in some important
cases, there must easy ways to override those defaults:

If a function is implicitly defined and should not be defined in the code,
and the programmer tries to fix it by declaring the function but not
defining it, so that one may end up with a linker error instead, then that
falls into the category of trying to trick the language into something it
was not designed to do. -- Then the language should be properly augmented,
be it by a "prohibited" keyword or some other mechanism.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: esa.pulkkinen@kotiposti.net (Esa Pulkkinen <esa.pulkkinen>)
Date: Mon, 25 Jun 2001 15:12:34 GMT
Raw View
remove.haberg@matematik.su.se (Hans Aberg) writes:
> Has anybody discussed support for the virtual copy constructor, often
> called a clone operator in the new C++ revision?
[SNIP]
> The question is how to add this to C++:
>
> One suggestion might be to add it to all polymorphic classes (with at
> least one virtual function defined).

I would rather like it to be added only where there is an accessible
copy constructor in the class, or at least if it is automatically
generated, its access should be dependent on the access defined for
the copy constructor. Also, access to "operator new" should somehow
influence the choice of access for the automatically generated clone
operation.

> The advantage with the first form is that it clearly separates the two
> forms (const/non-const) of the clone operators. Also, not all classes have
> a copy constructor, so one could in such a case make the clone operators
> throw an exception.

Such errors should be diagnosed at compile time. I somewhat fear that
this feature would cause problems similar to what the current
mechanism of automatic definition of constructors and assignment
operations has caused. You do not want to repeat that mistake. At
least, there is the problem of how to ensure that when the programmer
needs to provide his own clone operation, he remembers to do that
(say, you want to use a special allocator for the class). I would
prefer a compile-time error in those cases.

> The advantage with the second form (using "This") is greater generality:
> Such a keyword might be useful in other contexts.

This will introduce yet another mechanism in which inheritance does
not imply subtyping.
--
 Esa Pulkkinen                            | C++ programmers do it virtually
 E-Mail:  esa.pulkkinen@kotiposti.net     | everywhere with class, resulting
 WWW : http://sivut.koti.soon.fi/epulkkin | in multiple inheritance.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Mon, 25 Jun 2001 15:13:02 GMT
Raw View
Hi,
remove.haberg@matematik.su.se (Hans Aberg) wrote:
> Has anybody discussed support for the virtual copy constructor, often
> called a clone operator in the new C++ revision?

What does this achieve what is not yet doable? Does the effort to
standardize this stuff has sufficient benefit to warrent this
extension? What is wrong with the form you presented and it this
particular use common enough to always use it?

Personally, I have rare use for a polymorphic copy constructor but
then I have rarely use for dynamic polymorph objects anyway. However,
when I have things like this, object identity is typically a crucial
aspect and polymorphic objects don't have the need to copy themselves
at all. If I want value semantics, I use value semantics...
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 25 Jun 2001 18:00:58 GMT
Raw View
In article <5b15f8fd.0106250534.5ccf5c6a@posting.google.com>,
dietmar_kuehl@yahoo.com (Dietmar Kuehl) wrote:
>> Has anybody discussed support for the virtual copy constructor, often
>> called a clone operator in the new C++ revision?
>
>What does this achieve what is not yet doable?

When setting up a polymorphic hierarchy, all classes in it must have a
clone, otherwise the dynamic copying does not becomes right. And it is
hard to detect a forgotten clone, or to ensure that if somebody else adds
a class to the hierarchy that it becomes properly added.

> Does the effort to
>standardize this stuff has sufficient benefit to warrent this
>extension?

Beats me. I think that if one should do polymorphic programming in C++, it
should be there -- it is just a dynamic copy constructor, and fulfills the
same dynamic role as the static copy constructor does in static
programming.

So perhaps the satisfaction of making the language C++ usable in dynamic
program can bring enough pleasure to those that bother to standardize the
feature.

> What is wrong with the form you presented and it this
>particular use common enough to always use it?

I am not sure what you have in your mind here: If there was something
wrong with it I would not have presented it, and if you know that what was
wrong with, it would have been appropriate of you to explain that to
straighten that out. And if there was something wrong with it, how could
its use be common?

>Personally, I have rare use for a polymorphic copy constructor but
>then I have rarely use for dynamic polymorph objects anyway. However,
>when I have things like this, object identity is typically a crucial
>aspect and polymorphic objects don't have the need to copy themselves
>at all. If I want value semantics, I use value semantics...

Well, if one is using a ref count or a conservative GC or something to
keep track of references, actual copying might become rare. But it will
happen if one mutates an object in say a pure function call, and it is
also possible to mix styles of "unboxed" elements which are copied (i.e.,
treated by value) and "boxed" elements that are not (i.e., treated by
reference).

It depends on which style one is choosing, and when copying does happen,
it must come out right.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 25 Jun 2001 18:22:32 GMT
Raw View
In article <878zijmmam.fsf@212.246.110.78>, esa.pulkkinen@kotiposti.net
(Esa Pulkkinen <esa.pulkkinen>) wrote:
>> Has anybody discussed support for the virtual copy constructor, often
>> called a clone operator in the new C++ revision?
...
>> One suggestion might be to add it to all polymorphic classes (with at
>> least one virtual function defined).
>
>I would rather like it to be added only where there is an accessible
>copy constructor in the class, ...
...
>Such errors should be diagnosed at compile time.

It is not necessarily an error to add a class which does not have a
(static) copy constructor to a polymorphic hierarchy: A dedicated
polymorphic system should be able to handle all types of data, including
those that do not have a copy constructor, and have a mechanism to handle
the exceptions that may ensue if an attempt to copy a non-copyable object
is done at run-time. For example, one might want to have a stream in the
hierarchy, in which the clone() should throw an exception.

(In my set-up, I make use of a clone() operator which should produce a
state-independent copy, a reference() operator, and a copy() operator
which is the one normally used for copying, and which each object chooses
between the reference() or clone().)

So I think this might be choice of styles: Those that prefer that an
exception is thrown and those that want it to cause a compiler error.

>I would rather like it to be added only where there is an accessible
>copy constructor in the class, or at least if it is automatically
>generated, its access should be dependent on the access defined for
>the copy constructor.

This access aspect is interested, because it that is important, it might
suggest that one should have it implemented into C++ (as it might be
difficult to get proper control over it otherwise).

>..I somewhat fear that
>this feature would cause problems similar to what the current
>mechanism of automatic definition of constructors and assignment
>operations has caused.

I suggested elsewhere that one should be able to use the key-word
"prohibited" on automatically generated functions in order to prevent them
being generated and called.

>> The advantage with the second form (using "This") is greater generality:
>> Such a keyword might be useful in other contexts.
>
>This will introduce yet another mechanism in which inheritance does
>not imply subtyping.

I am not familiar with these problems, so you may have to explain it further.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Tue, 26 Jun 2001 15:38:41 GMT
Raw View
Hi,
remove.haberg@matematik.su.se (Hans Aberg) wrote:
> When setting up a polymorphic hierarchy, all classes in it must have a
> clone, otherwise the dynamic copying does not becomes right. And it is
> hard to detect a forgotten clone, or to ensure that if somebody else adds
> a class to the hierarchy that it becomes properly added.

It may be "hard" or not as beautiful as your proposal but it is doable with
existing C++ features. The basic idea is to use a virtual base class in your
hierarchy which can only be instantiated by a specific friend class, ie.
which has all constructors private and a single friend which happens to be
a template. This template in turn, call it "final", derives from its
template argument and virtually from an auxiliary class which also can only
be instantiated by the class "final" (the second is only there to make the
class "final", well, final). The class "final" overrides the virtual function
'clone()' (and possibly some others) to do the right thing. The only open end
so far are the constructors because all other functions are inherited from
the template argument. To cope with these, you have to know the maximum number
of possible constructor arguments (yes, this is a limitation) and provide
corresponding templated constructors which just delegate construction to its
base class and arranges for the virtual bases to be constructed.

In this setup, it is impossible to instantiate a class derived from the base
(because there is no default constructor and virtual bases have to be
constructed by the most derived class) except using the class "final". It is
thus guaranteed that there is an overriding 'clone()' function in the most
derived class (well, not really: it is possible to specialize "final" and
to omit the 'clone()' function; however, we are defending against Murphy, not
against Machiavelli).

> > Does the effort to
> >standardize this stuff has sufficient benefit to warrent this
> >extension?
>
> Beats me. I think that if one should do polymorphic programming in C++, it
> should be there -- it is just a dynamic copy constructor, and fulfills the
> same dynamic role as the static copy constructor does in static
> programming.

Polymorphic programming is a specific use of C++. Within this use, many idoms
don't require cloning of objects. Actually, I found extreme rare situations
where cloning polymorphic objects is necessary or even desirable. That is,
you are asking for special syntax for a very special problem which actually
has already an approach within the language. That is, I don't think that the
benefit of this feature warrants the effort to standardize it...

> > What is wrong with the form you presented and it this
> >particular use common enough to always use it?
>
> I am not sure what you have in your mind here:

A rhetoric question: Why would you need a different approach? The stuff
already there can be used to implement this feature. Why would you need a
language extensions? What does the language extension give you what is not
yet available. My perspective: a little bit saved work, maybe a cleaner
syntax because you can write 'new T' instead of 'new final<T>', and no
restriction on the number of constructor arguments where is consider the
latter to be pretty irrelevant because the class 'final' can readily
support lots of arguments.

> Well, if one is using a ref count or a conservative GC or something to
> keep track of references, actual copying might become rare.

I wasn't talking about copy-on-write semantics. I was talking about objects
with identity: You simply don't want to clone them. They are never copied.
In a setting using polymorphic objects I typically use things like
'boost::shared_ptr' to keep track of the objects and there is no need to
really copy the polymorphic object.

> It depends on which style one is choosing, and when copying does happen,
> it must come out right.

Correct. I found a style cloning polymorphic objects to be pretty rare. Thus,
I think you are asking for a language extensions coping with an extremely
specific problem. This might be reasonable if there is no approach to cope
with this problem in the language but there is.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: esa.pulkkinen@kotiposti.net (Esa Pulkkinen <esa.pulkkinen>)
Date: Tue, 26 Jun 2001 15:44:07 GMT
Raw View
> In article <878zijmmam.fsf@212.246.110.78>, esa.pulkkinen@kotiposti.net
> (Esa Pulkkinen <esa.pulkkinen>) wrote:
> >..I somewhat fear that this feature would cause problems similar
> >to what the current mechanism of automatic definition of
> >constructors and assignment operations has caused.
>
remove.haberg@matematik.su.se (Hans Aberg) writes:
> I suggested elsewhere that one should be able to use the key-word
> "prohibited" on automatically generated functions in order to prevent them
> being generated and called.

I don't think this addresses the problem. Current C++ mechanism of
automatically generating assignment operators and constructors can
also be disabled by providing an explicit version. The problem is that
the default might be wrong (and that this is not detected
automatically). Adding a mechanism in which the programmer can
explicitly ask not to use the default does not help if the programmer
doesn't notice the problem (and therefore has not used the new
keyword).

> >This will introduce yet another mechanism in which inheritance does
> >not imply subtyping.
>
> I am not familiar with these problems, so you may have to explain it
> further.

Private inheritance is often considered obscure, at least partially
because it defines inheritance that doesn't imply subtyping, that is,
you cannot convert a pointer to derived class to a pointer to base
class (except inside the class), if private inheritance was used. The
reason is that the conversion that excercises the subtyping relation
is usually implicit (and always between pointers or references to a
class, not objects of the class itself), and therefore it's not always
obvious what was the cause of the compiler error message. This is
further complicated by multiple inheritance (that can cause
ambiguities and use of virtual inheritance can prevent some forms of
conversions), and the less-than-ideal semantics of C++ pointers as
well as conversions between different types of pointers or references
(where const-correctness can also cause similar errors).

Adding another mechanism which introduces a compile time error on uses
of the implicit pointer-to-derived-class to pointer-to-base-class
conversion because the inheritance did not imply subtyping (and this
fact will not be obvious when you look at the definition of the class,
in fact it might be buried in some base class) will make this even
harder for people to understand. The fundamental problem arguably is
not with the feature as such but with its interaction with existing
(unsafe/overly complex) features of C++, and the resulting increase in
complexity that programmers will need to understand.
--
 Esa Pulkkinen                            | C++ programmers do it virtually
 E-Mail:  esa.pulkkinen@kotiposti.net     | everywhere with class, resulting
 WWW : http://sivut.koti.soon.fi/epulkkin | in multiple inheritance.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Tue, 26 Jun 2001 18:14:00 GMT
Raw View
In article <5b15f8fd.0106260123.f8c6903@posting.google.com>,
dietmar_kuehl@yahoo.com (Dietmar Kuehl) wrote:
>> When setting up a polymorphic hierarchy, all classes in it must have a
>> clone, otherwise the dynamic copying does not becomes right. And it is
>> hard to detect a forgotten clone, or to ensure that if somebody else adds
>> a class to the hierarchy that it becomes properly added.
>
>It may be "hard" or not as beautiful as your proposal but it is doable with
>existing C++ features. The basic idea is to use a virtual base class in your
>hierarchy which can only be instantiated by a specific friend class, ie.
>which has all constructors private and a single friend which happens to be
>a template. This template in turn, call it "final", derives from its
>template argument and virtually from an auxiliary class which also can only
>be instantiated by the class "final" (the second is only there to make the
>class "final", well, final). The class "final" overrides the virtual function
>'clone()' (and possibly some others) to do the right thing. The only open end
>so far are the constructors because all other functions are inherited from
>the template argument. To cope with these, you have to know the maximum number
>of possible constructor arguments (yes, this is a limitation) and provide
>corresponding templated constructors which just delegate construction to its
>base class and arranges for the virtual bases to be constructed.

This idea is too complicated for me to follow. You would need to explain
by an explicit code example.

I use a Flex/Bison setup which writes the appropriate C++ classes.

It is much simpler than trying to fiddle around with C++'s limited
template system.

But I still feel that those that want to not use such setups should be
able to do simple dynamic programming in C++. Then dynamic copy
constructors should be there for relatively easy access when needed.

>Polymorphic programming is a specific use of C++. Within this use, many idoms
>don't require cloning of objects. Actually, I found extreme rare situations
>where cloning polymorphic objects is necessary or even desirable.

When used it cloning should be used in more advanced programming. When I
write more simpler programs, like a parser building an object, then I
found that I did not need cloning.

> That is,
>you are asking for special syntax for a very special problem which actually
>has already an approach within the language. That is, I don't think that the
>benefit of this feature warrants the effort to standardize it...

So I think that appears to be special if one is not programming with more
general dynamic objects.

>> > What is wrong with the form you presented and it this
>> >particular use common enough to always use it?
>>
>> I am not sure what you have in your mind here:
>
>A rhetoric question: Why would you need a different approach? The stuff
>already there can be used to implement this feature.

As I indicated, I have found that one can avoid the problem altogether by
simply using a Flex/Bison combination that writes the correct C++ code.

But when I was doing this by hand, I found it was easy to forget. The best
method was to use an already existing class as a template, and then alter
the copy constructor by hand. This was OK for the first couple of ten
classes, but when the number of classes gets up into the hundreds, it
becomes a chore.

Even worse, suppose one adds a polymorphic class library to C++, where the
idea is that users should additional dynamic data classes. Then there is a
good chance that this particular silly little aspect is implemented wrong.
One will end up with hard-to-debug runtime problems.

>> Well, if one is using a ref count or a conservative GC or something to
>> keep track of references, actual copying might become rare.
>
>I wasn't talking about copy-on-write semantics. I was talking about objects
>with identity: You simply don't want to clone them. They are never copied.
>In a setting using polymorphic objects I typically use things like
>'boost::shared_ptr' to keep track of the objects and there is no need to
>really copy the polymorphic object.

I do not know about this boost::shared_ptr: from your description it
appears that the effect of its use is the same as when using a ref count
or a conservative GC, namely, keeping track of the reference to a single
runtime object.

The runtime objects I use are simple objects like integers, etc, up to
lambda expression closures. It is quite clear that one should be able to
clone such objects when needed.

Further, one can hook up such runtime objects in a distributed settings. I
recall that support for distributed programming is a task for the next C++
language revision.

\begin{polemics}
Are you saying that sending lambda expression and such over the network
should be prohibited?
\end{polemics}

>> It depends on which style one is choosing, and when copying does happen,
>> it must come out right.
>
>Correct. I found a style cloning polymorphic objects to be pretty rare. Thus,
>I think you are asking for a language extensions coping with an extremely
>specific problem. This might be reasonable if there is no approach to cope
>with this problem in the language but there is.

In a more limited programming settings, your conclusions might be true,
but not if one should do qualified dynamic programming, including
distributed programming and such.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Tue, 26 Jun 2001 18:32:43 GMT
Raw View
In article <87u214c7xv.fsf@212.246.110.78>, esa.pulkkinen@kotiposti.net
(Esa Pulkkinen <esa.pulkkinen>) wrote:
>> I suggested elsewhere that one should be able to use the key-word
>> "prohibited" on automatically generated functions in order to prevent them
>> being generated and called.
>
>I don't think this addresses the problem. Current C++ mechanism of
>automatically generating assignment operators and constructors can
>also be disabled by providing an explicit version.

But not prohibited.

> The problem is that
>the default might be wrong (and that this is not detected
>automatically).

I am not sure what you have in your mind here: Is it pointers that are
copied even though they point at dynamic memory locations which should not
be shared?

> Adding a mechanism in which the programmer can
>explicitly ask not to use the default does not help if the programmer
>doesn't notice the problem (and therefore has not used the new
>keyword).

If so, this is correct, it will not help. Other ideas will have to be used
to attack such problems, like classifying pointers according their usage.

The idea with "prohibited" is for classes that should not have a type of
default function, and avoid that it is being called accidentally. (I have
not use of it now, but I recall that when starting programming C++, such a
mechanism would have helped.)

>> >This will introduce yet another mechanism in which inheritance does
>> >not imply subtyping.
...
>Private inheritance is often considered obscure, at least partially
>because it defines inheritance that doesn't imply subtyping, that is,
>you cannot convert a pointer to derived class to a pointer to base
>class (except inside the class), if private inheritance was used.

Aha, I thought you were speaking about the "This" suggestions".

But I think that you are speaking about the form
  class A {
  public:
    A* clone() const { return new A(*this); }
  };
so that if A derives from a base class B, an A* must be converted to a B*
at runtime.

The reason for choosing this form is to make the definition independent of
other classes than the class within the clone operator appears.

As for the other aspect, C++ class access privileges, in the world I am
living all is runtime objects, and those C++ constructs are essentially
useless. The derivation I have used is always "public virtual" from the
root or one of its derivations, and I have no idea why one would want to
choose anything else.

So I can not help out much if one wants to try other variations: After
all, the use of the clone() operators is to create dynamic copies in a
runtime world where C++'s static access class privileges do not exist.

The only replacement I can think of is some kind of runtime access
privileges. I know that people who do polymorphic programming gets into
trouble with such runtime access privileges, but I happen to work with a
computational model that seems to be able to avoid that: Basically, one
send around requests, instead of "imperative" manipulations.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: esa.pulkkinen@kotiposti.net (Esa Pulkkinen <esa.pulkkinen>)
Date: Tue, 26 Jun 2001 23:22:11 GMT
Raw View
> In article <87u214c7xv.fsf@212.246.110.78>, esa.pulkkinen@kotiposti.net
> (Esa Pulkkinen <esa.pulkkinen>) wrote:
> > The problem is that
> >the default might be wrong (and that this is not detected
> >automatically).
>
remove.haberg@matematik.su.se (Hans Aberg) writes:
> I am not sure what you have in your mind here: Is it pointers that are
> copied even though they point at dynamic memory locations which should not
> be shared?

I mean, your suggestion that "... add it to all polymorphic classes
(with at least one virtual function defined)" will automatically
define it to all polymorphic classes with a definition that invokes
the copy constructor. Very often, defining a clone method like
"virtual A* A::clone() { return new A(*this); }" is exactly the right
thing to do. However, there are situations where this does not work
(and therefore making it the default is not a good thing to do), or
where this default produces the wrong answer. For example,
std::locale::facet is a polymorphic class where this default would
invoke (and require) a method that is not implemented (since that
class has a private copy constructor that is not defined), possibly
producing a link-time error. It's not realistic to add uses of the
proposed "prohibited" keyword to all such cases without help from the
compiler (in terms of explicit errors before a class is used). So my
fear is that this default will also not be correct for other
situations, therefore causing problems similar to what implicit
definition of copy constructor and assignment operator have already
caused.

> >Private inheritance is often considered obscure, at least partially
> >because it defines inheritance that doesn't imply subtyping, that is,
> >you cannot convert a pointer to derived class to a pointer to base
> >class (except inside the class), if private inheritance was used.
>
> Aha, I thought you were speaking about the "This" suggestions".

I was. I think I've been somewhat too brief. Sorry for confusing
things. I'll try again.  Here's an example of the original problem
with the "This" proposal:

  class X {public: virtual void ReadOther(This *s) {} }; // new feature
  class Y : public virtual X
  {int a;  X() : a(0) {}
   virtual void ReadOther(This *s) { cout << s->a << endl; }
  };

Now, there is no subtyping anywhere in this example. Any conversion
from "Y*" to "X*" must not be allowed. This is because the following
sequence of operations will fail:

X *x = new X;
X *y = new Y; // This is the conversion Y* -> X*. Assume it was
              // valid, then:

y->ReadOther(x); // reads member "a" from an object (*x) that does not
                 // have it. This call will type check, because both
                 // pointers have type "X*".

Therefore, to maintain consistency, you must abandon the idea that (in
this particular case) Y* can be converted to X*, and the subtyping is
not valid, even when there is public inheritance between Y and X.
[If it's still not clear, see the references below].

Therefore, if you add the "This" feature, you must accept one new
situation (when you use "This" in contravariant positions,
i.e. as a function argument type) where public inheritance does not
imply subtyping. This situation is similar to the case with private
inheritance (where this has already arguably caused problems). And
since the conversion from Y* to X* is implicit, it is very easy to
misunderstand this prohibition on subtyping as something entirely
different (because there are all kinds of other features that use the
derived-to-base conversion or other pointer conversions which also
might cause similar-looking errors). Given the current complexity of
this part of C++, I don't see much hope that this extension will be
useful for the large majority of potential users.

[1] : Abadi, Cardelli: A Theory of Objects. Springer Verlag.
[2] : Castagna: Covariance and contravariance: Conflict without a cause,
      http://citeseer.nj.nec.com/castagna95covariance.html
--
 Esa Pulkkinen                            | C++ programmers do it virtually
 E-Mail:  esa.pulkkinen@kotiposti.net     | everywhere with class, resulting
 WWW : http://sivut.koti.soon.fi/epulkkin | in multiple inheritance.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Wed, 27 Jun 2001 16:37:11 GMT
Raw View
Hi,
remove.haberg@matematik.su.se (Hans Aberg) wrote:
> This idea is too complicated for me to follow. You would need to explain
> by an explicit code example.

Don't pick on some ommissions or syntax errors but here is the general
layout (it is typed just from the top of my head - and, yes, it uses a
slightly different approach than the one I outlined in my previous
article because apparently some stuff doesn't work the way I wanted;
however, this one is easier anyway):

  // A small framework to cope with guaranteed clonable objects:
  template <class T> class final;

  class clone_base {
  public:
    virtual ~clone_base() {}
    virtual clone_base* clone() const = 0;
  private:
    template <class T> friend class final;
    struct inaccessible;
    virtual void dummy(inaccessible&) = 0;
  };

  class final_aux {
    final_aux(int) {}
    template <class T> friend class final;
  };

  template <class T> class final: public virtual final_aux, public T {
  public:
    final(): final_aux(0), T() {}
    template <class T1> final(T1 const& t1): final_aux(0), T(t1) {}
    template <class T1, class T2>
    final(T1 const& t1, T2 const& t2): final_aux(0), T(t1, t2) {}
    // add more constructors here

    final<T>* clone() const { return new final<T>(*this); }
  private:
    void dummy(inaccessible&) {}
  };

Basically, the above classes have the effect that any class derived from
'clone_base' is clonable (of course, that is what the virtual function
'clone()' is for) but can only be instantiated via the class template
'final' because this is the only class which can override the abstract
function 'dummy()': 'inaccessible' is, well, inaccessible for all other
classes. Since 'final' also overrides an appropriate 'clone()' function,
it is guaranteed that the most derived class derived from 'clone_base',
namely 'final<T>', overrides the 'clone()' function. The minor caveat is
that you have to write

  final<some_class> object;

instead of

  some_class object;

Also, the number of template arguments usable is limited (in the above
excerpt to a maximum of two arguments but it can be extended).

> But I still feel that those that want to not use such setups should be
> able to do simple dynamic programming in C++. Then dynamic copy
> constructors should be there for relatively easy access when needed.

Here is my viewpoint: The necessary code to have a safe approach using
features of the current standard is definitely acceptable and the imposed
burdon, namely writing 'final<T>' rather than 'T' where instantiating
objects, is reasonable. A change of the standard to achieve the same is
IMO wrong because it make a very special use of the language marginally
more convenient at the cost of considerable complexity due to rules under
which the dynamic constructor takes effect.

I'm not commenting on most of the stuff you wrote basically because it
mainly implied things on my arguments I haven't said! The above paragraph
is my whole point.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Fri, 22 Jun 2001 17:52:24 GMT
Raw View
Has anybody discussed support for the virtual copy constructor, often
called a clone operator in the new C++ revision?

I think one can give it the forms
  class root {
  public:
    virtual root* clone() { return new root(*this); }
    virtual root* clone() const { return new root(*this); }
  };

  class A : public virtual root {
  public:
    virtual A* clone() { return new A(*this); }          // A::A(A&)
    virtual root* clone() const { return new A(*this); } // A::A(const A&)
  };
(That is, A::clone() overrides root::clone() via an A* -> root* return
conversion when needed.)

The question is how to add this to C++:

One suggestion might be to add it to all polymorphic classes (with at
least one virtual function defined).

Another idea would be to add a keyword "This" that expands to the current
class, instead of the class the definition it was in. Thus, one could
write
  class root {
  public:
    virtual This* clone() { return new This(*this); }
    virtual This* clone() const { return new This(*this); }
  };

  class A : public virtual root {
    ...
  };
The idea is that when class A is instantiated, the compiler will replace
the keyword This is the class "root" declaration with "A", so that one
gets the appropriate (in this case) clone operators.

The advantage with the first form is that it clearly separates the two
forms (const/non-const) of the clone operators. Also, not all classes have
a copy constructor, so one could in such a case make the clone operators
throw an exception.

As for ways of indicating that there should be no copy constructor, I have
the idea of a keyword "prohibited" for such a use:
  class B {
  prohibited:
    B::B(const B&);  // No such copy constructor defined.
  };

The advantage with the second form (using "This") is greater generality:
Such a keyword might be useful in other contexts.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]