Topic: Default initializers, why not???


Author: jason@cygnus.com (Jason Merrill)
Date: 08 Mar 1995 19:22:22 GMT
Raw View
>>>>> John Max Skaller <maxtal@Physics.usyd.edu.au> writes:

>  Yes. Of course, MY interpretation of rvalues is that
> they are executable functions which can _initialise_ a storage
> location (usually a temporary).

This is essentially how rvalues of class types that define constructors are
represented in g++.

Jason




Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sat, 11 Mar 1995 05:35:11 GMT
Raw View
smeyers@netcom.com (Scott Meyers) writes:

>maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>|  class X {
>|   const int n = 1; // permitted
>|  };
>|  const int X::n; // required still
>
>I thought this was only true if n was static.  Does this work for
>non-statics, too?  It makes no sense to have an out-of-line definition for
>a non-static.

You're correct, it is only allowed for static constants.

--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: tony@online.tmx.com.au (Tony Cook)
Date: Wed, 8 Mar 1995 01:27:59 GMT
Raw View
John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
: In article <D4w2z7.Mnx@online.tmx.com.au>,
: Tony Cook <tony@online.tmx.com.au> wrote:
: >John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
: >:  Because I wrote a proposal that specified just that and
: >: it was rejected. Complain at the time of the ANSI public review
: >: if you want that behaviour.
: >
: >: [Instead, the completely useless subcase of my proposal
: >: was adopted --
: >
: >:  class X {
: >:   const int n = 1; // permitted
: >:  };
: >:  const int X::n; // required still
: >
: >: This is the one case where no extension was needed --
: >
: >:  class X { enum {n=1}; }
: >
: >But it's ugly and non-obvious and was unfortunately the only way to
: >do it.
: >
: >Now you can use the part of the language (const) that is meant for
: >this purpose.

:  No.

:  const int n=10;

: declares an _variable_ whereas

Are you saying 'const' is not _meant_ for defining semantic
constants?  I'm not saying that 'const int n = 10;' is exactly the
same as 'enum {n=10};' - it isn't.

:  enum {n=1}

: declares a constant. in particular the first "n" is addressable,
: the second is not. So the first has to be allocated.

:  #define N 10

: is actually more powerful because the pre-processor knows about it.

:  define int n=10;

: is what I would have done.

I very much wish for something clean with the same meaning as this,
but also with this meaning for non-basic types (such as strings).

Currently I have to use #define for this type of thing - otherwise
the compiler generates an initialised variable.
--
        Tony Cook - tony@online.tmx.com.au
                    100237.3425@compuserve.com




Author: jones@cais3.cais.com (Ben Jones)
Date: 7 Mar 1995 03:59:32 GMT
Raw View
In article <rogerrD4qopo.1B9@netcom.com> Roger Reynolds wrote:
: Here is a little thing that has bugged me for some months now.

: Why can we not provide default values for data members of
: a class at the point where they are defined?

: For example, wouldn't this:

:  class foo {
:   foo(){}
:   ~foo(){}
:   int a(1), b(2);
:   String c("abcdefg");
:  }

: Be better than this:

:  class foo {
:   foo () : a(1), b(2), c("abcdefh") {}
:   ~foo(){}
:   int a, b;
:   String c;
:  }

: Now, I will readily concede that in this trivial example, this matter
: is indeed trivial.  But, when you start to get classes that are
: a) are split between .h and .cc files, and b) have multiple constructors,
: I think it is clear that the first method would be preferable.

It would be nicer still if you didn't always have to split your classes
between .h and .cc files but simply declared an "exportable class" with
initializations and function bodies (marking explicitly the functions you
want to be inline).  The interface would be generated automatically by
extracting the declarations.  Static members would be initialized in the
exporting module.  Non-static members initializations would be included
in the constructor, which may or may not be declared inline.  For example:

    export class foo
    {
        int a = 1, b = 2;
  String c("abcdefg");

        static int s = 100;

 int f() { ... }
        inline int g() { ... }
    }

would generate an interface:

    class foo
    {
        foo();
        ~foo(){}
        int a,b;
 String c;
        static int s;

        int f();
        int g() { ... }
    };

