www.digitalmars.com         C & C++   DMDScript  

D - vpt initialized before constructor?

reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
Hi,

hm, if I got it right:

- the vp-table is initialized, and the members are set to something static
before the constructor is called
- you can call funktions from within the construktor. These are dynamically
linked (since the vpt exist).

This means, that within any member-function, there could be 2 states:

- The own constructor could be completed successfull - all is ok
- The function is called from a constructor (or a function the constructor
called...). This means, the
member-variables are initialized with default values, given at compile time.


Isn't this bad?

- Either I assume the default values for members are alright and valid - so
I need no constructor at
all and can take this() {} out of language?
- Or I assume, static linked default values are not enough, but members will
be filled within
the constructor - so I have to check the members in each member-function
whether they already
initialized or not.

Are there a solution?

Imi
Mar 05 2002
next sibling parent reply "Walter" <walter digitalmars.com> writes:
What happens is a static initializer is prepared for each class. Memory is
allocated and the static initializer is copied over it. Then, the
constructor is called.

This ensures that within the constructor the object is in a defined state,
virtual functions can be called, and all members are initialized to the
default value. For many (if not most) classes, this is sufficient and it is
not even necessary to have a constructor. It guarantees no more bugs due to
adding a member and forgetting to initialize it in one of the constructors.

Constructors are only necessary if any dynamic initialization is needed.

"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a630s6$241$1 digitaldaemon.com...
 Hi,

 hm, if I got it right:

 - the vp-table is initialized, and the members are set to something static
 before the constructor is called
 - you can call funktions from within the construktor. These are

 linked (since the vpt exist).

 This means, that within any member-function, there could be 2 states:

 - The own constructor could be completed successfull - all is ok
 - The function is called from a constructor (or a function the constructor
 called...). This means, the
 member-variables are initialized with default values, given at compile

 Isn't this bad?

 - Either I assume the default values for members are alright and valid -

 I need no constructor at
 all and can take this() {} out of language?
 - Or I assume, static linked default values are not enough, but members

 be filled within
 the constructor - so I have to check the members in each member-function
 whether they already
 initialized or not.

 Are there a solution?

 Imi

Mar 05 2002
next sibling parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Walter" <walter digitalmars.com> schrieb im Newsbeitrag
news:a634fp$3p4$1 digitaldaemon.com...
 What happens is a static initializer is prepared for each class. Memory is
 allocated and the static initializer is copied over it. Then, the
 constructor is called.

 This ensures that within the constructor the object is in a defined state,
 virtual functions can be called, and all members are initialized to the
 default value. For many (if not most) classes, this is sufficient and it

 not even necessary to have a constructor. It guarantees no more bugs due

 adding a member and forgetting to initialize it in one of the

 Constructors are only necessary if any dynamic initialization is needed.

This happens due you presume that a "defined state" is some static value. So you could consider to forbid the constructor to alter the member variables and only allow static pre-constructor-constructs? This means, the problem (stated best in the other posting to Pavel) vanished, but many coders will kill you for this ;) Imi
Mar 05 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a636cb$4fo$1 digitaldaemon.com...

 This happens due you presume that a "defined state" is some static value.
 So you could consider to forbid the constructor to alter the member
 variables and only allow static pre-constructor-constructs?
 This means, the problem (stated best in the other posting to Pavel)
 vanished, but many coders will kill you for this ;)

If you forbid constructor to modify member variables, it simply loses sense... moreover, it is easy overridden by: class Foo { int bar; this() { init(); } // I don't modify anything... init() { bar = 666; } // muhahahahahaha! =) }
Mar 05 2002
parent reply "Immanuel Scholz" <digitals-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a637u0$57f$1 digitaldaemon.com...
 "Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
 news:a636cb$4fo$1 digitaldaemon.com...

 This happens due you presume that a "defined state" is some static


 So you could consider to forbid the constructor to alter the member
 variables and only allow static pre-constructor-constructs?
 This means, the problem (stated best in the other posting to Pavel)
 vanished, but many coders will kill you for this ;)

If you forbid constructor to modify member variables, it simply loses sense... moreover, it is easy overridden by:

Of course, then the constructor have no rights to call non-const member functions ;-)
     class Foo
     {
         int bar;

         this() { init(); }     // I don't modify anything...
         init() { bar = 666; }  // muhahahahahaha! =)
     }

I was joking. Of course it would be a bad idea to forbid the constructor to alter members. But I would state, that it is also a joke to blindly assume, that static values to variables are enough of initialisation. Maybe if the constructor is only allowed to call "final" - member functions? Imi
Mar 06 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
news:a65256$vqj$1 digitaldaemon.com...

 Of course, then the constructor have no rights to call non-const
 member functions ;-)

D doesn't have const and non-const functions, because D doesn't have const objects. How'd you declare them in D anyhow?
 But I would state, that it is also a joke to blindly assume, that static
 values
 to variables are enough of initialisation.

Definitely not. That's what the constructor is for.
 Maybe if the constructor is only allowed to call "final" - member

So what? class Foo { this() { init(); } final void init() { foo(); } void foo() { ... } }
Mar 06 2002
next sibling parent reply "Immanuel Scholz" <digitals-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a659c9$12o6$1 digitaldaemon.com...
 "Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
 news:a65256$vqj$1 digitaldaemon.com...

 Of course, then the constructor have no rights to call non-const
 member functions ;-)

D doesn't have const and non-const functions, because D doesn't have const objects. How'd you declare them in D anyhow?

Hmm... Yes. Why doesn't D support const functions and classes? I thought they cast away more problems than they do? (And they give the compiler the chance to optimization). I like const functions...
 But I would state, that it is also a joke to blindly assume, that static
 values
 to variables are enough of initialisation.

Definitely not. That's what the constructor is for.

Ack. So it is too bad to have that hole (as stated in this thread) in D.
 Maybe if the constructor is only allowed to call "final" - member

So what? class Foo { this() { init(); } final void init() { foo(); } void foo() { ... } }

Oh dear, you are right. So this makes no sense too.. I become thinking that static linkage within constructors is the best solution (The solution to ignore this problem will make me to not look any futher on D, because I do not believe you could write a library as like as QT or MFC on such a base without ever and ever checking member-variables in functions :-( ) Imi
Mar 06 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
news:a65kdh$17b2$1 digitaldaemon.com...

 Hmm... Yes.

 Why doesn't D support const functions and classes? I thought they
 cast away more problems than they do? (And they give the compiler the
 chance to optimization).

 I like const functions...

Const functions operate only on const objects. And you cannot have const objects in D, since no objects are on stack, and all constants must be literals: Object foo; // actually a pointer to foo const Object bar; // impossible: no initializer! const Object baz = new Object; // wrong: constant expression required
 Oh dear, you are right. So this makes no sense too.. I become thinking
 that static linkage within constructors is the best solution (The solution

Is it? class Foo { int n; this() { init(); n = 666; } // calls init() statically void init() { foo(); } // calls foo() dynamically via vtable void foo() { ... } } class Bar: Foo { void foo() { printf("%d", n); } } Piece of cake! =)
Mar 06 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a65n8o$18jp$1 digitaldaemon.com...
 "Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
 news:a65kdh$17b2$1 digitaldaemon.com...

 Hmm... Yes.

 Why doesn't D support const functions and classes? I thought they
 cast away more problems than they do? (And they give the compiler the
 chance to optimization).

 I like const functions...

Const functions operate only on const objects. And you cannot have const objects in D, since no objects are on stack, and all constants must be literals: Object foo; // actually a pointer to foo const Object bar; // impossible: no initializer! const Object baz = new Object; // wrong: constant expression required

Hm... I do not understand, why this should be a problem. With my conses of const, you can only initialize a const object, but never assign to it (or call non-const functions) and of course, you can only initialize any object-instance once. Whether the object is on the heap or stack or static or not doesnt matter. Object foo; // agreed, its a pointer. (a non-const one..) const Object bar; // bar is just initialized and then, compiler forbids to // call non-const functions (e.g. operator= is non-const) const Object baz = new Object; // the object baz is only initialized once, // with the copy-constructor. There is no assignment or anything like // two initialisations. Also no temporary object is created. So wheres the problem with const and no stack-variables? (Hm, maybe we get this part of the posting to a new thread? ;-)
 Oh dear, you are right. So this makes no sense too.. I become thinking
 that static linkage within constructors is the best solution (The


 Is it?

     class Foo
     {
         int n;
         this() { init(); n = 666; }        // calls init() statically
         void init() { foo(); }    // calls foo() dynamically via vtable
         void foo() { ... }
     }

     class Bar: Foo
     {
         void foo() { printf("%d", n); }
     }

 Piece of cake! =)

No, piece of sh**t, because the vtable is initialized, when the constructor finished successful, so all calls, even the foo() will be static linked (no vpt - no dynamic linkage - no surprises with functions called before constructor finished)
Mar 06 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a65pp1$19kf$1 digitaldaemon.com...

 Object foo;    // agreed, its a pointer. (a non-const one..)
 const Object bar;  // bar is just initialized and then, compiler forbids

 // call non-const functions (e.g. operator= is non-const)
 const Object baz = new Object;  // the object baz is only initialized

 // with the copy-constructor. There is no assignment or anything like
 // two initialisations. Also no temporary object is created.

In D, constants are always compile-time. That's one of its major differences from C++. As the result, constants turn out to be literals, or expressions involving literals and/or other constants. No memory is allocated for consts.
 No, piece of sh**t, because the vtable is initialized, when the

 finished successful, so all calls, even the foo() will be static linked

 vpt -
 no dynamic linkage - no surprises with functions called before constructor
 finished)

The question is, how the program tells, in function init(), that vtable isn't yet initialized? Add a bit flag and perform an implicit check for each method call?
Mar 06 2002
parent reply "Immanuel Scholz" <digitals-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a65ub0$1blo$1 digitaldaemon.com...
 In D, constants are always compile-time. That's one of its major
 differences from C++. As the result, constants turn out to
 be literals, or expressions involving literals and/or other
 constants. No memory is allocated for consts.

Isn't it a disadvantage to loose the type safety provided by declaring something const? What was the reason for this decission?
 The question is, how the program tells, in function init(), that
 vtable isn't yet initialized? Add a bit flag and perform an implicit
 check for each method call?

Err. Ok, I confuse "static-linkage" a bit with "vpt not completly build up". Imi
Mar 08 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
news:a6a72b$q9c$1 digitaldaemon.com...

 Isn't it a disadvantage to loose the type safety provided by declaring
 something const? What was the reason for this decission?

I don't really see much reason in it. In C++, the most obvious reason for const would be const references (const Object& foo), to allow passing of temporaries created in the process of type conversions. Since there are no such things in D, the need for const is not high. I'm sure Walter might add something to this... =)
Mar 08 2002
parent "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a6a8jv$quo$1 digitaldaemon.com...
 "Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
 news:a6a72b$q9c$1 digitaldaemon.com...
 Isn't it a disadvantage to loose the type safety provided by declaring
 something const? What was the reason for this decission?

reason for const would be const references (const Object& foo), to allow passing of temporaries created in the process of type conversions. Since there are no such things in D, the need for const is not high. I'm sure Walter might add something to this... =)

My experience with const as a type modifier is it: 1) has confusing syntax & semantics 2) does not enable any better code to be generated (for various technical reasons) 3) needs to be subverted anyway with "mutable" 4) adds a lot of complexity to overload resolution 5) causes declarations to be peppered with "const", reducing readability 6) I haven't seen any convincing data that using them reduces bugs 7) adds unreasonable complexity to the typing system So, it is not in D. const *is* useful as a storage class, as it: 1) enables compile time constant folding 2) enables data to be placed in ROM So, D supports const as a storage class, not as a type modifier. One consequence of this is, as Pavel pointed out, that class objects cannot be const, because class objects can only be created on the garbage collected heap.
Mar 09 2002
prev sibling parent reply "Richard Krehbiel" <rich kastle.com> writes:
(Not in reply to any particular person - I'm just clarifying this issue in
my mind)

