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

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.




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




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

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

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
> called?
>
> Currently, it aborts with an error in such a case, I believe.

good.

Imi



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

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.



March 06, 2002
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))) ]


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



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



March 07, 2002
"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. =)




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



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