and then generate a module which includes the above declaration
plus the following code:

    foo::foo():a(1),b(d),c("abcdef") {}

    int foo::s = 100;

    int foo::f() { ... }

The mere fact of inheriting "foo" would import the exported interface:

    export class fooey: foo { ... }

Such a scheme has been implemented in an experimental C++ preprocessor
called ARC++.  For further information, please contact:

    ARSoftware Corporation
    8201 Corporate Drive #1110
    Landover, MD 20785 USA
    (301) 459-3773
    (800) 257-0073
    jones@arsoftware.arclch.com
    arsoftware@aol.com





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Wed, 8 Mar 1995 03:59:53 GMT
Raw View
In article <D53LEn.KsL@online.tmx.com.au>,
Tony Cook <tony@online.tmx.com.au> wrote:

>:  const int n=10;
>
>: declares an _variable_ whereas
>
>Are you saying 'const' is not _meant_ for defining semantic
>constants?

 I don't care what was _meant_, the fact is that
such a statement declares an entity which denotes an _object_
and not a _value_.

 In my terminology, a constant is a value,
and an immutable variable is a variable all the same,
even if the set of values it can vary over is exactly 1. :-)

>:  enum {n=1}
>
>: declares a constant.

 That is, "n" is a symbolic constant. The other kind
of constant I call a literal. 1 is a literal. The distinction
is in the form of the names, both are constants. Neither have
addresses because they are values not objects.

>in particular the first "n" is addressable,

 So it is an immutable variable initialised to some
value. Not a constant. (Its value is certainly invariant,
that is, its value can be said to be constant, but it is not
in itself "a" constant :-)

>:  define int n=10;
>
>: is what I would have done.
>
>I very much wish for something clean with the same meaning as this,
>but also with this meaning for non-basic types (such as strings).

 A constant of a class type can't exist. The closest
thing we might get is

 define string s = "Hello";
 .. &s .. // ERROR: take address of rvalue

that is, "define" introduces an rvalue rather than an lvalue.

>Currently I have to use #define for this type of thing - otherwise
>the compiler generates an initialised variable.

 Yes. Of course, MY interpretation of rvalues is that
they are executable functions which can _initialise_ a storage
location (usually a temporary). But the committee insists
that rvalues of class type actually _denote_ objects.

 In my interpretation

 define string s = "Hello"

s is an rvalue and it does NOT denote an object. So nothing
is allocated. If you write:

  string x = s;

_then_ of course x is allocated.

The main differences between these approaches is:

 1) my approach permits explicit statement of constraints,
 so that violations can be detected, and optimisations
 assured

 2) the committee approach is to make the compiler deduce
 the constraint if it wants to do any optimisations;
 the programmer can accidentally violate some intent
 and not get a message

A similar case is "register". In C++ you can take the address
of a register. I would have disallowed that. I like code
to express intended constraints, and have violations
of my intentions diagnosed.


BTW: I would also permit

 define i = 1; // no type given
 declare i = 1; // no type given
 declare const i = 1; // no type given

This kind of type deduction is already permformed by templates.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: u865151@student.canberra.edu.au (Burger / John Adriaan (ISE))
Date: Sun, 5 Mar 95 19:24:03 GMT
Raw View
In article <rogerrD4qopo.1B9@netcom.com>,
roger reynolds <rogerr@netcom.com> wrote:

[Rest snipped to highlight this question]

>The only reason I can think of is that the initialization list lets you
>specify the order in which things are initialized. BFD I say.
>And of course, if cases where the order is important, you could create an
>init proc as described above.

Surely this is incorrect? I thought that different constructors for the
same class executed their initialiser lists in the same order (namely,
the order they were defined in the class) regardless of the order they
appeared in the initialiser lists, so that the destructor could guarantee
they were destructed in reverse order? Otherwise, wouldn't the initialisation
order have to be saved so that the single destructor could destruct them in
the required order?

I know I've observed this behaviour while debugging constructor calls!

John "Then again, I could be wrong. I often am." Burger




Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 6 Mar 1995 00:37:45 GMT
Raw View
u865151@student.canberra.edu.au (Burger / John Adriaan (ISE)) writes:

>roger reynolds <rogerr@netcom.com> wrote:
>
>>The only reason I can think of is that the initialization list lets you
>>specify the order in which things are initialized.
>
>Surely this is incorrect? I thought that different constructors for the
>same class executed their initialiser lists in the same order (namely,
>the order they were defined in the class) regardless of the order they
>appeared in the initialiser lists, so that the destructor could guarantee
>they were destructed in reverse order? Otherwise, wouldn't the initialisation
>order have to be saved so that the single destructor could destruct them in
>the required order?

Absolutely right.

>John "Then again, I could be wrong. I often am." Burger

Not this time ;-)

--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: osinski@hellgate.cs.nyu.edu (Ed Osinski)
Date: 6 Mar 1995 20:39:49 GMT
Raw View
In article <03MAR95.16935419.0153@SDSUMUS.SDSTATE.EDU>, Chris Engebretson <E8AG@SDSUMUS.SDSTATE.EDU> writes:
|> In article <rogerrD4qopo.1B9@netcom.com> rogerr@netcom.com (roger reynolds) writes:
|> >Here is a little thing that has bugged me for some months now.
|> >
|> >Why can we not provide default values for data members of
|> >a class at the point where they are defined?
|> >
|> >For example, wouldn't this:
|> >
|> > class foo {
|> >  foo(){}
|> >  ~foo(){}
|> >  int a(1), b(2);
|> >  String c("abcdefg");
|> > }
|>
|> Cannot be done, and for a reason:
|> When a class is instantiated ...
|>
|> 1) Space for the data members is allocated
|> 2) The data members are initialized as per the initialization list
|>    of the *constructor that is being used* .. (consts are also
|>    enforced at this time...)
|> 3) The constructor body is executed.

I missed the reason.  If you are just saying that it doesn't work because the
current rules simply do not allow it, fine.  But you don't give any reason
above why these rules cannot be changed.

|> >Now, I will readily concede that in this trivial example, this matter
|> >is indeed trivial.  But, when you start to get classes that are
|> >a) are split between .h and .cc files, and b) have multiple constructors,
|> >I think it is clear that the first method would be preferable.
|>
|> Hmmm ... can't you think of any situation where it you would need to
|> initialize data members DIFFERENTLY based on which constructor is being
|> used to instantiate the class? :)

Yes, of course, and there are (at least) two possible solutions:

1) If the data member is explicitly initialized in the declaration, it cannot
   be explicitly initialized in any constructor's initialization list.
2) If the data member is explicitly initialized in a constructor's
   initialization list, that initialization simply overrides the one specified
   at the data member's declaration.

Solution (1) has the virtue of simplicity, but forces the programmer to change
the class declaration *and* existing constructors in order to allow a new
constructor to initialize a member differently.

--
---------------------------------------------------------------------
 Ed Osinski                  |
 Computer Science Department | "Do I know you?
 New York University         |  And don't try to deny it!"
 E-mail:  osinski@cs.nyu.edu |                 Col. Flagg to Hawkeye
---------------------------------------------------------------------




Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Mon, 6 Mar 1995 02:47:12 GMT
Raw View
In article <smeyersD4vp0F.46J@netcom.com>,
Scott Meyers <smeyers@netcom.com> wrote:
>In article <D4uq8r.LnD@ucc.su.OZ.AU> maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>|  class X {
>|   const int n = 1; // permitted
>|  };
>|  const int X::n; // required still
>
>I thought this was only true if n was static.  Does this work for
>non-statics, too?  It makes no sense to have an out-of-line definition for
>a non-static.

 Woops.

 static const int n = 1;
--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: pde@zoo.bt.co.uk (Paul D Evans)
Date: 5 Mar 1995 18:11:18 GMT
Raw View
In article 1B9@netcom.com, rogerr@netcom.com (roger reynolds) writes:

[stuff deleted]

> The only reason I can think of is that the initialization list lets you
> specify the order in which things are initialized.

No.  ARM 12.6.2:

First, the base classes are intialised in declaration order
(independent of the order of [the initialisation list]), then the members
are initialised in declaration order (independent of the order
of [the initialisation list]), then the body of [the ctor] is
executed.

---
                      ,')
-__ /\\                /|
  ||  \\   _           ||
 /||__||  < \, '\ /\\  ||        pde@zoo.bt.co.uk
 \||__||  /-||  || ||  ||
  ||  |, (( ||  || ||  ||               "Close this book at once,
_-||-_/   \/\\   \\/   |/   it's full of lies!"
  ||                   (_ _  The Book of Bokannon
                         -






Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Tue, 7 Mar 1995 14:44:22 GMT
Raw View
In article <D4w2z7.Mnx@online.tmx.com.au>,
Tony Cook <tony@online.tmx.com.au> wrote:
>John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
>:  Because I wrote a proposal that specified just that and
>: it was rejected. Complain at the time of the ANSI public review
>: if you want that behaviour.
>
>: [Instead, the completely useless subcase of my proposal
>: was adopted --
>
>:  class X {
>:   const int n = 1; // permitted
>:  };
>:  const int X::n; // required still
>
>: This is the one case where no extension was needed --
>
>:  class X { enum {n=1}; }
>
>But it's ugly and non-obvious and was unfortunately the only way to
>do it.
>
>Now you can use the part of the language (const) that is meant for
>this purpose.

 No.

 const int n=10;

declares an _variable_ whereas

 enum {n=1}

declares a constant. in particular the first "n" is addressable,
the second is not. So the first has to be allocated.

 #define N 10

is actually more powerful because the pre-processor knows about it.


 define int n=10;

is what I would have done.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Fri, 3 Mar 1995 06:34:02 GMT
Raw View
In article <rogerrD4qopo.1B9@netcom.com>,
roger reynolds <rogerr@netcom.com> wrote:
>Here is a little thing that has bugged me for some months now.
>
>Why can we not provide default values for data members of
>a class at the point where they are defined?
>

 Because I wrote a proposal that specified just that and
it was rejected. Complain at the time of the ANSI public review
if you want that behaviour.

[Instead, the completely useless subcase of my proposal
was adopted --

 class X {
  const int n = 1; // permitted
 };
 const int X::n; // required still

This is the one case where no extension was needed --

 class X { enum {n=1}; }

already works and is superior (no definition is needed)]


--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: rogerr@netcom.com (roger reynolds)
Date: Wed, 1 Mar 1995 02:10:36 GMT
Raw View
Here is a little thing that has bugged me for some months now.

Why can we not provide default values for data members of
a class at the point where they are defined?

For example, wouldn't this:

 class foo {
  foo(){}
  ~foo(){}
  int a(1), b(2);
  String c("abcdefg");
 }

Be better than this:

 class foo {
  foo () : a(1), b(2), c("abcdefh") {}
  ~foo(){}
  int a, b;
  String c;
 }


Now, I will readily concede that in this trivial example, this matter
is indeed trivial.  But, when you start to get classes that are
a) are split between .h and .cc files, and b) have multiple constructors,
I think it is clear that the first method would be preferable.

Of course, I would still allow the ability to initialize elements in
the constructor list, for cases where you want to initialize elements from
args in the constructor, and so on.

I suppose there is some good reason why it is this way, but it sure
seems silly and makes for alot of extra unnecessary verbiage in the code.

Someone will no doubt suggest creating a common initialize procedure that
is used by all constructors, but that is just adding more complexity
to code which should be simple.

The only reason I can think of is that the initialization list lets you
specify the order in which things are initialized. BFD I say.
And of course, if cases where the order is important, you could create an
init proc as described above.


Thanks for letting me vent...
rogerr@netcom.com




Author: smeyers@netcom.com (Scott Meyers)
Date: Fri, 3 Mar 1995 19:05:03 GMT
Raw View
In article <D4uq8r.LnD@ucc.su.OZ.AU> maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
|  class X {
|   const int n = 1; // permitted
|  };
|  const int X::n; // required still

I thought this was only true if n was static.  Does this work for
non-statics, too?  It makes no sense to have an out-of-line definition for
a non-static.

| This is the one case where no extension was needed --
|
|  class X { enum {n=1}; }
|
| already works and is superior (no definition is needed)]

But is opaque as Hell.  The special case allowed above makes things much
easier to understand, especially for people who have more to do in life
than just study the semantics of C++.

Scott




Author: tob@world.std.com (Tom O Breton)
Date: Wed, 1 Mar 1995 22:12:53 GMT
Raw View
rogerr@netcom.com (roger reynolds) writes:
> Someone will no doubt suggest creating a common initialize procedure
> that is used by all constructors, but that is just adding more
> complexity to code which should be simple.

What will sometimes work is...

struct
S       {
        S( void ) { /* some stuff */ };
        S( int )
                {
                /* other stuff */;
                new( this ) S;  /* Call the CTOR ( void ) */
                };
        };

However, it is not always legal. For instance, if some elements require
initialization, no go. And you have to have a placement new( void*
address ) operator available.

One solution might be to fortify this mechanism a bit so a compiler
could recognize that another CTOR was called to initialize elements. And
incidentally drop the placement new, which is basically a workaround.

Perhaps:

        S( int )
                {
                /* other stuff */;
                } = S(); /* Call the CTOR ( void ) */



> The only reason I can think of is that the initialization list lets you
> specify the order in which things are initialized. BFD I say.

Actually, an init list does _not_ specify the order.

BFD?

        Tom

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





Author: tony@online.tmx.com.au (Tony Cook)
Date: Sat, 4 Mar 1995 00:06:43 GMT
Raw View
John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
:  Because I wrote a proposal that specified just that and
: it was rejected. Complain at the time of the ANSI public review
: if you want that behaviour.

: [Instead, the completely useless subcase of my proposal
: was adopted --

:  class X {
:   const int n = 1; // permitted
:  };
:  const int X::n; // required still

: This is the one case where no extension was needed --

:  class X { enum {n=1}; }

But it's ugly and non-obvious and was unfortunately the only way to
do it.

Now you can use the part of the language (const) that is meant for
this purpose.
--
        Tony Cook - tony@online.tmx.com.au
                    100237.3425@compuserve.com




Author: Chris Engebretson <E8AG@SDSUMUS.SDSTATE.EDU>
Date: 03 MAR 95 15:40:51 CDT
Raw View
In article <rogerrD4qopo.1B9@netcom.com> rogerr@netcom.com (roger reynolds) writes:
>Here is a little thing that has bugged me for some months now.
>
>Why can we not provide default values for data members of
>a class at the point where they are defined?
>
>For example, wouldn't this:
>
> class foo {
>  foo(){}
>  ~foo(){}
>  int a(1), b(2);
>  String c("abcdefg");
> }

Cannot be done, and for a reason:
When a class is instantiated ...

1) Space for the data members is allocated
2) The data members are initialized as per the initialization list
   of the *constructor that is being used* .. (consts are also
   enforced at this time...)
3) The constructor body is executed.

>Now, I will readily concede that in this trivial example, this matter
>is indeed trivial.  But, when you start to get classes that are
>a) are split between .h and .cc files, and b) have multiple constructors,
>I think it is clear that the first method would be preferable.

Hmmm ... can't you think of any situation where it you would need to
initialize data members DIFFERENTLY based on which constructor is being
used to instantiate the class? :)

>I suppose there is some good reason why it is this way, but it sure
>seems silly and makes for alot of extra unnecessary verbiage in the code.

See above. It's how object classes are instantiated.

>The only reason I can think of is that the initialization list lets you
>specify the order in which things are initialized. BFD I say.
>And of course, if cases where the order is important, you could create an
>init proc as described above.

The initialization list lets you specify the order of initialization?

class employee
{
     long ssn;
     double salary;
     public:
     employee(long = 0L, float = 0.0);
};

inline employee::employee(long n, double s): salary(s), ssn(n) {}

Actually, it's declaration order that governs the order in which data
members are initialized. In the above simple example, ssn get
initialized first because it appears first. The order of items in the
initialization list has nothing do do with order of initialization.

>Thanks for letting me vent...
>rogerr@netcom.com

You're welcome. :) Hope this clears some things up.

- Chris