So - the way an object in D is built is:

1. Allocate the needed memory.

2. Copy a compiler-built static image, which includes the final vtbl
pointer, into the new memory.

3. Call the constructor of the actual "outermost" instance type.

4. The instance's constructor calls superclass constructors at it's
convenience.

This is philosophically different from C++, which believes it's wrong to
touch the methods of a descendant object until it's superclass is fully
constructed.  C++ calls constructors in the opposite order, innermost-first.

(In C++, in the presence of virtual overrides, there would have been
potential for a base  constructor to call a descendant's method, except that
C++ rules that descendant methods can NOT be called by a parent's
constructor.  So it's as if the object being constructed gradually evolves
from the innermost base class, into the actual instance type, by updating
the vtbl pointer at each level of construction.)

So the order of construction for class C derived from B derived from A is,
C.this() calls B.this(), which calls A.this().  And C.this() can touch and
invoke any of C's methods or variables, before calling B.this(), effectively
*without* having a "valid" base class.

And, now I can see it: C.this() can also touch any of A's methods and
variables before A.this() is called, effectively before A is a valid object.
Hmmm.

Now, Walter says (unless I'm mistaken) that this is okay because there are
never any uninitialized areas of storage.  All of A's and B's and C's static
constructors "happen" before any .this() is called.

So, if it's important, I see how this you can use this as a safety net.

class A
{
   private int A_constructed = 0;
   this()
   {
      // ...
      A_constructed = 1;
   }
}

Any of A's methods that are called before A.this() can see A_constructed ==
0 (if they look).

But they *do* have to look.  And in C++ they wouldn't have to.  So in this
respect, D is not as safe as C++.

Now, as a long-time C programmer, I'm willing to sacrifice some safety for
power.  But frankly, I'm not seeing how this adds power.  If anyone can come
up with a concrete example that shows the power of calling base class
methods before calling the base class constructor, I'd appreciate it.

--
Richard Krehbiel, Arlington, VA, USA
rich kastle.com (work) or krehbiel3 comcast.net  (personal)
Mar 06 2002
next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Richard Krehbiel wrote:

 Now, as a long-time C programmer, I'm willing to sacrifice some safety for
 power.  But frankly, I'm not seeing how this adds power.  If anyone can come
 up with a concrete example that shows the power of calling base class
 methods before calling the base class constructor, I'd appreciate it.

I ran across this sort of situation in a library I was developing in C++: class Worker {...}; class Thing { protected: Worker *myWorker; public: Thing() { myWorker = new Worker }; } class WorkerChild : public Worker {...}; class ThingChild : public Thing { // how do I create a WorkerChild object and pass it to my // parent class? I want to use WorkerChild as the worker } The problem I ran into was that when you implement the ThingChild constructor, you must pass values into the Thing constructor. But you can't call 'new' in the defintion, since that will work in some compilers but break in others. What I really want to do was to be able to call the Thing constructor from INSIDE the ThingChild constructor...then I can make runtime decisions about the parameters of the WorkerChild and create it dynamically. -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Mar 06 2002
next sibling parent "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> schrieb im Newsbeitrag
news:3C86780B.1A35A735 deming-os.org...
 I ran across this sort of situation in a library I was developing in C++:

 class Worker {...};
 class Thing
 {
 protected:
     Worker *myWorker;

 public:
     Thing() { myWorker = new Worker };
 }
 class WorkerChild : public Worker {...};
 class ThingChild : public Thing
 {
    // how do I create a WorkerChild object and pass it to my
    // parent class?  I want to use WorkerChild as the worker
 }

I do not think, that ThingChild should create the WorkerChild, since it is not his responsibility (It is the responsibility of the base class Thing). Maybe a factory-class can do it as a gray area... My solution (maybe not the straight-forward-one? ;-): class Employer { ... virtual Worker* employ() {return new Worker;} }; class ChildEmployer { ... // if you like, you can make runtime checks to determinate // whether a WorkerChild is good or something else. Worker* employ() {return new WorkerChild;} }; class Thing { protected: Worker *myWorker; public: Thing(const Employer& employer) myWorker = employer.employ() }; } class ThingChild : public Thing : Thing(ChildEmployer()) {} You see, it is possible without dynamic linkage within the constructor. Whether it is obvious, a good OO-Model, a good solution or maybe a bad hack, whe could discuss ;-) Imi
Mar 06 2002
prev sibling parent reply "Rchard Krehbiel" <krehbiel3 comcast.net> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3C86780B.1A35A735 deming-os.org...
 Richard Krehbiel wrote:

 Now, as a long-time C programmer, I'm willing to sacrifice some safety


 power.  But frankly, I'm not seeing how this adds power.  If anyone can


 up with a concrete example that shows the power of calling base class
 methods before calling the base class constructor, I'd appreciate it.

I ran across this sort of situation in a library I was developing in C++: class Worker {...}; class Thing { protected: Worker *myWorker; public: Thing() { myWorker = new Worker }; } class WorkerChild : public Worker {...}; class ThingChild : public Thing { // how do I create a WorkerChild object and pass it to my // parent class? I want to use WorkerChild as the worker }

Well... If you can change the Thing class, then add a separate constructor which takes a Worker*. But if you can't, then maybe you could destroy the Worker that Thing::Thing() created, and implant your replacement. Well, that may be inefficient, or worse, the original Worker may have caused some undesirable side effect. In either case, yes, I can see how it would might have been a boon to be able to *not* call the Thing constructor at all. Now, I don't know who wrote your Thing class, but maybe it was intended that Worker not be replaceable. After all, what if Thing were designed like this? class Worker { }; class Thing { Worked worker; } It would have been more obvious that you were stuck without an option.
Mar 06 2002
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Rchard Krehbiel wrote:

 Well... If you can change the Thing class, then add a separate constructor
 which takes a Worker*.

Right, that's exactly what I did. But it didn't work because I had to implement the ThingChild constructor like this: ThingChild::ThingChild() : Thing( new WorkerChild ) {...} And different compilers differ on whether that 'new WorkerChild' causes a new object to be created for every ThingChild::ThingChild, or if the same WorkerChild (created once at runtime) is passed every time, or if the whole thing was legal at all. Now, with D, I can do this: ThingChild::this() { super( new WorkerChild ); }; and the code is 100% clear what it means.
 In either case, yes, I can see how it would might have been a boon to be
 able to *not* call the Thing constructor at all.

 Now, I don't know who wrote your Thing class, but maybe it was intended that
 Worker not be replaceable.

I wrote both classes, so I can't blame anybody but me :-0 I intended to replace Worker...but never realized how hard it would be :( -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Mar 06 2002
next sibling parent reply "Sean L. Palmer" <spalmer iname.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3C8698CB.61C5ECAC deming-os.org...
 Right, that's exactly what I did.  But it didn't work because I had to

 the ThingChild constructor like this:

     ThingChild::ThingChild() : Thing( new WorkerChild ) {...}

 And different compilers differ on whether that 'new WorkerChild' causes a

 object to be created for every ThingChild::ThingChild, or if the same
 WorkerChild (created once at runtime) is passed every time, or if the

 thing was legal at all.

Really? Which compiler(s)? I've never seen one that couldn't handle this properly, though I've only used Borland, Watcom, VC++ 4 thru 7, GCC, and CodeWarrior. Sean
Mar 07 2002
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
"Sean L. Palmer" wrote:

 Really?  Which compiler(s)?  I've never seen one that couldn't handle this
 properly, though I've only used Borland, Watcom, VC++ 4 thru 7, GCC, and
 CodeWarrior.

I remember having a problem with this. Frankly, I don't remember if the problem was that I found compilers with varying outputs, if I just couldn't find a spec, or what. Maybe I'm nuts, and all compilers are the same...but if so, I don't have any idea what the spec is, and it's not obvious from the language construction. So, bascially, I may be totally wrong about C++. If so, I'm sorry. I still think that calling super() inside the function body is a better way to do things. -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Mar 07 2002
parent reply "Sean L. Palmer" <spalmer iname.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3C879F11.7CBD799C deming-os.org...
 "Sean L. Palmer" wrote:

 Really?  Which compiler(s)?  I've never seen one that couldn't handle


 properly, though I've only used Borland, Watcom, VC++ 4 thru 7, GCC, and
 CodeWarrior.

I remember having a problem with this. Frankly, I don't remember if the problem was that I found compilers with varying outputs, if I just

 find a spec, or what.  Maybe I'm nuts, and all compilers are the

 so, I don't have any idea what the spec is, and it's not obvious from the
 language construction.

 So, bascially, I may be totally wrong about C++.  If so, I'm sorry.

 I still think that calling super() inside the function body is a better

 do things.

I agree... it's the way we used to do things back in the old days using Borland Pascal. I think Delphi still works this way. It makes a constructor more like an ordinary virtual function that's been overridden. As with any such function, the overridden version gets control first, does what it has to do, (possibly) calls the inherited version, does any final work, then returns. You always have to do before the call to inherited function what needs to be done before the inherited function is called, and afterward what needs done afterwards. If you want to change its inputs you do it before, and if you want to change its outputs you do it after, usually. But there's no hard and fast rule about it, you just do it in the way that works. If it doesn't work you did it the wrong way. I don't mind shooting myself in the foot once in a while... it keeps me awake. I'd rather have a more flexible language than one that prevents me from being bad. It's good to be bad sometimes. ;) Sean
Mar 07 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Sean L. Palmer" <spalmer iname.com> wrote in message
news:a68c6n$2f91$1 digitaldaemon.com...

 I agree... it's the way we used to do things back in the old days using
 Borland Pascal.  I think Delphi still works this way.

Absolutely. AFAIK it doesn't even require the base constructor to be called (which is definitely not the best idea)!
Mar 07 2002
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3C8698CB.61C5ECAC deming-os.org...
  I intended to replace
 Worker...but never realized how hard it would be :(

I've heard that some european laws make that very difficult <g>.
Mar 09 2002
parent "OddesE" <OddesE_XYZ hotmail.com> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a6dp5h$2e8g$1 digitaldaemon.com...
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3C8698CB.61C5ECAC deming-os.org...
  I intended to replace
 Worker...but never realized how hard it would be :(

I've heard that some european laws make that very difficult <g>.

LOL! :) Especially Dutch labour laws :) -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net __________________________________________ Remove _XYZ from my address when replying by mail
Mar 11 2002
prev sibling next sibling parent "Pavel Minayev" <evilone omen.ru> writes:
"Richard Krehbiel" <rich kastle.com> wrote in message
news:a65rol$1aio$1 digitaldaemon.com...

 Now, as a long-time C programmer, I'm willing to sacrifice some safety for
 power.  But frankly, I'm not seeing how this adds power.  If anyone can

 up with a concrete example that shows the power of calling base class
 methods before calling the base class constructor, I'd appreciate it.

The "base" method could be overridden in this class (easily detectable), or in one of its descendants (not detectable). So calling it could be perfectly legal in some context.
Mar 06 2002
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Richard Krehbiel" <rich kastle.com> wrote in message
news:a65rol$1aio$1 digitaldaemon.com...
 So - the way an object in D is built is:
 1. Allocate the needed memory.
 2. Copy a compiler-built static image, which includes the final vtbl
 pointer, into the new memory.
 3. Call the constructor of the actual "outermost" instance type.
 4. The instance's constructor calls superclass constructors at it's
 convenience.

Yes.
 This is philosophically different from C++, which believes it's wrong to
 touch the methods of a descendant object until it's superclass is fully
 constructed.  C++ calls constructors in the opposite order,

The point is to enable the most derived constructor to completely control the construction of the base classes. I find the base class initialization syntax of C++ to be inflexible. If you've ever tried to call a base constructor with a non-trivial computation on its arguments, you know what I mean.
 Now, Walter says (unless I'm mistaken) that this is okay because there are
 never any uninitialized areas of storage.  All of A's and B's and C's

 constructors "happen" before any .this() is called.

Yes.
 Now, as a long-time C programmer, I'm willing to sacrifice some safety for
 power.  But frankly, I'm not seeing how this adds power.  If anyone can

 up with a concrete example that shows the power of calling base class
 methods before calling the base class constructor, I'd appreciate it.

Ok, here's an example: this(int a, int b, int c) { ... computation ... if (condition) super(a,b); else super(c,d); } Or how about: this() { ... basic construction ... } this(int a) { this(); // do basic construction ... more advanced construction ... } Neither can be done without some falderal in C++.
Mar 09 2002
prev sibling parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a634fp$3p4$1 digitaldaemon.com...
 What happens is a static initializer is prepared for each class. Memory is
 allocated and the static initializer is copied over it. Then, the
 constructor is called.

 This ensures that within the constructor the object is in a defined state,
 virtual functions can be called, and all members are initialized to the
 default value. For many (if not most) classes, this is sufficient and it

 not even necessary to have a constructor. It guarantees no more bugs due

 adding a member and forgetting to initialize it in one of the

 Constructors are only necessary if any dynamic initialization is needed.

 "Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
 news:a630s6$241$1 digitaldaemon.com...
 Hi,

 hm, if I got it right:

 - the vp-table is initialized, and the members are set to something


 before the constructor is called
 - you can call funktions from within the construktor. These are

 linked (since the vpt exist).

 This means, that within any member-function, there could be 2 states:

 - The own constructor could be completed successfull - all is ok
 - The function is called from a constructor (or a function the


 called...). This means, the
 member-variables are initialized with default values, given at compile

 Isn't this bad?

 - Either I assume the default values for members are alright and valid -

 I need no constructor at
 all and can take this() {} out of language?
 - Or I assume, static linked default values are not enough, but members

 be filled within
 the constructor - so I have to check the members in each member-function
 whether they already
 initialized or not.

 Are there a solution?

 Imi


And even then it shouldn't be a problem. *You* make the constructor of your class, so you know which functions it calls. Only these functions may not assume a completed constructor on it's call. Or am I missing something? -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net __________________________________________ Remove _XYZ from my address when replying by mail
Mar 05 2002
parent "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"OddesE" <OddesE_XYZ hotmail.com> schrieb im Newsbeitrag
news:a63ehb$81k$1 digitaldaemon.com...
 Are there a solution?


And even then it shouldn't be a problem. *You* make the constructor of your class, so you know which functions it calls. Only these functions may not assume a completed constructor on it's call. Or am I missing something?

Yes, you miss something: class Base_with_no_source_code_access { this() { foo(); } int foo() {} } class My_class_which_I_know_very_well { this() { super(); /* do some initialisation important to the class */ } int foo() { /* do something, that rely on an initialized class */ } } Got it? Even I do not call foo() from within my class, it is called in the base classes constructor - and this before I could initialize the members. (Generally putting super() at the end of constructor is even worse, I think you realize that already ;-). In C++, this is not possible, because a virtual function is not dynamically linked within the constructor. So there, the Base..::foo() would be called instead (and bring its own suprise to programmers ;-) Imi
Mar 05 2002
prev sibling next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a630s6$241$1 digitaldaemon.com...

 Hi,

 hm, if I got it right:

 - the vp-table is initialized, and the members are set to something static
 before the constructor is called

YES!
 - you can call funktions from within the construktor. These are

 linked (since the vpt exist).

YES!!!
 This means, that within any member-function, there could be 2 states:

 - The own constructor could be completed successfull - all is ok
 - The function is called from a constructor (or a function the constructor
 called...). This means, the
 member-variables are initialized with default values, given at compile

 Isn't this bad?

No. You should design your interface and implementations in such a manner that things like that don't happen - or at least if they do, it's your responsibility to ensure proper work. There might be a function that doesn't rely on object variables, but rather changes them: class Foo { int bar; this(int n) { init(1); ... } this(float f) { init(2); ... void init(n) { bar = n * n; } } Definitely a stupid, meaningless example... yet it shows that everything might not be that bad.
 - Either I assume the default values for members are alright and valid -

 I need no constructor at
 all and can take this() {} out of language?

Constructor has duties other than assigning values to members. It might perform special specialization routines. For example, the Window class might want to call CreateWindowEx in its constructor.
 - Or I assume, static linked default values are not enough, but members

 be filled within
 the constructor - so I have to check the members in each member-function
 whether they already
 initialized or not.

Just don't call member functions that rely on class variables from the constructor.
Mar 05 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a634lr$3qf$1 digitaldaemon.com...
 "Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
 - Or I assume, static linked default values are not enough, but members

 be filled within
 the constructor - so I have to check the members in each member-function
 whether they already
 initialized or not.

Just don't call member functions that rely on class variables from the constructor.

HA! And here is the point I want to show. In C++ of course you can call to member-functions from within the constructor too. But since they are static linked, you may only be aware of functions, that your own constructor in your own class call. In D member functions may be called from constructors you didn't even know they exist, so you live with the bad feeling in your stomach, whether this function may be called before the own constructor finished? Example: class foo : public bar { int x = 0; this {super(); x = calculate_x_right();} int foobar() { // here you cannot be sure, that x contains a right value (returned from // calculate_x_right), because the class bar may define int foobar() and // call it within its constructor... // all you can do is check it (but not with an assertion, because it may // depend on runtime-things whether foobar is called in a superclass) if (x != 0) ... } The check for x != 0 stinks, but you can't really go without it, unless you check the whole hirachy from foo upwards and this may be impossible. Imi
Mar 05 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a635ug$49p$1 digitaldaemon.com...

 HA! And here is the point I want to show.
 In C++ of course you can call to member-functions from within the
 constructor too.
 But since they are static linked, you may only be aware of functions, that
 your own
 constructor in your own class call.
 In D member functions may be called from constructors you didn't even know
 they exist, so you live with the bad feeling in your stomach, whether this
 function may be called before the own constructor finished?

Functions always exist. They, however, might rely on the data that wasn't yet properly initialized. For example the constructor of Window might call a caption() method, which'd in turn call SetWindowText, passing hWnd - which is still 0. Yes, it is possible. But it is something YOU should control. It's a usual consistency-vs-usability tradeoff. C++ constructors are very inconvenient, especially when it is required to call the base constructor with different arguments depending on what you get. It usually turns out to be something like: class Foo: public Bar { Foo(int n): Bar(n == 0 ? 1 : n == 1 ? 5 : n == 2 ? 10 : ...) { ... } } In D it can be written much cleaner: class Foo: Bar { this(int n) { switch (n) { case 0: super(1); return; case 1: super(5); return; ... } } } While this method has some quirks that you've mentioned, it is (IMO) much more practical. As long as you don't do "bad" things, the code is way more readable and flexible.
Mar 05 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a638a2$5ai$1 digitaldaemon.com...
 Functions always exist. They, however, might rely on the data that wasn't
 yet properly initialized. For example the constructor of Window might
 call a caption() method, which'd in turn call SetWindowText, passing

 which is still 0. Yes, it is possible. But it is something YOU should
 control.

If I control class Window (to recognize the fact) and the class that redefine caption() (to include the check to hWnd) all is ok. But since I even don't know Window calls to caption, I usually have to check all variables in all functions before assuming, they have a value, that they get in the constructor. So you get no guarantee in any of you member-functions, that one of the constructors finished correctly. And this is IMHO a big disadvantage compared to C++. I tend to layout my Classes, that initializing is done within the constructor, so I can depend on a fully initialized class (not only static copied one) and do not have to check for validness on start on each member function. Maybe this tends to code like: class bar { this {init();} void init () { /* do the real init-stuff here */ } bool is_valid() { /* checks if initialized */ } f1 () {if (!is_valid()) init(); ...} // this first line appear in each function f2 () {if (!is_valid()) init(); ...} // which depends on a valid constructor-run f3 () {if (!is_valid()) init(); ...} f4 () {if (!is_valid()) init(); ...} } And worse: You can't use something like in{} and assert(bar) for this, since it may depend on runtime-decisions whether bar is initialized on call to a member or not. And worst: I think the real problem is deeper, because not everyone sees the problem behind this and may blindly depends on the fact, that the constructor is already passed successfully. And you need some luck to find such a bug in short time.
 It's a usual consistency-vs-usability tradeoff. C++ constructors
 are very inconvenient, especially when it is required to call the
 base constructor with different arguments depending on what you get.
 It usually turns out to be something like:

     class Foo: public Bar
     {
         Foo(int n): Bar(n == 0 ? 1 : n == 1 ? 5 : n == 2 ? 10 : ...)

     }

 In D it can be written much cleaner:

     class Foo: Bar
     {
         this(int n)
         {
             switch (n)
             {
             case 0: super(1); return;
             case 1: super(5); return;
             ...
             }
         }
     }

This is a different issue? Or how it is connected to my problem? It is no problem to call the base classes constructor at any other time, as long as these base class Bar cannot call any member-function within Foo before Foo.init() is finished! But anyway: Did you ensure (maybe with an warning, that can be turned to an error) that the user did not simple forget calling the base-constructor?
 While this method has some quirks that you've mentioned, it is
 (IMO) much more practical. As long as you don't do "bad" things,
 the code is way more readable and flexible.

<GRHN!> I disagree! It is not me who has to do no "bad things". It is the writer of my base classes! They should not be able to call my functions before my constructor finish. And I cannot access the source of my base-classes (either because I cannot or won't or shouldn't or have such time). Maybe all functions a constructor call (and all functions this function calls...) has to be final and cannot overidden? This might be a solution. Imi
Mar 05 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a63a8a$68f$1 digitaldaemon.com...
 If I control class Window (to recognize the fact) and the class that
 redefine
 caption() (to include the check to hWnd) all is ok. But since I even
 don't know Window calls to caption, I usually have to check all variables
 in all functions before assuming, they have a value, that they get in the
 constructor.

You've just described the problem resolved by the class invariant!
 So you get no guarantee in any of you member-functions, that one of
 the constructors finished correctly. And this is IMHO a big disadvantage
 compared to C++.

C++ has a terrible disadvantage in that there's no guarantee there's any value other than garbage in any member. I can't even count the number of times I've had a bug where I added a member and then forgot to initialize it in one of the many constructors for it. With D, you have: 1. all members are guaranteed to at least contain their static default values. 2. you can use preconditions on a function to guarantee specific values. 3. you can use class invariants to guarantee correct construction before public member functions get called. None of this is supported by C++.
 class bar
 {
   this {init();}
   void init () { /* do the real init-stuff here */ }
   bool is_valid() { /* checks if initialized */ }

   f1 () {if (!is_valid()) init(); ...} // this first line appear in each
 function
   f2 () {if (!is_valid()) init(); ...} // which depends on a valid
 constructor-run
   f3 () {if (!is_valid()) init(); ...}
   f4 () {if (!is_valid()) init(); ...}
 }

The "is_valid()" function is analogous to the D class invariant, except with D the class invariant call is automatically inserted (and inherited).
 And worse: You can't use something like in{} and assert(bar) for this,
 since it may depend on runtime-decisions whether bar is initialized on
 call to a member or not.

I don't see how.
 And worst: I think the real problem is deeper, because not everyone
 sees the problem behind this and may blindly depends on the fact, that
 the constructor is already passed successfully. And you need some
 luck to find such a bug in short time.

D has both more flexibility in constructor design and more inherent robustness. You can add initialization guarantees using the class invariant.
Mar 05 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Walter" <walter digitalmars.com> schrieb im Newsbeitrag
news:a63duu$7q1$1 digitaldaemon.com...
 "Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
 news:a63a8a$68f$1 digitaldaemon.com...
 If I control class Window (to recognize the fact) and the class that
 redefine
 caption() (to include the check to hWnd) all is ok. But since I even
 don't know Window calls to caption, I usually have to check all


 in all functions before assuming, they have a value, that they get in


 constructor.

You've just described the problem resolved by the class invariant!

Hm. I do not think so. Class invariants are, as long as I read the manual right, only compiled into the debug version. But the decission, whether a inherited function is called could be at runtime: class B { this () { if (/* User is unhappy with the programm */) foo(); } int foo(); } class D : B { this() {} int foo(); // is this function called only after constructor finished? }
 So you get no guarantee in any of you member-functions, that one of
 the constructors finished correctly. And this is IMHO a big disadvantage
 compared to C++.

C++ has a terrible disadvantage in that there's no guarantee there's any value other than garbage in any member. I can't even count the number of times I've had a bug where I added a member and then forgot to initialize

 in one of the many constructors for it.

Those problems are on an other page! I am disagree with resolving function linkage through the vpt within constructors, not preinitialize members. Maybe with preinitializing, you can ommit some or most constructors, but you cannot go around the dynamic-linkage-within-constructors-problem.
 With D, you have:

 1. all members are guaranteed to at least contain their static default
 values.

Wonderful! I missed this one in C++ due lack of sense for typical error situations from the C++-Authority (these are alltogether performance- sharks ;-).
 2. you can use preconditions on a function to guarantee specific values.

Only in debug! So this is almost useless against unknown source guarantees.
 3. you can use class invariants to guarantee correct construction before
 public member functions get called.

Also only in debug-mode. Theese are all suits pretty when coding and fast finding errors, but IMHO it cannot replace a good scheme of guarantees on runtime!
 None of this is supported by C++.

hm, somewhat.. you can emulate it, but not use it directly, thats right. So D is not more powerful, but much easier to use on those. (But thats not my problem in this thread)
 class bar
 {
   this {init();}
   void init () { /* do the real init-stuff here */ }
   bool is_valid() { /* checks if initialized */ }

   f1 () {if (!is_valid()) init(); ...} // this first line appear in each
 function
   f2 () {if (!is_valid()) init(); ...} // which depends on a valid
 constructor-run
   f3 () {if (!is_valid()) init(); ...}
   f4 () {if (!is_valid()) init(); ...}
 }

The "is_valid()" function is analogous to the D class invariant, except

 D the class invariant call is automatically inserted (and inherited).

...and removed on release-build. BTW: I thought the invariant are only looked after if you call to assert(b); (and b is from type bar)? So it might be usable, if you provide such a valid- check and let the "compile-invariant-switch" for those classes on... But even then: It is not good to give the burden for this workaround to the programmer.
 And worse: You can't use something like in{} and assert(bar) for this,
 since it may depend on runtime-decisions whether bar is initialized on
 call to a member or not.

I don't see how.

e.g. it could depend on some registry-entries, whether a function is called or not: class B { this() { if (/* there are some interesting registry entries */) foo(); } int foo(); } class D : B { int foo() in { /* check for validation is useless, since on the test-system, there might be no those registry entries */ } body { /* although I checked in the "in"-section, I can not be sure, that D is initialized proper (means -> D.this() is called successfull) */ } } Of course, you alwasy can blame it to a bad testbed... but I would blame it to a trap-hard-to-find-but-easy-to-step-into.
 D has both more flexibility in constructor design and more inherent
 robustness. You can add initialization guarantees using the class

So you keep it to the user to realize, that there might be a problem, if he depends on successfull constructor finishing. (And you need to let the invariant-checks compiled in, even in release) On the other hand, if D implements a static linkage within the constructor (like in C++), many programmer would get into trouble with this inconsistency. And sometimes it come in handy to call a virtual function from within constructors... Are you planning to include a keyword like the java's "final" ? Why not? And what about one to say: "This function may not overwrite an other!" ? So you can at least do some basic protection against the problem in this thread (when you realized, there is a problem) Imi
Mar 05 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a63h9j$9e1$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> schrieb im Newsbeitrag
 news:a63duu$7q1$1 digitaldaemon.com...
 "Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
 news:a63a8a$68f$1 digitaldaemon.com...
 If I control class Window (to recognize the fact) and the class that
 redefine
 caption() (to include the check to hWnd) all is ok. But since I even
 don't know Window calls to caption, I usually have to check all


 in all functions before assuming, they have a value, that they get in


 constructor.


right, only compiled into the debug version.

Generally, yes, though this is individually controllable. And it is a debugging issue, not an error to be dealt with in released code.
 But the decission, whether a inherited
 function is called could be at runtime:

 class B
 {
   this ()
   {
     if (/* User is unhappy with the programm */)
       foo();
   }

   int foo();
 }

 class D : B
 {
   this() {}

   int foo();  // is this function called only after constructor finished?
 }

That is a good point. You can guard against that by using a class invariant in D.foo(), or by calling foo() using the direct syntax: B.foo();
 Maybe with preinitializing, you can ommit some or most constructors, but
 you cannot go around the dynamic-linkage-within-constructors-problem.

Ok, I understand your point now.
 With D, you have:
 1. all members are guaranteed to at least contain their static default
 values.

situations from the C++-Authority (these are alltogether performance- sharks ;-).

I *really* wanted to fix that one, having had so many bugs due to it.
 2. you can use preconditions on a function to guarantee specific values.

So this is almost useless against unknown source guarantees.

You can still leave it on the release code.
 3. you can use class invariants to guarantee correct construction before
 public member functions get called.

Theese are all suits pretty when coding and fast finding errors, but IMHO it cannot replace a good scheme of guarantees on runtime!

Again, you can leave that stuff turned on.
 None of this is supported by C++.


 D is not more powerful, but much easier to use on those.
 (But thats not my problem in this thread)

<g> All of C++'s features can be emulated in C, after all.
Mar 05 2002
parent reply "Immanuel Scholz" <digitals-mars kutzsche.net> writes:
"Walter" <walter digitalmars.com> schrieb im Newsbeitrag
news:a63puv$e0l$1 digitaldaemon.com...
 "Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
 Hm. I do not think so. Class invariants are, as long as I read the


 right, only compiled into the debug version.

Generally, yes, though this is individually controllable. And it is a debugging issue, not an error to be dealt with in released code.

Right. You should never forced to use debugging tools for release - things. So all you can do is to add your own "invariant" - code in each function that depend on an correctly, dynamically initialized member.
 But the decission, whether a inherited
 function is called could be at runtime:

 class B
 {
   this ()
   {
     if (/* User is unhappy with the programm */)
       foo();
   }

   int foo();
 }

 class D : B
 {
   this() {}

   int foo();  // is this function called only after constructor


 }

That is a good point. You can guard against that by using a class

 in D.foo(),

But as I stated above, class invariants are not for testing runtime- conditions, but to debug and find static-conditions (errors in code, not in enviroment).
 or by calling foo() using the direct syntax:
     B.foo();

In my szenario, you have no control over the constructor of B. This is real, because it might be deep in a gui-library (as example MFC).
 Maybe with preinitializing, you can ommit some or most constructors, but
 you cannot go around the dynamic-linkage-within-constructors-problem.

Ok, I understand your point now.

I hope you do something against that, I think it is not just a constructed problem, that very seldom to never occours. I think it could be become typical, since user begin to allocate the memory for their pointers within constructor: class bar : foo { ptr_to_important = null; this() { ptr_to_important = new ImportantClass(); } int widget() { if (ptr_to_important == null) ... /* This error-check needs to be included, since you do not know, if function widget() is called from an baseclass-constructor. */ } } These tests to null are stupid, uncomfortable (so nobody will make them), not easy to understand why you need them (I hope you understand it now) and very hard to recognize when you forget them. And they are essentiel. You cannot longer trust the fact like in C++ that never ever a non-static member function is called when constructer- initialisation is not done (exept for those, your own constructor called). Maybe make the calls from within a constructor statically linked is the best solution?
 With D, you have:
 1. all members are guaranteed to at least contain their static default
 values.

situations from the C++-Authority (these are alltogether performance- sharks ;-).

I *really* wanted to fix that one, having had so many bugs due to it.

This can be done without dynamically linkage within constructors.
 2. you can use preconditions on a function to guarantee specific



 Only in debug!
 So this is almost useless against unknown source guarantees.

You can still leave it on the release code.

See above. I stated, that this is not the idea of class-invariants. Mixing debugging code and runtime-important code is also one of the great problems with any language I saw (or the fact, that mostly the code will not run at first release build, because somebody wrote "assert(function_with_side_effects()); " ;-)
 3. you can use class invariants to guarantee correct construction



 public member functions get called.

Theese are all suits pretty when coding and fast finding errors, but


 it cannot replace a good scheme of guarantees on runtime!

Again, you can leave that stuff turned on.

So you have to mix up debugging and runtime - stuff with the same compiler-identifier? I think the "leave it to the invariant-debug-concept" is not good. Plus, the debugging should stop the code, if something went wrong, and my examples may recover from such a "call before constructor completes".
 None of this is supported by C++.


 D is not more powerful, but much easier to use on those.
 (But thats not my problem in this thread)

<g> All of C++'s features can be emulated in C, after all.

I have seen a C to preprocessor-C converter, which converts plain C code to pure preprocessor-code ;-) (since the preprocessor is turing- compatible).. Imi
Mar 06 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
news:a651sm$voa$1 digitaldaemon.com...

 Right. You should never forced to use debugging tools for release -

 So all you can do is to add your own "invariant" - code in each function
 that
 depend on an correctly, dynamically initialized member.

A better idea would be to debug program (using invariants and such) to the state when it surely doesn't depend on uninitialized members. That is, you define an invariant, and develop your program in debug-mode... and then, when you're sure it works properly, you remove all the invariants and let it run at full speed. Or, you could leave the invariants there, even in the release build, to avoid explicitly inserted checks.
 In my szenario, you have no control over the constructor of B. This is
 real, because it might be deep in a gui-library (as example MFC).

What do you mean, no control???
 Maybe make the calls from within a constructor statically linked is the

 solution?

I showed how I'd fool the compiler in this case. Anyhow, I think it's not the best idea. I always hated this "feature" of C++, which didn't allow me to define user hooks to be called at the end of the constructor (when all data is surely initialized). This is a very important issue for me, thanks to Walter we have it in D.
 See above. I stated, that this is not the idea of class-invariants.
 Mixing debugging code and runtime-important code is also one of the great
 problems with any language I saw (or the fact, that mostly the code will

 run at first release build, because somebody wrote
 "assert(function_with_side_effects()); "  ;-)

I believe assertions on expressions with side effects are forbidden by the language, and the compiler should do its best to catch such things.
Mar 06 2002
next sibling parent reply "Immanuel Scholz" <digitals-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a659o0$12u2$1 digitaldaemon.com...
 "Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
 news:a651sm$voa$1 digitaldaemon.com...

 Right. You should never forced to use debugging tools for release -

 So all you can do is to add your own "invariant" - code in each function
 that
 depend on an correctly, dynamically initialized member.

A better idea would be to debug program (using invariants and such) to the state when it surely doesn't depend on uninitialized members. That is, you define an invariant, and develop your program in debug-mode... and then, when you're sure it works properly, you remove all the invariants and let it run at full speed.

Most functions that depend on initialised members have to depend on them and cannot simple "not using" them. You may add a check before the first use of them in each of your function, but I think this is buggy (because easy to forget) and not good detectable at debug-time for all cases.
 Or, you could leave the invariants there, even in the release
 build, to avoid explicitly inserted checks.

This means, "class invariants" degrees to helper-functions that are called before each member function is called. This is not their normal usage. I would not recommend this.
 In my szenario, you have no control over the constructor of B. This is
 real, because it might be deep in a gui-library (as example MFC).

What do you mean, no control???

No source, or not the posibility to compile the source. Simple, it is not your code, that calls the function, its a code you are forced to use.
 Maybe make the calls from within a constructor statically linked is the

 solution?

I showed how I'd fool the compiler in this case.

No, sorry. You cannot fool the compiler to resolve a virtual function, if the vpt of the class is not already build. All calls to virtual functions will be static linked until the constructor ends (without an exception, of course). That's the way C++ goes, and it will not run into this problem.
 Anyhow, I think
 it's not the best idea. I always hated this "feature" of C++, which
 didn't allow me to define user hooks to be called at the end of
 the constructor (when all data is surely initialized). This is a very
 important issue for me, thanks to Walter we have it in D.

Yes, I think so too. It is a good feature to be able to call virtual functions, and it is some kind of suprising, if you first time realize, that there is a static linkage with constructors. But I think, the problem I stated should NOT BE IGNORED! Maybe a solution could be, that all function called from within the constructor (and all functions they call and so on) are somewhat marked, and checked, whether they use members of the class. If so, the compiler shoud give a warning or something like that. So you can do this without any problem: class B { this() { printf( "I am a %s.",myself(); } char[] myself() {return "Base";} } class D { char[] myself() { return "Derrived"; // give no warning, since no // member-variable is touched. } } This is a common and good usage for the call to virtual functions from the constructor (and currently not possible in C++). Instead, this would produce at least a warning (if not an error at all?) class D { int i = 0; char[] myself() { // WARNING! "use of 'i' as a rvalue. Constructor may not be completed. if (i == 1) /* do something */ return "Derrived"; // give no warning, since no // member-variable is touched. } } How about this? I don't know if it is possible (I think it is not, because I do not know how the compiler could resolve the correct function that is called at compile-time).
 See above. I stated, that this is not the idea of class-invariants.
 Mixing debugging code and runtime-important code is also one of the


 problems with any language I saw (or the fact, that mostly the code will

 run at first release build, because somebody wrote
 "assert(function_with_side_effects()); "  ;-)

I believe assertions on expressions with side effects are forbidden by the language, and the compiler should do its best to catch such things.

I hope he does this job perfect. This is one of the major problems with any #ifdef - related language to me ;-) Imi
Mar 06 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
news:a65lid$17pl$1 digitaldaemon.com...

 Most functions that depend on initialised members
 have to depend on them and cannot simple "not using" them.
 You may add a check before the first use of them in each of
 your function, but I think this is buggy (because easy to forget)
 and not good detectable at debug-time for all cases.

Just don't call such functions from the point where members aren't yet properly initialized. Invariants will help to trap such cases and fix them, so you can be sure that in the release build you'll never get such a mistake - so checks aren't needed!
 This means, "class invariants" degrees to helper-functions that are called
 before each member function is called. This is not their normal usage.
 I would not recommend this.

And what are invariants if not "helper functions"? They help you to ensure validity of object's state, don't they?
 No source, or not the posibility to compile the source. Simple, it is
 not your code, that calls the function, its a code you are forced to use.

I understand now. I thought you meant to forbid calling the constructor of the base class explicitly. =)
 No, sorry. You cannot fool the compiler to resolve a virtual function, if
 the vpt of the class is not already build. All calls to virtual functions
 will
 be static linked until the constructor ends (without an exception, of
 course). That's the way C++ goes, and it will not run into this problem.

But what if compiler calls another function which calls a virtual function? I guess C++ doesn't actually do static calls, it just uses the vtable built to the needed stage, since child constructors haven't yet been executed, vtable contains pointers to methods of this class or its ancestors only.
 Yes, I think so too. It is a good feature to be able to call virtual
 functions, and it is some kind of suprising, if you first time realize,

 there is a static linkage with constructors.

 But I think, the problem I stated should NOT BE IGNORED!
 Maybe a solution could be, that all function called from within
 the constructor (and all functions they call and so on) are
 somewhat marked, and checked, whether they use members of the
 class. If so, the compiler shoud give a warning or something like that.

 So you can do this without any problem:

 class B {
   this() { printf( "I am a %s.",myself(); }
   char[] myself() {return "Base";}
 }

 class D {
   char[] myself() {
     return "Derrived";  // give no warning, since no
           // member-variable is touched.
   }
 }

 This is a common and good usage for the call to virtual functions
 from the constructor (and currently not possible in C++). Instead,
 this would produce at least a warning (if not an error at all?)

 class D {
   int i = 0;

   char[] myself() {
     // WARNING! "use of 'i' as a rvalue. Constructor may not be completed.
     if (i == 1)
       /* do something */
    return "Derrived";  // give no warning, since no
           // member-variable is touched.
   }
 }

 How about this? I don't know if it is possible (I think it is not, because
 I do not know how the compiler could resolve the correct
 function that is called at compile-time).

Yes, exactly. Unless we have AI built into the compiler, I guess these are just dreams. So the question is, should this feature be forbidden at all (because it might be used improperly), or should it be left (because it is a very powerful tool when used properly). I vote for the second.
Mar 06 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a65n91$18ju$1 digitaldaemon.com...
 "Immanuel Scholz" <digitals-mars kutzsche.net> wrote in message
 news:a65lid$17pl$1 digitaldaemon.com...

 Most functions that depend on initialised members
 have to depend on them and cannot simple "not using" them.
 You may add a check before the first use of them in each of
 your function, but I think this is buggy (because easy to forget)
 and not good detectable at debug-time for all cases.

Just don't call such functions from the point where members aren't yet properly initialized. Invariants will help to trap such cases and fix them, so you can be sure that in the release build you'll never get such a mistake - so checks aren't needed!

GRRR! Am I talking to a wall? :-| You can NOT (!) always remove the call to the function, because it may be essential to the library or you simple CANNOT change the source code, that calls the function. In C++, your argument is correct, since only your own constructor of your own class you are currently writing will call anything, so the only place to look after, is your own constructor. But in D, the call can come from a base-class constructor, or a function a base-class constructor calls. Another example (a more real one:) ------ this is a library you don't own the sources ------- class Window { this() { if (cmdline == "-with-window") CreateWindow(); } void CreateWindow() = 0; // user have to implement how to do this ... } ----- this is your code. Here you may change anything ------ class MyWindow { FileWrapperClass* file = null; this () {...; super(); ...; file = new FileWrapperClass; } CreateWindow() { file.load_window_resources(); // <-- null-pointer-access ! } } The problem here is, that you even might not know, that there are a switch "-with-windows" in Window - class (or the switch is added later one, when MyWindow was already compiled and shipped 1000 yards away), so you do really not expect, that MyWindow.CreateWindow is called, before the constructor finished. And so you thought, that "file" must be in a correct state - but it isn't. You cannot change the constructor of Window not to call CreateWindow (you may even want it not to change). So all you can do is building a check to CreateWindow() whether the constructor finished or not. And this is buggy, because you normally would not spot the bug, until it is too late (because you do not know about "-with-windows" or it wasn't there as you code MyWindow) class invariants help no good if stripped out in release (and thats what they are for, they do not ensure runtime-effects, only compile-bugs!)
 This means, "class invariants" degrees to helper-functions that are


 before each member function is called. This is not their normal usage.
 I would not recommend this.

And what are invariants if not "helper functions"? They help you to ensure validity of object's state, don't they?

Maybe they can help to spot some of the problems, but anyway, I think they this is no really solution. If you spot such a case (which mean, you are lucky), you have to add a check inside the functions body, since you cannot alter the base-class and CreateWindow might be called if constructor is finished...
 No source, or not the posibility to compile the source. Simple, it is
 not your code, that calls the function, its a code you are forced to


 I understand now. I thought you meant to forbid calling the
 constructor of the base class explicitly. =)

If have my problems with this too, but this is another story. As example some of my thoughts about explicit calling: - Protect the compiler the access to the base classes members and member-variables, before the super-constructor is called at least once? - If you do not call the base class constructor, it is automatically called? - If yes, before the current constructors code? If all questions resolve to "yes", I am satisfied, elsewhere I may begin a new thread with these topics?
 No, sorry. You cannot fool the compiler to resolve a virtual function,


 the vpt of the class is not already build. All calls to virtual


 will
 be static linked until the constructor ends (without an exception, of
 course). That's the way C++ goes, and it will not run into this problem.

But what if compiler calls another function which calls a virtual

 I guess C++ doesn't actually do static calls, it just uses the vtable
 built to the needed stage, since child constructors haven't yet been
 executed, vtable contains pointers to methods of this class or its
 ancestors only.

IMHO, this is the way it goes. During constructor phase, the object simple IS a type of the current class. You can easily check this by: ----- #include <iostream> #include <typeinfo> using namespace std; class foo { public: foo() { cout << typeid(this).name() << endl; } }; class bar : public foo { public: bar() { cout << typeid(this).name() << endl; } }; void main() { bar b; } ----- This means, childs functions are protected from access through the base class constructor, and the base class functions are protected, since you cannot do any statement before calling the base-constructor. Ok, there is a way, but this is terrible and a bug in C++-design: class foo { public: foo(int); int some_function(); } class bar : public foo { bar() : foo(some_function()); // some_function is called before the // base-class constructor!!! } But this requires explicit badness by the programmer.
 Yes, I think so too. It is a good feature to be able to call virtual
 functions, and it is some kind of suprising, if you first time realize,

 there is a static linkage with constructors.

 But I think, the problem I stated should NOT BE IGNORED!
 Maybe a solution could be, that all function called from within
 the constructor (and all functions they call and so on) are
 somewhat marked, and checked, whether they use members of the
 class. If so, the compiler shoud give a warning or something like that.

 So you can do this without any problem:

 class B {
   this() { printf( "I am a %s.",myself(); }
   char[] myself() {return "Base";}
 }

 class D {
   char[] myself() {
     return "Derrived";  // give no warning, since no
           // member-variable is touched.
   }
 }

 This is a common and good usage for the call to virtual functions
 from the constructor (and currently not possible in C++). Instead,
 this would produce at least a warning (if not an error at all?)

 class D {
   int i = 0;

   char[] myself() {
     // WARNING! "use of 'i' as a rvalue. Constructor may not be


     if (i == 1)
       /* do something */
    return "Derrived";  // give no warning, since no
           // member-variable is touched.
   }
 }

 How about this? I don't know if it is possible (I think it is not,


 I do not know how the compiler could resolve the correct
 function that is called at compile-time).

Yes, exactly. Unless we have AI built into the compiler, I guess these are just dreams. So the question is, should this feature be forbidden at all (because it might be used improperly), or should it be left (because it is a very powerful tool when used properly). I vote for the second.

I do not live good with this... Maybe because I always think, that the constructor have to be something special.. There is nothing before the constructor, and if the constructor passed by, I got a valid object in a valid state. This is the dreaming of the right way, object-design should be, and I think it is too much violated with rules like the one above. So people start to write objects, where the constructor does simple nothing or nearly nothing (since someone, IMO stupid person, said "never raise an exception within a constructor"). And they wrote functions like init() or Create() to take the place of a constructor... like in MFC which stinks because those. (Ok, to be honor, MFC does something about the Create() even because the fact, that no virtual function is resolved ;-) but there are other ways to do it, like other libraries does.) Such a design - I mean to violate the rule, that "no member function is called implizit before the constructor." - does not invite people to write better OO-Code. (Thats just my opinion, I am open to flames and any other way of discussion ;-) Maybe there are other solutions to this? btw: how is it solved in Java? Imi.
Mar 06 2002
next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a65sot$1b28$1 digitaldaemon.com...

 GRRR! Am I talking to a wall? :-|

...the wall being asked? =)
 You can NOT (!) always remove the call to the function, because it may be
 essential to the library or you simple CANNOT change the source code,
 that calls the function.

Then, the one who wrote such a library should warn that this function is called before some members are initialized - or, even better, don't do such things at all. Also, if one really needs to call a method of some concrete class, he could specify the full name: class Foo { this() { Foo.bar(); } void bar() { ... } }
 ...
 The problem here is, that you even might not know, that there are a switch
 "-with-windows" in Window - class (or the switch is added later one, when
 MyWindow was already compiled and shipped 1000 yards away),
 so you do really not expect, that MyWindow.CreateWindow is called,
 before the constructor finished.
 And so you thought, that "file" must be in a correct state - but it isn't.

This is called "side effects of the constructor" and should be properly documented in the code. That is, it should be stated clearly that CreateWindow is called from the ctor of Window, and once you're aware of it, you can put all the initialization before the call to super(). In fact, it is a wise idea to initialize members before calling super() whenever possible.
 As example some of my thoughts about explicit calling:
 - Protect the compiler the access to the base classes members and
 member-variables, before the super-constructor is called at least once?

Hmmm... class Foo { int n; this() { ... } } class Bar: Foo { this() { bar(); /* not a base member! */ super(); } void bar() { n = 666; /* modify the base member! */ } } While this example is rather simplistic, I don't see how it can be detected in more general case. Bar.bar() could have been overriden in some descendant of Bar, and you'd never know about it, nor would the compiler...
 - If you do not call the base class constructor, it is automatically

Currently, it aborts with an error in such a case, I believe.
 This is the dreaming of the right way, object-design should be,
 and I think it is too much violated with rules like the one above.

"Right way" isn't always the best way. Once again, it depends on the POV.
Mar 06 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a65v6k$1c3n$1 digitaldaemon.com...
 You can NOT (!) always remove the call to the function, because it may


 essential to the library or you simple CANNOT change the source code,
 that calls the function.

Then, the one who wrote such a library should warn that this function is called before some members are initialized - or, even better, don't do such things at all.

Or we give Walter beer until he make the compiler to warn us. (If possible (both, that Walter build in warnings and that the compiler could warn us)) ;-)
 The problem here is, that you even might not know, that there are a


 "-with-windows" in Window - class (or the switch is added later one,


 MyWindow was already compiled and shipped 1000 yards away),
 so you do really not expect, that MyWindow.CreateWindow is called,
 before the constructor finished.
 And so you thought, that "file" must be in a correct state - but it


 This is called "side effects of the constructor" and should be properly
 documented in the code. That is, it should be stated clearly that
 CreateWindow
 is called from the ctor of Window, and once you're aware of it, you
 can put all the initialization before the call to super().

 In fact, it is a wise idea to initialize members before calling super()
 whenever possible.

I cried out as I read this and was up to shout loudly that the opposite is the truth... But then I realized you were right. (some freely translated phrase of a poem from Goethe ;-) The only thing against it may be, that you need to call base-class functions or you may need base-class members to initialize your class-members. So it may be a good guideline to beginners is to lay out the constructor as follow: this() { /* first do stuff that don't depend on base-class-members or function */ super(); /* now, do stuff that depend on a correct base-class */ } This seems understandable and it should minimize the side effect of surprises... And best: no need to change the compiler ;-)
 As example some of my thoughts about explicit calling:
 - Protect the compiler the access to the base classes members and
 member-variables, before the super-constructor is called at least once?

Hmmm... class Foo { int n; this() { ... } } class Bar: Foo { this() { bar(); /* not a base member! */ super(); } void bar() { n = 666; /* modify the base member! */ } } While this example is rather simplistic, I don't see how it can be detected in more general case. Bar.bar() could have been overriden in some descendant of Bar, and you'd never know about it, nor would the compiler...

Hm.. If it would not dynamic linked, it could be.... ;-)
 - If you do not call the base class constructor, it is automatically

Currently, it aborts with an error in such a case, I believe.

good. Imi
Mar 06 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a66091$1d3b$1 digitaldaemon.com...

 So it may be a good guideline to beginners is to lay out the
 constructor as follow:

 this() {
   /* first do stuff that don't depend on base-class-members or function */
   super();
   /* now, do stuff that depend on a correct base-class */
 }

 This seems understandable and it should minimize the side effect
 of surprises... And best: no need to change the compiler ;-)

Exactly. And BTW that's the way I do it. =)
Mar 06 2002
prev sibling parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a65sot$1b28$1 digitaldaemon.com...
<SNIP>
 Another example (a more real one:)

 ------ this is a library you don't own the sources -------
 class Window
 {
   this() { if (cmdline == "-with-window") CreateWindow(); }

   void CreateWindow() = 0;  // user have to implement how to do this
 ...
 }

 ----- this is your code. Here you may change anything ------
 class MyWindow
 {
   FileWrapperClass* file = null;
   this () {...; super(); ...; file = new FileWrapperClass; }

   CreateWindow()
   {
     file.load_window_resources();    // <-- null-pointer-access !
   }
 }

Good example.
 The problem here is, that you even might not know, that there are a switch
 "-with-windows" in Window - class (or the switch is added later one, when
 MyWindow was already compiled and shipped 1000 yards away),
 so you do really not expect, that MyWindow.CreateWindow is called,
 before the constructor finished.
 And so you thought, that "file" must be in a correct state - but it isn't.

In this case you could protect yourself: this () { file = new FileWrapperClass; super(); } I think this works in the general case? Initialize your own fields, call base constructor, do the rest? It looks ugly to me though, I think that the base constructor should be called first normally. -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net __________________________________________ Remove _XYZ from my address when replying by mail
Mar 06 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"OddesE" <OddesE_XYZ hotmail.com> schrieb im Newsbeitrag
news:a666h8$1fj1$1 digitaldaemon.com...
 In this case you could protect yourself:

 this ()
 {
    file = new FileWrapperClass;
    super();
 }

 I think this works in the general case?
 Initialize your own fields, call base constructor,
 do the rest?  It looks ugly to me though, I
 think that the base constructor should be
 called first normally.

Yeah. It works for many cases. It does not work for Initializing member functions, that depend on anything that hat to do with the base class, because you would have to access the base before their constructor was through. Maybe it is simple *different* to write classes with such concept. Constructors become more "normal functions" who are implizit called and where you can put some uncritical initialisation in. They loose their academical touch of beeing something you only have to touch with velvet gloves. And maybe this is good so..... ? Because its just pragmatic instead of scietific. Although I do not think it is really good...! ;-) Imi.
Mar 06 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a66ddt$1ioe$1 digitaldaemon.com...

 concept. Constructors become more "normal functions"
 who are implizit called and where you can put some
 uncritical initialisation in.
 They loose their academical touch of beeing something you
 only have to touch with velvet gloves.

 And maybe this is good so..... ? Because its just pragmatic
 instead of scietific.

