March 05, 2002
"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



March 05, 2002
"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
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!

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
it
> 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
with
> 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
invariant.

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



March 06, 2002
"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
> 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!
> Hm. I do not think so. Class invariants are, as long as I read the manual 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.
> Wonderful! I missed this one in C++ due lack of sense for typical error 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.
> Only in debug!
> 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.
> 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!

Again, you can leave that stuff turned on.

> > 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)

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



March 06, 2002
"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
manual
> > 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
finished?
> > }
>
> That is a good point. You can guard against that by using a class
invariant
> 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.
> > Wonderful! I missed this one in C++ due lack of sense for typical error 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
values.
> > 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
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!
>
> 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++.
> > 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)
>
> <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



March 06, 2002
"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
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:

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


March 06, 2002
"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
functions?

So what?

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


March 06, 2002
"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 -
things.
> 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
best
> 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
not
> 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.




March 06, 2002
"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
> functions?
>
> 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



March 06, 2002
"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 -
> things.
> > 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
> best
> > 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
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()); "  ;-)
>
> 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



March 06, 2002
"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! =)