www.digitalmars.com         C & C++   DMDScript  

D - construction destruction conventions

reply Ruslanas Abdrachimovas <anubis 03bar.ktu.lt> writes:
Hello,

could some body please explain construction/destruction conventions in 
D, because I'm confused with the fact:
"allowing one constructor to call another at any point".

That's confuses a little bit, because I can't imagine subclass without 
constructed baseclass.

Ruslanas
Jan 30 2002
parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Ruslanas Abdrachimovas" <anubis 03bar.ktu.lt> wrote in message
news:3C57E45C.7010804 03bar.ktu.lt...
 Hello,

 could some body please explain construction/destruction conventions in
 D, because I'm confused with the fact:
 "allowing one constructor to call another at any point".

 That's confuses a little bit, because I can't imagine subclass without
 constructed baseclass.

 Ruslanas

I think what Walter means by it is that two constructors of the *same* class can call each other. You might have a constructor that takes parameters and a default constructor. The default constructor might then call the other constructor with the default values as parameters: class Test { this () { this (10); } this (int iParam) { m_iValue = iParam; } int m_iValue; } -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net __________________________________________ Remove _XYZ from my address when replying by mail
Jan 30 2002
next sibling parent "Juan Carlos Arevalo Baeza" <jcab roningames.com> writes:
"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a39jnj$21em$1 digitaldaemon.com...
 "Ruslanas Abdrachimovas" <anubis 03bar.ktu.lt> wrote in message
 news:3C57E45C.7010804 03bar.ktu.lt...
 Hello,

 could some body please explain construction/destruction conventions in
 D, because I'm confused with the fact:
 "allowing one constructor to call another at any point".

 That's confuses a little bit, because I can't imagine subclass without
 constructed baseclass.

 Ruslanas

I think what Walter means by it is that two constructors of the *same* class can call each other.

Actually, it's a bit more profound than that. What's the meaning of a constructor? C++ -> It is the "thingy" that gets called to make an object usable. It begins the "life" of the object. Before the constructor, there's no object. Not even an uninitialized one. For all the language cares, a compiler might make it so that the memory itself (the bits and bytes) is not accessible before constructing the object or after destructing it. That makes the whole constructor-destructor thng very strict. Until the base class' constructor runs, there is nothing there, and nothing is accessible. This means that the base class constructor HAS to be called before the derived class constructor begins. D -> It's a function that is used to initialize the object. Just a function that hopefully puts meaningful values there. Now, when a derived class' constructor gets called, the base class constructor hasn't been called yet. It has to be called manually, if so desired. But the memory is definitely there and accessible. Salutaciones, JCAB
Jan 30 2002
prev sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a39jnj$21em$1 digitaldaemon.com...

 I think what Walter means by it is that two constructors of the
 *same* class can call each other. You might have a constructor

Actually, your constructor may call the constructor of the base class - but doesn't have to! This might seem strange from the point of view of C++ programmer, but the resulting object will be pretty valid, vtable is there; most likely, however, you will have to call super() just to make sure you don't break some code in the base class... Once again, what about _requiring_ call to super() to be present in all execution branches of a constructor?
Jan 31 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3c1nl$2hfk$1 digitaldaemon.com...
 "OddesE" <OddesE_XYZ hotmail.com> wrote in message
 news:a39jnj$21em$1 digitaldaemon.com...
 I think what Walter means by it is that two constructors of the
 *same* class can call each other.


Yes.
 Actually, your constructor may call the constructor of the base
 class - but doesn't have to! This might seem strange from the
 point of view of C++ programmer, but the resulting object will
 be pretty valid, vtable is there; most likely, however, you will
 have to call super() just to make sure you don't break some code
 in the base class...

 Once again, what about _requiring_ call to super() to be present
 in all execution branches of a constructor?

I'm not sure what the right answer is here. I don't like the C++ way with the base initializer syntax, it's too restrictive.
Feb 01 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3er6r$sr$3 digitaldaemon.com...

 I'm not sure what the right answer is here. I don't like the C++ way with
 the base initializer syntax, it's too restrictive.

I don't mean the C++ syntax. I suggest to leave it as it is now, but raise an error if base constructor occasionally doesn't get called.
Feb 01 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
An example:

    // legal code
    this(int x)
    {
        if (x > 0)
            super(x);
        else if (x < 0)
            super(abs(x));
        else
            super();
    }

    // illegal code
    this(int x)
    {
        if (x > 0)
            super(x);
        else if (x < 0)
            super(abs(x));
    }