Yes, yes!!! =)
Mar 06 2002
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a659o0$12u2$1 digitaldaemon.com...
 I believe assertions on expressions with side effects are forbidden
 by the language, and the compiler should do its best to catch
 such things.

A probably more accurate statement would be that the assert expression must be written so that its removal or insertion has no effect on the proper operation of the program. Unfortunately, I see no way for the compiler to enforce this beyond trivial cases. Writing good asserts and invariants is a learned skill, and I'm still learning it myself. I do know that the combination of asserts, invariants, and unittests have significantly speeded up my own production of quality code.
Mar 09 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a6f0t2$2som$1 digitaldaemon.com...

 A probably more accurate statement would be that the assert expression

 be written so that its removal or insertion has no effect on the proper
 operation of the program. Unfortunately, I see no way for the compiler to
 enforce this beyond trivial cases.

At least it should forbid assignments and function calls there.
Mar 09 2002
parent reply "Roberto Mariottini" <rmariottini lycosmail.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a6f11t$2sp1$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a6f0t2$2som$1 digitaldaemon.com...

 A probably more accurate statement would be that the assert expression

 be written so that its removal or insertion has no effect on the proper
 operation of the program. Unfortunately, I see no way for the compiler


 enforce this beyond trivial cases.

At least it should forbid assignments and function calls there.

