Topic: C++0x Wish list, constructors


Author: nikolai@sun.com (Nikolai Pretzell)
Date: Tue, 10 Sep 2002 08:41:01 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) wrote:
> nikolai@sun.com (Nikolai Pretzell) wrote in message
> news:<20020905.9372264@mis.configured.host>...

> > > > Well it is my belief that the syntax:
> > > > C::C(): C(5, 10, 15) {}
> > > > Will work perfectly satisfactorily.
> > > It's basically the same as my syntax: I use "this", and you use the
> > > nam e of the class.  The keyword this is currently not legal in this
> > > context, so there is no risk of breaking anything.  I don't think
> > > that you could construct a program where the name of class was legal
> > > in this context either; the class can't have a member with its name,
> > > for example.  So there should be no problem with that either.

> > I would strongly prefer the use of the class name and not use this

> Any particular reason, or just personal preference.

Yes. Because of a mail-problem my posting was cut two times at that line.
 :-(
There was more originally. I try the third time now:


The reason being consistency.
Both terms (classname and this) match semantically in some way.

However, syntactically they are different:

'this' would have a syntactically completely new meaning here:
nowhere else there is a possibility to initialise a pointer with
multiple elements, or where impliciteley the c'tor of the pointed to
object is called.

The class name however, is exactly the way, how base classes are
initialised already today, so it would be perfectly consistent with
current use.

Regards,
Nikolai


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Fri, 6 Sep 2002 15:37:02 +0000 (UTC)
Raw View
nikolai@sun.com (Nikolai Pretzell) wrote in message
news:<20020905.9372264@mis.configured.host>...

> > > >I could implement the second constructor as:

> > > >    C::C()
> > > >        :   this( 5, 10, 15 )
> > > >    {
> > > >    }

> > > Well it is my belief that the syntax:

> > > C::C(): C(5, 10, 15) {}

> > > Will work perfectly satisfactorily.

> > It's basically the same as my syntax: I use "this", and you use the
> > nam e of the class.  The keyword this is currently not legal in this
> > context, so there is no risk of breaking anything.  I don't think
> > that you could construct a program where the name of class was legal
> > in this context either; the class can't have a member with its name,
> > for example.  So there should be no problem with that either.

> I would strongly prefer the use of the class name and not use "this"

Any particular reason, or just personal preference.

I have a personal preference for this, but it certainly isn't very
strong, and if there are concrete reasons for preferring the class name,
I'd have no trouble accepting them.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Tue, 3 Sep 2002 16:43:35 +0000 (UTC)
Raw View
In article <d6651fb6.0208300356.42b24da9@posting.google.com>, James
Kanze <kanze@gabi-soft.de> writes
>What I imagine should be possible would be a special, alternate syntax
>for the initialization list.  Thus, instead of writing something like:
>
>    C::C( int a, int b, int c )
>        :   myA( a )
>        ,   myB( b )
>        ,   myC( c )
>    {
>    }
>
>    C::C()
>        :   myA(  5 )
>        ,   myB( 10 )
>        ,   myC( 15 )
>    {
>    }
>
>I could implement the second constructor as:
>
>    C::C()
>        :   this( 5, 10, 15 )
>    {
>    }

Well it is my belief that the syntax:

C::C(): C(5, 10, 15) {}

Will work perfectly satisfactorily. It seems to be a perfectly simple
extension of the constructor initialiser list. It would have to be the
only initialiser and the body of C(int, int, int) would have to run
first, followed by the body of this one. We would have to smooth a few
rough patches to ensure that we did not get circularity. This is one of
the small extensions that I want to see in C++0x


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Wed, 4 Sep 2002 18:00:33 +0000 (UTC)
Raw View
francis.glassborow@ntlworld.com (Francis Glassborow) wrote in message
news:<oY2$yrDVa8b9EwRd@robinton.demon.co.uk>...
> In article <d6651fb6.0208300356.42b24da9@posting.google.com>, James
> Kanze <kanze@gabi-soft.de> writes
> >What I imagine should be possible would be a special, alternate
> >syntax for the initialization list.  Thus, instead of writing
> >something like:

> >    C::C( int a, int b, int c )
> >        :   myA( a )
> >        ,   myB( b )
> >        ,   myC( c )
> >    {
> >    }

> >    C::C()
> >        :   myA(  5 )
> >        ,   myB( 10 )
> >        ,   myC( 15 )
> >    {
> >    }

> >I could implement the second constructor as:

> >    C::C()
> >        :   this( 5, 10, 15 )
> >    {
> >    }

> Well it is my belief that the syntax:

> C::C(): C(5, 10, 15) {}

> Will work perfectly satisfactorily.

It's basically the same as my syntax: I use "this", and you use the name
of the class.  The keyword this is currently not legal in this context,
so there is no risk of breaking anything.  I don't think that you could
construct a program where the name of class was legal in this context
either; the class can't have a member with its name, for example.  So
there should be no problem with that either.  (I see a slight advantage
in using this in editors with syntax highlighting.  Since this is a
keyword, it will appear in a different color that a normal initialiser,
calling attention to the fact that I'm doing something special.)

> It seems to be a perfectly simple extension of the constructor
> initialiser list. It would have to be the only initialiser and the
> body of C(int, int, int) would have to run first, followed by the body
> of this one. We would have to smooth a few rough patches to ensure
> that we did not get circularity.

Quality of implementation issue.  Given separate compilation, I doubt
that we can ensure a lack of circularity.  I don't think it's a problem;
we don't guarantee that other recursive function calls will terminate
either.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: nikolai@sun.com (Nikolai Pretzell)
Date: Thu, 5 Sep 2002 17:25:12 +0000 (UTC)
Raw View
Hi,

> > >I could implement the second constructor as:

> > >    C::C()
> > >        :   this( 5, 10, 15 )
> > >    {
> > >    }

> > Well it is my belief that the syntax:

> > C::C(): C(5, 10, 15) {}

> > Will work perfectly satisfactorily.

> It's basically the same as my syntax: I use "this", and you use the nam=
e
> of the class.  The keyword this is currently not legal in this context,
> so there is no risk of breaking anything.  I don't think that you could
> construct a program where the name of class was legal in this context
> either; the class can't have a member with its name, for example.  So
> there should be no problem with that either. =20


I would strongly prefer the use of the class name =96 and not use "this"

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Mon, 26 Aug 2002 20:23:24 GMT
Raw View
In article <akdqtp$dmg$1@sunsite.dk>, Thorsten Ottosen
<nesotto@cs.auc.dk> writes
>I'm sure Stroupstrup has also thought about this. Basically what we want is
>something similar to java's resuse of constructors:
>
>class X
>{
>  private int x_, y_, z_;
>  X( int x, int y, int z)
> {
>    x_ = ...;
>    y_ = ...;
>    z_ = ...;
>  }
>  X( int z )
>  {
>     this( 4,4, z ); // call X(int, int, int )
>  }
>}
>
>so that we can avoid potencial inconsistencies between constructors
>initilization and type some less.

Tackling that is on the table for next time, but not that way but in a
way consistent with the rest of the C++ constructor syntax.

--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Allan_W@my-dejanews.com (Allan W)
Date: Tue, 27 Aug 2002 06:37:25 CST
Raw View
On July 31, David Schwartz wrote:
> > > > I'm suggesting the ability to call a
> > > > constructor for your own class in your initializer list.

"Thorsten Ottosen" <nesotto@cs.auc.dk> wrote
> I'm sure Stroupstrup has also thought about this.
If so, he rejected it!

(I think that D&C mentions it, but I don't have my copy handy...)

> Basically what we want is something similar to java's resuse
> of constructors:
>
> class X
> {
>   private int x_, y_, z_;
    // Java syntax will give you errors in C++!
    // But I know what you meant.

>   X( int x, int y, int z)
>  {
>     x_ = ...;
>     y_ = ...;
>     z_ = ...;
>   }
>   X( int z )
>   {
>      this( 4,4, z ); // call X(int, int, int )
>   }
> }
>
> so that we can avoid potencial inconsistencies between constructors
> initilization and type some less.

Some of Java's problems don't apply to C++. Consider:

    class Base {
    protected:
        int b1, b2;
        static int calc( static int i = 0; return ++i; }
    public:
        Base(int b_1, int b_2) : b1(b_1), b2(b_2)
            { std::cout << "Base(" << b_1 << ',' << b_2 << ")\n"; }
        Base() { int c = calc(); this(c, c); } // Call Base(int,int)
    }

I think that's hard enough! The compiler has to push C onto the stack
twice, as if it had been a parameter, and then jump to the other
constructor. But what happens when we complicate the mix?

    class Der : public Base {
        int d1, d2;
    public:
        Der(int a, int b, int c, int d) : Base(a,b), d1(c), d2(d)
            { std::cout << "Der(" << a << ',' << b << ',' << c
                        << ',' << d << ")\n"; }
        Der() { b1=calc(); b2=b1; this(b1,b2,0,0); }
    }

Should the second version of Der() overwrite the Base subobject as well?

On August 1, Bernd Strieder <strieder@student.uni-kl.de> wrote
> > > You could use a private helper base class with public members.

On August 8, "Allan W" <Allan_W@my-dejanews.com> wrote
> >
> > In fact, you could use private helper static functions for use with
> > any member, including const members, references, and even base classes.
> >
> >     class Foo {
> >        // Possibly-overloaded functions used to initialize member x
> >        static X initX(int);
> >        static X initX(const char*);
> >        // Same for y and z
> >
> >     public:
> >        Foo(int a) : x(initX(a)), y(initY(a)), z(initZ(a)) { }
> >        Foo(const char *a) : x(initX(a)), y(initY(a)), z(initZ(a)) { }
> >     };
> >
> > This should satisfy the OP's desire to factor out common code, without
> > having to change the language.

You could also do this with non-static functions.

    Foo *newfoo(const char*a) {
        int b = /* whatever */;
        return new foo(b);
    }

> This would remove inconsistencies, but it a somewhat tedious task to
> do so.
In what way? The code has to go somewhere; why not in a static or
free function?

> Why should we be afraid of adding a new feauture to the language when
> it has no drawbacks, but large advantages?

I do see some drawbacks -- if only confusion about how it works.
Not insurmountable problems, probably -- but I just don't see the
advantages. What does it buy you that you don't already have?

(I can see some novices unintentionally creating dependancy loops:
two constructors which end up trying to call each other. The compiler
would reject it, but I want to see you try to write an error message
that this novice would understand!

   sample.cpp(25): Mutually-dependant constructors prohibited
(huh?)

   sample.cpp(25): Constructor foo(char*) calls constructor foo(int),
                   which already calls constructor foo(char*), and this
                   is not possible.
(huh?!?!?)

   sample.cpp(25): Problems with the constructor. See Thorsten Ottosen
                   for an explanation!

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Thorsten Ottosen" <nesotto@cs.auc.dk>
Date: 27 Aug 2002 20:45:15 GMT
Raw View
"Francis Glassborow" <francis.glassborow@ntlworld.com> wrote in
[snip]
> Tackling that is on the table for next time, but not that way but in a
> way consistent with the rest of the C++ constructor syntax.

Sure, I wasn't saying that, was I?

"Allan W" <Allan_W@my-dejanews.com> wrote in message
news:23b84d65.0208261615.3ebf523@posting.google.com...
> On July 31, David Schwartz wrote:
> > > > > I'm suggesting the ability to call a
> > > > > constructor for your own class in your initializer list.
>
> "Thorsten Ottosen" <nesotto@cs.auc.dk> wrote
> > I'm sure Stroupstrup has also thought about this.
> If so, he rejected it!
>
> (I think that D&C mentions it, but I don't have my copy handy...)

Sorry for not knowing what D&C is. I cannot mention m source, but I think it
must be Stroupstrup or
Sutter or some other important guy, maybe in CUJ.

> > Basically what we want is something similar to java's resuse
> > of constructors:
> >
> > class X
> > {
> >   private int x_, y_, z_;
>     // Java syntax will give you errors in C++!
>     // But I know what you meant.

Yes, I was writing C++ code. I think the headline "java's resuse of ..."
pointed that out ;-)

> >   X( int x, int y, int z)
> >  {
> >     x_ = ...;
> >     y_ = ...;
> >     z_ = ...;
> >   }
> >   X( int z )
> >   {
> >      this( 4,4, z ); // call X(int, int, int )
> >   }
> > }
> >
> > so that we can avoid potencial inconsistencies between constructors
> > initilization and type some less.
>
> Some of Java's problems don't apply to C++. Consider:
>
>     class Base {
>     protected:
>         int b1, b2;
>         static int calc( static int i = 0; return ++i; }
>     public:
>         Base(int b_1, int b_2) : b1(b_1), b2(b_2)
>             { std::cout << "Base(" << b_1 << ',' << b_2 << ")\n"; }
>         Base() { int c = calc(); this(c, c); } // Call Base(int,int)
>     }
>
> I think that's hard enough! The compiler has to push C onto the stack
> twice, as if it had been a parameter, and then jump to the other
> constructor.
I'm not really following you. What is your goal with all this? What are
Java's
problems? What is the problem with the code above? I guess you could leave
it
to me to figure out all your thought, but I would rather not. :) Please be
more precise,
and do tell me when I have to also.

>But what happens when we complicate the mix?
>
>     class Der : public Base {
>         int d1, d2;
>     public:
>         Der(int a, int b, int c, int d) : Base(a,b), d1(c), d2(d)
>             { std::cout << "Der(" << a << ',' << b << ',' << c
>                         << ',' << d << ")\n"; }
>         Der() { b1=calc(); b2=b1; this(b1,b2,0,0); }
>     }
>
> Should the second version of Der() overwrite the Base subobject as well?

Depends on what you mean with "overwrite". My suggestion is that
a call to 'this(...)' (or whatever syntax that will be used) should have the
same semantics as the constructor 'Der(...)' . I also think that any call to
'this(...)'
within a constructor (initialiser list?) should be the very first statement,
so your example

>         Der() { b1=calc(); b2=b1; this(b1,b2,0,0); }

wouldn't compile


> On August 1, Bernd Strieder <strieder@student.uni-kl.de> wrote
> > > > You could use a private helper base class with public members.
>
> On August 8, "Allan W" <Allan_W@my-dejanews.com> wrote
> > >
> > > In fact, you could use private helper static functions for use with
> > > any member, including const members, references, and even base
classes.
> > >
> > >     class Foo {
> > >        // Possibly-overloaded functions used to initialize member x
> > >        static X initX(int);
> > >        static X initX(const char*);
> > >        // Same for y and z
> > >
> > >     public:
> > >        Foo(int a) : x(initX(a)), y(initY(a)), z(initZ(a)) { }
> > >        Foo(const char *a) : x(initX(a)), y(initY(a)), z(initZ(a)) { }
> > >     };
> > >
> > > This should satisfy the OP's desire to factor out common code, without

> > > having to change the language.
>
> You could also do this with non-static functions.
>
>     Foo *newfoo(const char*a) {
>         int b = /* whatever */;
>         return new foo(b);
>     }
>
> > This would remove inconsistencies, but it a somewhat tedious task to
> > do so.
> In what way? The code has to go somewhere; why not in a static or
> free function?
>
> > Why should we be afraid of adding a new feauture to the language when
> > it has no drawbacks, but large advantages?
>
> I do see some drawbacks -- if only confusion about how it works.
> Not insurmountable problems, probably
No. Java's way is quite intuituve and simple. So should C++'s version be.

>-- but I just don't see the
> advantages. What does it buy you that you don't already have?

Shorter programs. The implications of short, terse programs
are many: better maintainance, lesser errors etc (not really a discussion we
need
to have here, though ).

I'm quite surprised that you don't see having an extra function(s) to
initialize
each data member as a problem/somthing that can be improved. The solution
with an
extra function is already too tedious for many to use it.

> (I can see some novices unintentionally creating dependancy loops:
> two constructors which end up trying to call each other. The compiler
> would reject it, but I want to see you try to write an error message
> that this novice would understand!
>
>    sample.cpp(25): Mutually-dependant constructors prohibited
> (huh?)
>
>    sample.cpp(25): Constructor foo(char*) calls constructor foo(int),
>                    which already calls constructor foo(char*), and this
>                    is not possible.
> (huh?!?!?)
>
>    sample.cpp(25): Problems with the constructor. See Thorsten Ottosen
>                    for an explanation!

Very funny. Here's some output from javac. Any solution should be able to
utter something similar.

Cons.java:8: call to this must be first statement in constructor
    this( 4, 4 );
        ^
Cons.java:13: recursive constructor invocation
    this( 3, 3 );
        ^

Actually, javac does not catch  Mutually-dependant constructors. I like that
one, though:

>sample.cpp(25): Mutually-dependant constructors prohibited

regards

Thorsten


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Allan_W@my-dejanews.com (Allan W)
Date: 28 Aug 2002 21:55:11 GMT
Raw View
> > On July 31, David Schwartz wrote:
> > > > > > I'm suggesting the ability to call a
> > > > > > constructor for your own class in your initializer list.

> > "Thorsten Ottosen" <nesotto@cs.auc.dk> wrote
> > > I'm sure Stroupstrup has also thought about this.

> "Allan W" <Allan_W@my-dejanews.com> wrote
> > If so, he rejected it!
> >
> > (I think that D&C mentions it, but I don't have my copy handy...)

"Thorsten Ottosen" <nesotto@cs.auc.dk> wrote
> Sorry for not knowing what D&C is.

"D&C" is "D&E" misspelled. "D&E" is "The Design and Evolution and C++"
by Stroustrup, as mentioned in the FAQ.

> > > Basically what we want is something similar to java's resuse
> > > of constructors:
> > >
> > > class X
> > > {
> > >   private int x_, y_, z_;
> >     // Java syntax will give you errors in C++!
> >     // But I know what you meant.
>
> Yes, I was writing C++ code. I think the headline "java's resuse of ..."
> pointed that out ;-)

But this isn't C++! Try putting a colen after the word private,
and then adding "public:" before any of the public methods.

> > >   X( int x, int y, int z)
> > >  {
> > >     x_ = ...;
> > >     y_ = ...;
> > >     z_ = ...;
> > >   }
> > >   X( int z )
> > >   {
> > >      this( 4,4, z ); // call X(int, int, int )
> > >   }
> > > }
> > >
> > > so that we can avoid potencial inconsistencies between constructors
> > > initilization and type some less.
> >
> > Some of Java's problems don't apply to C++. Consider:
> >
> >     class Base {
> >     protected:
> >         int b1, b2;
> >         static int calc( static int i = 0; return ++i; }
> >     public:
> >         Base(int b_1, int b_2) : b1(b_1), b2(b_2)
> >             { std::cout << "Base(" << b_1 << ',' << b_2 << ")\n"; }
> >         Base() { int c = calc(); this(c, c); } // Call Base(int,int)
> >     }
> >
> > I think that's hard enough! The compiler has to push C onto the stack
> > twice, as if it had been a parameter, and then jump to the other
> > constructor.
>
> I'm not really following you. What is your goal with all this? What
> are Java's problems? What is the problem with the code above? I guess
> you could leave it to me to figure out all your thought, but I would
> rather not. :) Please be more precise, and do tell me when I have to
> also.

I'm saying that constructors are not functions, not in the usual
sense. Having one constructor "call" another one isn't going to be
as simple as you seem to think, especially if the stack context
isn't the same.

> >But what happens when we complicate the mix?
> >
> >     class Der : public Base {
> >         int d1, d2;
> >     public:
> >         Der(int a, int b, int c, int d) : Base(a,b), d1(c), d2(d)
> >             { std::cout << "Der(" << a << ',' << b << ',' << c
> >                         << ',' << d << ")\n"; }
> >         Der() { b1=calc(); b2=b1; this(b1,b2,0,0); }
> >     }
> >
> > Should the second version of Der() overwrite the Base subobject as well?
>
> Depends on what you mean with "overwrite". My suggestion is that
> a call to 'this(...)' (or whatever syntax that will be used) should have the
> same semantics as the constructor 'Der(...)' .

But what happens when the object is already partially constructed, before
you call this(...)?

> I also think that any call to
> 'this(...)'
> within a constructor (initialiser list?) should be the very first statement,
> so your example
>
> >         Der() { b1=calc(); b2=b1; this(b1,b2,0,0); }
>
> wouldn't compile

I assumed that your call to this() had to be the very LAST statement.
Your whole point seemed to be that we could do intermediate computations
and then pass them to another constructor. But if it has to be the very
FIRST statement, then what use is it?

> >-- but I just don't see the
> > advantages. What does it buy you that you don't already have?
>
> Shorter programs. The implications of short, terse programs
> are many: better maintainance, lesser errors etc (not really a discussion we
> need
> to have here, though ).

Please demonstrate. Your first example did nothing to shorten the program.

> I'm quite surprised that you don't see having an extra function(s) to
> initialize
> each data member as a problem/somthing that can be improved. The solution
> with an
> extra function is already too tedious for many to use it.

Just you, AFAICS.

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Homer Meyer" <homer@cqg.com>
Date: 28 Aug 2002 22:30:05 GMT
Raw View
"Allan W" <Allan_W@my-dejanews.com> wrote in message
news:23b84d65.0208261615.3ebf523@posting.google.com...
<SNIP>
> I do see some drawbacks -- if only confusion about how it works.
> Not insurmountable problems, probably -- but I just don't see the
> advantages. What does it buy you that you don't already have?
>
> (I can see some novices unintentionally creating dependancy loops:
> two constructors which end up trying to call each other. The compiler
> would reject it, but I want to see you try to write an error message
> that this novice would understand!

I'm not sure that the compiler could reasonably detect it.  What happens
when the two constructors are in different translation units?



---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "James Russell Kuyper Jr." <kuyper@wizard.net>
Date: 28 Aug 2002 23:40:01 GMT
Raw View
Allan W wrote:
....
> I'm saying that constructors are not functions, not in the usual
> sense. Having one constructor "call" another one isn't going to be

Well, the standard calls them functions. They don't have names, which
makes it tricky to call them, but that's a different issue.

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Thorsten Ottosen" <nesotto@cs.auc.dk>
Date: Thu, 29 Aug 2002 16:34:19 CST
Raw View
"Allan W" <Allan_W@my-dejanews.com> wrote in message
news:23b84d65.0208281345.1410ffa1@posting.google.com...
[snip]
> > > Some of Java's problems don't apply to C++. Consider:
> > >
> > >     class Base {
> > >     protected:
> > >         int b1, b2;
> > >         static int calc( static int i = 0; return ++i; }
> > >     public:
> > >         Base(int b_1, int b_2) : b1(b_1), b2(b_2)
> > >             { std::cout << "Base(" << b_1 << ',' << b_2 << ")\n"; }
> > >         Base() { int c = calc(); this(c, c); } // Call Base(int,int)
> > >     }
> > >
> > > I think that's hard enough! The compiler has to push C onto the stack
> > > twice, as if it had been a parameter, and then jump to the other
> > > constructor.
> >
> > I'm not really following you. What is your goal with all this? What
> > are Java's problems?

Since I imag   ne something similar for C++, then what problems are you
talking about?

> I'm saying that constructors are not functions, not in the usual
> sense. Having one constructor "call" another one isn't going to be
> as simple as you seem to think, especially if the stack context
> isn't the same.

I wouldn't know. I'm just considering it from a programmers perspective, not
really how it is implemented.

> But what happens when the object is already partially constructed, before
> you call this(...)?
>
> > I also think that any call to
> > 'this(...)'
> > within a constructor (initialiser list?) should be the very first
statement,
> > so your example
> >
> > >         Der() { b1=calc(); b2=b1; this(b1,b2,0,0); }
> >
> > wouldn't compile
>
> I assumed that your call to this() had to be the very LAST statement.
> Your whole point seemed to be that we could do intermediate computations
> and then pass them to another constructor.
Where did I state that? I think that is your statement. Let's look at it
from the beginning:

1) David Schwartz wrote that it would be nice to replace
-----------------
class Foo
{
 Foo(int a) : x(1), y(2), z(3)
 {
  foo=a;
 }
 Foo(const char *a) : x(1), y(2), z(3)
 {
  bar=a;
 }
};
-------------
with
-------------
class Foo
{
 Foo(void) : x(1), y(2), z(3) // this can be private if it's not meant
for ordinary use
 {
  // code could go here, but needn't.
 }
 Foo(int a) : Foo()
 {
  // at this point, the object is technically fully constructed
  foo=a;
 }
 Foo(const char *a) : Foo()
 {
  bar=a;
 }
};
------------
2)  Bernd Strieder suggested to use a private base class:
-----------
struct FooBase
{
  FooBase(): x(1), y(2), z(3)
  {
  }

  int x;
  mnbv y;
  whatever z;
};

class Foo: private FooBase
{
public:
  Foo(int a) : FooBase()
  {
   // at this point, the object is technically fully constructed
   foo=a;
  }
  Foo(const char *a) : FooBase()
  {
   bar=a;
  }

private:
  lkjh foo;
  fghjk bar;

};
------------------
and he had some good points:
>All partaking
>constructor implementations would have to be visible at once to enable this
>at all, and it would require extensive code analysis. There is no way, IMO.
[..]
>Another point: FooBase is often a candidate for a usual public superclass,
>e.g. if some part of the Foo interface only deals with the members moved to
>FooBase, then this is a clear indication that a superclass with just that
>interface could be modelled.

I'm sure how often constructors are put into seperate compileations units,
but
I think it's very rare (am I right?). I also doubt that the code analysis
would be extensive.
(But we're getting a bit off track, since we're discusssing feature, not
their implementation,
 If compiler writers can implement template stuff, I think this is simply
compared to that.)
As for the public superclass thing, I think we need some good real-world
examples to see it. What if the new superclass doesn't make up a concept
on its own? What if I don't want to add a virtual destructor to my class
because of the overhead? And it might not be initialized in a private
constructor, recall
David Schwartz wrote:
> class Foo
> {
>  Foo(void) : x(1), y(2), z(3) // this can be private if it's not meant
> for ordinary use

The point is that the same initialization problems will emerge in the
superclass. At this point I was considering
writng only one big constructor with default arguments, like

class X
{
public:
   X( int i, int j= 0, int k = 0 ) : i_(i), j_(j), k_(k) { /* common code
here*/ }
 };

but this is less flexible if I want to do additional/different computations
in different
constructors.

3) Then you(Allan W) wrote
>In fact, you could use private helper static functions for use with
>any member, including const members, references, and even base classes.
>
>   class Foo {
>       // Possibly-overloaded functions used to initialize member x
>       static X initX(int);
>       static X initX(const char*);
>       // Same for y and z
>
>    public:
>       Foo(int a) : x(initX(a)), y(initY(a)), z(initZ(a)) { }
>      Foo(const char *a) : x(initX(a)), y(initY(a)), z(initZ(a)) { }
>    };
>
>This should satisfy the OP's desire to factor out common code, without
>having to change the language.

Which only allow common code that can be performed prior to the
construction of the object . It could easily be that the constructor body
contained code as well, code that relyed on all members to be fully
constructed. I don't know if you imagine that that common code could be put
in 'initZ()',
but what if I add a new member to the class, then I have to declare it
before 'z' or
move the code from 'initZ()' to 'initNewMember()'. This is messy.

 Moreover, my objection
against your code have always been that you still have to initialize each
member explicily, you just
do it with a function.   David Schwartz's initial wish was to get rid of
this which you didn't.


> But if it has to be the very
> FIRST statement, then what use is it?
If you want to do some initial statements, I guess you could do them using
the comma operator
inside the peer-constructor argument list.

> > >-- but I just don't see the
> > > advantages. What does it buy you that you don't already have?
> >
> > Shorter programs. The implications of short, terse programs
> > are many: better maintainance, lesser errors etc (not really a
discussion we
> > need
> > to have here, though ).
>
> Please demonstrate. Your first example did nothing to shorten the program.

Isn't it pretty obvious we cannot do this in today's standard C++:

class X
{
   int i_;
   int l_;
   int m_;
// you seemed to be stuck in the static initializer business
// so I keep them also to show there not interfering with the main issue
static int initI( int );
static int initL( int );
static int initM( int );
public:
  X( int i, int l ) : i_( initI(i) ), l_( initL(l) ), m_( initM(0) ) { }//
notice, only here are the initXXXs called
  X( int i ) : X( i,  0 ) { }
  X() : X( 0 ) { }
};

but has to code the initialization of  'm_' for _every_ constructor.

class X
{
  int i_;
  int l_;
  int m_;
static int initI( int );
static int initL( int );
static int initM( int );
  public:
  X( int i, int l ) : i_( initI(i) ), l_( initL(l) ), m_( initM(0) ) { }
  X( int i ) : i_( initI(i) ), l_( initL(0) ), m_( initM(0) ) { }
  X() : i_( initI(0) ), l_( initL(0) ), m_( initM(0) ) { }
};

Its not hard to imagine how tedious this becomes when the number of
construcotors grow and the membervariables
names get longer and meaningful. And I really wonder what you want to put
inside those initXXs functions.

That said, you seems to be talking about the ability to perform computations
before the arguments are handed to
the constructor. That's quite another issue and it shouldn't interfere with
this matter.

>
> > I'm quite surprised that you don't see having an extra function(s) to
> > initialize
> > each data member as a problem/somthing that can be improved. The
solution
> > with an
> > extra function is already too tedious for many to use it.
>
> Just you, AFAICS.
I see a potential use of static functions if some code is repeated within
the constructor body.

best regards

Thorsten



---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: 30 Aug 2002 15:55:18 GMT
Raw View
Allan_W@my-dejanews.com (Allan W) wrote in message
news:<23b84d65.0208281345.1410ffa1@posting.google.com>...

    [...]
> > I'm not really following you. What is your goal with all this? What
> > are Java's problems? What is the problem with the code above? I
> > guess you could leave it to me to figure out all your thought, but I
> > would rather not. :) Please be more precise, and do tell me when I
> > have to also.

> I'm saying that constructors are not functions, not in the usual
> sense. Having one constructor "call" another one isn't going to be as
> simple as you seem to think, especially if the stack context isn't the
> same.

If there is a call, a new stack context should be established.  I don't
think that this is the real problem.

> > >But what happens when we complicate the mix?
> > >
> > >     class Der : public Base {
> > >         int d1, d2;
> > >     public:
> > >         Der(int a, int b, int c, int d) : Base(a,b), d1(c), d2(d)
> > >             { std::cout << "Der(" << a << ',' << b << ',' << c
> > >                         << ',' << d << ")\n"; }
> > >         Der() { b1=calc(); b2=b1; this(b1,b2,0,0); }
> > >     }

> > > Should the second version of Der() overwrite the Base subobject as well?

> > Depends on what you mean with "overwrite". My suggestion is that a
> > call to 'this(...)' (or whatever syntax that will be used) should
> > have the same semantics as the constructor 'Der(...)' .

> But what happens when the object is already partially constructed,
> before you call this(...)?

In Java, this is forbidden.  If used, the call to this must be the first
statement in the constructor.

In C++, there are two complications:
  - The constructor actually starts by initializing the base classes and
    members, via the initialization list, and
  - C++ members can have value semantics, even those with non-trivial
    constructors, so you can't call their constructor twice.
Basically, I think that these considerations eliminate anything like the
Java syntax from consideration -- any use of another constructor must
take place before the initialization of the base classes and members,
and it must inhibit this initialization.

What I imagine should be possible would be a special, alternate syntax
for the initialization list.  Thus, instead of writing something like:

    C::C( int a, int b, int c )
        :   myA( a )
        ,   myB( b )
        ,   myC( c )
    {
    }

    C::C()
        :   myA(  5 )
        ,   myB( 10 )
        ,   myC( 15 )
    {
    }

I could implement the second constructor as:

    C::C()
        :   this( 5, 10, 15 )
    {
    }

This would have the effect of calling the three argument constructor of
C *IN* *PLACE* *OF* initializing the base class and members; the
initializations would take place in the three argument constructor, and
so should not be repeated.

Thus, the grammar at the top of 12.6.2 would become:

    ctor-initializer:
            : mem-initializer-list
            : this( expression-list )

The semantics of the second form would be to call the constructor
determined by the expression-list, and enter the body of this
constructor only after that constructor had terminated.

> > I also think that any call to
> > 'this(...)'
> > within a constructor (initialiser list?) should be the very first
> > statement, so your example

> > >         Der() { b1=calc(); b2=b1; this(b1,b2,0,0); }

> > wouldn't compile

> I assumed that your call to this() had to be the very LAST statement.

No.  Once you've started to construct the sub-members, it is impossible
to call any other constructor.

> Your whole point seemed to be that we could do intermediate
> computations and then pass them to another constructor. But if it has
> to be the very FIRST statement, then what use is it?

To factor out common behavior in the initialization.  Common behavior in
the body of the constructor, after initialization, can easily be
factored out by means of a member function, since all of the
initializations have taken place.  Common behavior in the
initializations themselves, however, cannot currently be factored out by
any means; it must be repeated in all constructors.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Thorsten Ottosen" <nesotto@cs.auc.dk>
Date: Mon, 26 Aug 2002 18:40:47 GMT
Raw View
[repost]
"Allan W" <Allan_W@my-dejanews.com> wrote in message
news:23b84d65.0208081116.56cb4544@posting.google.com...
> > David Schwartz wrote:
> > > I'm suggesting the ability to call a
> > > constructor for your own class in your initializer list.
>
I'm sure Stroupstrup has also thought about this. Basically what we want is
something similar to java's resuse of constructors:

class X
{
  private int x_, y_, z_;
  X( int x, int y, int z)
 {
    x_ = ...;
    y_ = ...;
    z_ = ...;
  }
  X( int z )
  {
     this( 4,4, z ); // call X(int, int, int )
  }
}

so that we can avoid potencial inconsistencies between constructors
initilization and type some less.

> Bernd Strieder <strieder@student.uni-kl.de> wrote
> > You could use a private helper base class with public members.
>
> In fact, you could use private helper static functions for use with
> any member, including const members, references, and even base classes.
>
>     class Foo {
>        // Possibly-overloaded functions used to initialize member x
>        static X initX(int);
>        static X initX(const char*);
>        // Same for y and z
>
>     public:
>        Foo(int a) : x(initX(a)), y(initY(a)), z(initZ(a)) { }
>        Foo(const char *a) : x(initX(a)), y(initY(a)), z(initZ(a)) { }
>     };
>
> This should satisfy the OP's desire to factor out common code, without
> having to change the language.

This would remove inconsistencies, but it a somewhat tedious task to do so.
Why should we
be afraid of adding a new feauture to the language when it has no drawbacks,
but large
advantages?

-Thorsten, AAU


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: David Schwartz <davids@webmaster.com>
Date: Wed, 31 Jul 2002 15:02:18 GMT
Raw View
 Sometimes you have to make an unpleasant choice when you have a few
constructors that have a lot of code in common. If that code involves,
for example, constructing const members, you can't put that common code
in a function. For example:

class Foo
{
 Foo(int a) : x(1), y(2), z(3)
 {
  foo=a;
 }
 Foo(const char *a) : x(1), y(2), z(3)
 {
  bar=a;
 }
};

 If there are lots of constructors and/or lots of initializers, this can
be very tedious and error-prone. I'm suggesting the ability to call a
constructor for your own class in your initializer list. For example:

class Foo
{
 Foo(void) : x(1), y(2), z(3) // this can be private if it's not meant
for ordinary use
 {
  // code could go here, but needn't.
 }
 Foo(int a) : Foo()
 {
  // at this point, the object is technically fully constructed
  foo=a;
 }
 Foo(const char *a) : Foo()
 {
  bar=a;
 }
};

 This way, the initializer list lives in only one place. Also, any code
needed to sanitize the object to a state where it can be 'tweaked' as
needed can be put in one (and only one) place.

 DS

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Maciej Sobczak" <maciej@maciejsobczak.com>
Date: Wed, 31 Jul 2002 18:06:08 GMT
Raw View
Hello,

"David Schwartz" <davids@webmaster.com> wrote in message
news:3D4783BD.C39A5D51@webmaster.com...

> class Foo
> {
>  Foo(void) : x(1), y(2), z(3) // this can be private if it's not meant
> for ordinary use
>  {
>   // code could go here, but needn't.
>  }
>  Foo(int a) : Foo()
>  {
>   // at this point, the object is technically fully constructed
>   foo=a;
>  }
>  Foo(const char *a) : Foo()

You may also wish to initialize the bar member in the initializer list here:

Foo(const char *a) : Foo(), bar(a)
{
}

but... what if bar has been already initialized in the Foo()?
You could also wish to initialize some base subobject this way.

The language would need to enforce the rule that each member (and base
subobject) can be initialized only once, which can get tricky if the number
of constructors that call each other grows.
Now this rule is obvious without imposing any checks.

Are you sure that refactoring the initializer list (because this is what you
want, as I understand) justifies introducing these checks and rules?

Regards,

--
Maciej Sobczak
http://www.maciejsobczak.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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Bernd Strieder <strieder@student.uni-kl.de>
Date: Thu, 1 Aug 2002 08:53:40 GMT
Raw View
David Schwartz wrote:

>
> Sometimes you have to make an unpleasant choice when you have a few
> constructors that have a lot of code in common. If that code involves,
> for example, constructing const members, you can't put that common code
> in a function. For example:
> [...]
> If there are lots of constructors and/or lots of initializers, this can
> be very tedious and error-prone. I'm suggesting the ability to call a
> constructor for your own class in your initializer list. For example:
>
> class Foo
> {
>  Foo(void) : x(1), y(2), z(3) // this can be private if it's not meant
> for ordinary use
>  {
>   // code could go here, but needn't.
>  }
>  Foo(int a) : Foo()
>  {
>   // at this point, the object is technically fully constructed
>   foo=a;
>  }
>  Foo(const char *a) : Foo()
>  {
>   bar=a;
>  }
> };
>
> This way, the initializer list lives in only one place. Also, any code
> needed to sanitize the object to a state where it can be 'tweaked' as
> needed can be put in one (and only one) place.

You could use a private helper base class with public members. Most of the
Foo code could remain unchanged.

struct FooBase
{
  FooBase(): x(1), y(2), z(3)
  {
  }

  int x;
  mnbv y;
  whatever z;
};

class Foo: private FooBase
{
public:
  Foo(int a) : FooBase()
  {
   // at this point, the object is technically fully constructed
   foo=a;
  }
  Foo(const char *a) : FooBase()
  {
   bar=a;
  }

private:
  lkjh foo;
  fghjk bar;

};

What you suggested would require the compiler to determine subobjects like
that FooBase itself to maintain the rule that every member is constructed
exactly once. Since every constructor should initialize all members when
called directly, there would have to be at least two variants of each
constructor, one constructing all members, and one constructing only an
essential set of members leaving the others to the caller. All partaking
constructor implementations would have to be visible at once to enable this
at all, and it would require extensive code analysis. There is no way, IMO.

Another point: FooBase is often a candidate for a usual public superclass,
e.g. if some part of the Foo interface only deals with the members moved to
FooBase, then this is a clear indication that a superclass with just that
interface could be modelled.

Bernd Strieder


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]