The latter should raise a "not all control paths call base constructor"
error (or maybe warning?), because sometimes (x == 0) base constructor
is not called at all - which is almost always a bug.
Feb 01 2002
next sibling parent "Walter" <walter digitalmars.com> writes:
True. I think you're on to a good addition here. -Walter

"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3es6c$i5$1 digitaldaemon.com...
 An example:

     // legal code
     this(int x)
     {
         if (x > 0)
             super(x);
         else if (x < 0)
             super(abs(x));
         else
             super();
     }

     // illegal code
     this(int x)
     {
         if (x > 0)
             super(x);
         else if (x < 0)
             super(abs(x));
     }

 The latter should raise a "not all control paths call base constructor"
 error (or maybe warning?), because sometimes (x == 0) base constructor
 is not called at all - which is almost always a bug.

Feb 01 2002
prev sibling next sibling parent Ruslanas Abdrachimovas <anubis 03bar.ktu.lt> writes:
I like such idea. Because if you want to be implementation independent, 
you MUST call super() - it moves base class objects to correct state (if 
ther aren't some bugs in base class).

I think that REQUIRING super() call is a MUST. :)

Pavel Minayev wrote:
 An example:
 
     // legal code
     this(int x)
     {
         if (x > 0)
             super(x);
         else if (x < 0)
             super(abs(x));
         else
             super();
     }
 
     // illegal code
     this(int x)
     {
         if (x > 0)
             super(x);
         else if (x < 0)
             super(abs(x));
     }
 
 The latter should raise a "not all control paths call base constructor"
 error (or maybe warning?), because sometimes (x == 0) base constructor
 is not called at all - which is almost always a bug.
 
 
 

Feb 06 2002
prev sibling parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3es6c$i5$1 digitaldaemon.com...
 An example:

     // legal code
     this(int x)
     {
         if (x > 0)
             super(x);
         else if (x < 0)
             super(abs(x));
         else
             super();
     }

     // illegal code
     this(int x)
     {
         if (x > 0)
             super(x);
         else if (x < 0)
             super(abs(x));
     }

 The latter should raise a "not all control paths call base constructor"
 error (or maybe warning?), because sometimes (x == 0) base constructor
 is not called at all - which is almost always a bug.

I think Java is already doing this isn't it? Would be a very good idea anyhow. I don't know about the warning though? Is there a situation where this is not an error? -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net __________________________________________ Remove _XYZ from my address when replying by mail
Feb 07 2002
parent reply "Walter" <walter digitalmars.com> writes:
"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a3uuhv$2aqo$1 digitaldaemon.com...
 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a3es6c$i5$1 digitaldaemon.com...
 An example:

     // legal code
     this(int x)
     {
         if (x > 0)
             super(x);
         else if (x < 0)
             super(abs(x));
         else
             super();
     }

     // illegal code
     this(int x)
     {
         if (x > 0)
             super(x);
         else if (x < 0)
             super(abs(x));
     }

 The latter should raise a "not all control paths call base constructor"
 error (or maybe warning?), because sometimes (x == 0) base constructor
 is not called at all - which is almost always a bug.

I think Java is already doing this isn't it? Would be a very good idea anyhow. I don't know about the warning though? Is there a situation where this is not an error?

As it turns out, the way D builds objects is all class members, including base classes, get initialized with the static defaults.
Feb 07 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3vsm6$1e1s$2 digitaldaemon.com...

 As it turns out, the way D builds objects is all class members, including
 base classes, get initialized with the static defaults.

So what? Base constructor might perform some initialization that is cruical for its methods to work properly. And, following the incapsulation paradigm, it's not responsible for telling you that it does, right?
Feb 08 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a40jgb$1p1j$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a3vsm6$1e1s$2 digitaldaemon.com...

 As it turns out, the way D builds objects is all class members,


 base classes, get initialized with the static defaults.

So what? Base constructor might perform some initialization that is cruical for its methods to work properly. And, following the incapsulation paradigm, it's not responsible for telling you that it does, right?

You're right. I was just pointing out that it is not initialized to random data.
Feb 08 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a41imf$2pnk$5 digitaldaemon.com...

 You're right. I was just pointing out that it is not initialized to random
 data.

...just as stated in the spec. Yes, I'm aware of that. Good idea BTW.
Feb 08 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a41jke$2q5a$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a41imf$2pnk$5 digitaldaemon.com...

 You're right. I was just pointing out that it is not initialized to


 data.

...just as stated in the spec. Yes, I'm aware of that. Good idea BTW.