I have many function calls in my own asserts (like IsEmpty(...), Initialized(), and so on). I suggest you can call only _const_ functions :-) Ciao
Mar 11 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Roberto Mariottini" <rmariottini lycosmail.com> wrote in message
news:a6ido2$1agt$1 digitaldaemon.com...

 I suggest you can call only _const_ functions :-)

There are no const functions...
Mar 11 2002
prev sibling parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
Dear Immanuel,

You were right that I missed your point, I see it
now...  :)
I agree that calling a virtual function from within a
constructor might cause trouble, however there does
not exist an effective solution to that problem.
You state that being able to call a virtual function from
a constructor is bad, because now you can't trust your
object to be initialized in any function when you inherit
from a base class that someone else programmed.
Consider this however:
I state that you can't trust your object to be initialized
in any function when you inherit from a base class
someone else programmed, period.
How are you ever going to be sure that the author of
the base class did his work properly and initialized all the
member variables in the constructor at all?
Virtual function calls or not, the fact of the matter is that
you can't be sure.

Consider this C++ code:

class Foo
{
   CImportantClass *pVeryImportant;

   Foo ()
   {
      // Oops, forgot to initialize my all important pointer.
      // it is not even NULL, it is just garbage!
   }
};

class Bar: public Foo
{
   void MyFunction()
   {
      pVeryImportant->IAmDead();       // Crash and burn...
   }

   void AnotherTry()
   {
      if (pVeryImportant != NULL)     // Won't help, because
      {                                                // the pointer is
garbage
         pVeryImportant->IAmDead();       // And crash again...
      }
   }
};

Now how is any construct going to protect you against
this? You see, D already greatly improves on the situation.
If you use code that is very badly programmed, you will
be in trouble anyhow. The point of D is to make it easy to
write good code, not impossible to write bad code.

Your point that it might cause trouble remains valid though.
Walter does not like warnings, otherwise one might be
issued when you override a function from a base class that
is called from it's constructor, and one might be issued when
you call a function from a constructor without prepending it's
class name, meaning you would write DoSomething();
instead of MyClass.DoSomething(). Otherwise I don't see
a good solution, without seriously hampering an otherwise
very powerful language feature.


--
Stijn
OddesE_XYZ hotmail.com
http://OddesE.cjb.net
__________________________________________
Remove _XYZ from my address when replying by mail
Mar 06 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"OddesE" <OddesE_XYZ hotmail.com> schrieb im Newsbeitrag
news:a65rs6$1ait$1 digitaldaemon.com...
 I state that you can't trust your object to be initialized
 in any function when you inherit from a base class
 someone else programmed, period.
 How are you ever going to be sure that the author of
 the base class did his work properly and initialized all the
 member variables in the constructor at all?
 Virtual function calls or not, the fact of the matter is that
 you can't be sure.