It actually winds up more efficient than the way C++ does it. How a class object is initialized is a static default version of it is defined, and then is memcpy'd over the allocated object. This sets up all the static defaults, and even initializes all the vptr's automatically!
Feb 08 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a41oeq$2se5$7 digitaldaemon.com...

 It actually winds up more efficient than the way C++ does it. How a class
 object is initialized is a static default version of it is defined, and

 is memcpy'd over the allocated object. This sets up all the static

 and even initializes all the vptr's automatically!

I've seen that code. Yep, it's quite fast. Also, if you add the pointer to constructor to the classinfo (pleeeease!), it could be used to construct objects by their classinfos - could be used for serialization.
Feb 08 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a42kgo$6oa$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a41oeq$2se5$7 digitaldaemon.com...

 It actually winds up more efficient than the way C++ does it. How a


 object is initialized is a static default version of it is defined, and

 is memcpy'd over the allocated object. This sets up all the static

 and even initializes all the vptr's automatically!

I've seen that code. Yep, it's quite fast. Also, if you add the pointer to constructor to the classinfo (pleeeease!), it could be used to construct objects by their classinfos - could be used for serialization.

I plan on adding serialization support. ClassInfo will likely acquire more stuff over time. Info on each field will be necessary to make a copying gc, for example. Serialization is another, as you mentioned.
Feb 09 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a42tca$hrc$3 digitaldaemon.com...

 I plan on adding serialization support. ClassInfo will likely acquire more
 stuff over time. Info on each field will be necessary to make a copying

 for example. Serialization is another, as you mentioned.

Serialization is easy to make as long as we have a globally accessible list of classinfos, and each classinfo knows its constructor. Then, an instance of the class can be easily created from the class name: // object.d class ClassInfo { ... Object newInstance() { ... } // creates new object of that type static ClassInfo[char[]] classes; // list of all classinfos in program } // stream.d interface IPersistent { void saveToStream(Stream); void loadFromStream(Stream); } class Stream { ... Object readObject() { int len; char[] classname; Object obj; IPersistent pers; // read classname file.read(len); classname = file.readString(len); // create a class instance obj = ClassInfo.classes[classname].newInstance(); // check if it is IPersistent pers = cast(IPersistent) obj; assert(pers); // call user-defined loading routine pers.loadFromStream(this); // and return what we have return obj; } }
Feb 09 2002
parent reply "Walter" <walter digitalmars.com> writes:
The list of classes is already globally available, look at how modules get
initialized!

"Pavel Minayev" <evilone omen.ru> wrote in message
news:a434lo$lmu$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a42tca$hrc$3 digitaldaemon.com...

 I plan on adding serialization support. ClassInfo will likely acquire


 stuff over time. Info on each field will be necessary to make a copying

 for example. Serialization is another, as you mentioned.

Serialization is easy to make as long as we have a globally accessible list of classinfos, and each classinfo knows its constructor. Then, an instance of the class can be easily created from the class name: // object.d class ClassInfo { ... Object newInstance() { ... } // creates new object of that

         static ClassInfo[char[]] classes; // list of all classinfos in
 program
     }

     // stream.d
     interface IPersistent
     {
         void saveToStream(Stream);
         void loadFromStream(Stream);
     }

     class Stream
     {
         ...

         Object readObject()
         {
             int len;
             char[] classname;
             Object obj;
             IPersistent pers;
             // read classname
             file.read(len);
             classname = file.readString(len);
             // create a class instance
             obj = ClassInfo.classes[classname].newInstance();
             // check if it is IPersistent
             pers = cast(IPersistent) obj;
             assert(pers);
             // call user-defined loading routine
             pers.loadFromStream(this);
             // and return what we have
             return obj;
         }
     }

Feb 09 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a43tq4$11uk$3 digitaldaemon.com...

 The list of classes is already globally available, look at how modules get
 initialized!

Ahh... now I see. But the _moduleinfo_array[] is not "official" part of the language, right? So it's not portable... Also I've just thought that it'd be great for the class to know the module where it's declared. Well you know, just a ModuleInfo member in the ClassInfo. Might be useful to handle cases where classnames match...
Feb 09 2002
parent "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a443u6$148r$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a43tq4$11uk$3 digitaldaemon.com...

 The list of classes is already globally available, look at how modules


 initialized!

Ahh... now I see. But the _moduleinfo_array[] is not "official" part of the language, right? So it's not portable...

I hadn't thought of that. Once some experience with it shows it's right, it should probably go into the spec.
 Also I've just thought that it'd be great for the class to know the
 module where it's declared. Well you know, just a ModuleInfo member
 in the ClassInfo. Might be useful to handle cases where classnames
 match...

Yeah, that should be there.
Feb 09 2002