The construct of calling a virual function from a constructor may be a good idea! (This is the real problem, it IS still a powerful tool you can use for good as for bad ;-) See the example with CreateWindow in my other post...
 Consider this C++ code:

 class Foo
 {
    CImportantClass *pVeryImportant;

    Foo ()
    {
       // Oops, forgot to initialize my all important pointer.
       // it is not even NULL, it is just garbage!
    }
 };

This is surely a mistake and should be blamed to the author of Foo! It is a real bug, not a class design, I think.
 Now how is any construct going to protect you against
 this? You see, D already greatly improves on the situation.

Yes, most because the member are preinitialized (so this gives at least the chance for a workaround ;-)
 If you use code that is very badly programmed, you will
 be in trouble anyhow. The point of D is to make it easy to
 write good code, not impossible to write bad code.

But I would add the statement "it should not be easy to get errors, that are hard to understand."
 Your point that it might cause trouble remains valid though.
 Walter does not like warnings, otherwise one might be

:-[ It seems, that Walter does like printf, or why there are a static printf - member in Object? :-( Why does Walter do not like warnings?
 issued when you override a function from a base class that
 is called from it's constructor, and one might be issued when
 you call a function from a constructor without prepending it's
 class name, meaning you would write DoSomething();
 instead of MyClass.DoSomething(). Otherwise I don't see
 a good solution, without seriously hampering an otherwise
 very powerful language feature.

Hm, I am still in doubt if this is good... maybe these "already initialized" - checking can be automated by the compiler? Imi
Mar 06 2002
next sibling parent "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a65u2p$1bko$1 digitaldaemon.com...

 :-[ It seems, that Walter does like printf, or why there are a
 static printf - member in Object? :-(

Static printf() in Object was a bug, AFAIK, and was removed from the class (you can check it in the latest alpha). For now, printf() is the only way to do screen I/O in a more or less convenient way, since we don't have function overloading, typesafe varargs, or variants.
 Why does Walter do not like warnings?

The answer is in the "standartize errors/warnings" thread.
Mar 06 2002
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a65u2p$1bko$1 digitaldaemon.com...
 Why does Walter do not like warnings?

I should put this in the FAQ <g>. The trouble with warnings is they introduce ambiguities into whether a program successfully compiled or not. Many times I've gotten source code from someone, and it compiles with warnings. Are those warnings supposed to be there or not? Who knows? Looking closer at each warning, it turns out to be the result of a problem in the design of the language. They can be eliminated by changing the design. For example, warnings about possible = in conditional: if (a = b) can be eliminated by a language change disallowing assignment in a boolean expression, so the above must be: if ((a = b) != null) or: if (a == b) The need for the warning is gone.
Mar 06 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Walter" <walter digitalmars.com> schrieb im Newsbeitrag
news:a671bd$1rjq$1 digitaldaemon.com...
 "Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
 news:a65u2p$1bko$1 digitaldaemon.com...
 Why does Walter do not like warnings?

I should put this in the FAQ <g>. The trouble with warnings is they introduce ambiguities into whether a program successfully compiled or not. Many times I've gotten source code from someone, and it compiles with warnings. Are those warnings supposed

 be there or not? Who knows?

 Looking closer at each warning, it turns out to be the result of a problem
 in the design of the language. They can be eliminated by changing the
 design. For example, warnings about possible = in conditional:

What about "unused parameter"? If I read right, in D this is an error? But often it is ignored, because you have to declare a parameter (as example because you everride a virtual function) but do not use it: InvisibleLine::draw (int x,int y, int color); Does not need color, because it is invisible, but has to declare a third parameter to be correct overwrite the virtual draw. Imi
Mar 07 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a67p5j$26ie$1 digitaldaemon.com...

 InvisibleLine::draw (int x,int y, int color);

 Does not need color, because it is invisible, but has to declare a third
 parameter
 to be correct overwrite the virtual draw.

The suggested form is: void draw(int x, int y, int /* unnamed */); This makes it clear that the 3rd parameter is not used. I believe that's what Stroustrup said about C++ as well.
Mar 07 2002
parent reply "Immanuel Scholz" <digital-mars kutzsche.net> writes:
"Pavel Minayev" <evilone omen.ru> schrieb im Newsbeitrag
news:a681do$2a37$1 digitaldaemon.com...
 "Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
 news:a67p5j$26ie$1 digitaldaemon.com...

 InvisibleLine::draw (int x,int y, int color);

 Does not need color, because it is invisible, but has to declare a third
 parameter
 to be correct overwrite the virtual draw.

The suggested form is: void draw(int x, int y, int /* unnamed */); This makes it clear that the 3rd parameter is not used. I believe that's what Stroustrup said about C++ as well.

oh. I thought unnamed parameter were not allowed in D? Great, now I am absolutly satisfied (at least with "no warnings" ;)
Mar 08 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Immanuel Scholz" <digital-mars kutzsche.net> wrote in message
news:a6b1b3$14ro$1 digitaldaemon.com...

 oh. I thought unnamed parameter were not allowed in D?

For some reason, they are currently forbidden in function definitions (but allowed in declarations). Following Walter's logic, to prevent the "unused parameter" warning, unnamed parameters must be allowed everywhere...
Mar 08 2002