Thread overview
Order of base-class constructor calls
Oct 07, 2011
Andrej Mitrovic
Oct 11, 2011
Andrej Mitrovic
Oct 11, 2011
Regan Heath
October 07, 2011
Is there any way to enforce the user to call the base-class ctor via super(), so it's the first statement in his class ctor? e.g.:

class Base {
    this(int) { }
}

class Derived : Base {
    this(int x) {
        super(x);
        // user statements
    }
}

The problem I'm having is that Base does some required initialization in its ctor, and Derived shouldn't be allowed to call any Base class methods (well, virtual methods) before calling the Base ctor.

This is somewhat mitigated if I have a default constructor in the base class, e.g.:

class Base {
    this() { /* init section */ }
    this(int) { this(); }
}

class Derived : Base {
    this(int x) {
        // Base class ctor automatically called *before* any other statements
        // user statements..
    }
}

But this is only partially safe as the user could still call super()
or super(int) after he's made some calls of his own, e.g.:

class Base {
    this() { /* init section */ }
    this(int) { this(); }
    void foo() { /* expects Base.this() having been already called */ }
}

class Derived : Base {
    this(int x) {
        foo();  // boom
        super();  // or super(int);
    }
}

So I'm looking for some techniques or tricks (or, dare I say, design patterns :x) you guys might have if you've ever ran into this kind of problem.
October 11, 2011
On Fri, 07 Oct 2011 18:02:33 -0400, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:

> Is there any way to enforce the user to call the base-class ctor via
> super(), so it's the first statement in his class ctor? e.g.:
>
> class Base {
>     this(int) { }
> }
>
> class Derived : Base {
>     this(int x) {
>         super(x);
>         // user statements
>     }
> }
>
> The problem I'm having is that Base does some required initialization
> in its ctor, and Derived shouldn't be allowed to call any Base class
> methods (well, virtual methods) before calling the Base ctor.
>
> This is somewhat mitigated if I have a default constructor in the base
> class, e.g.:
>
> class Base {
>     this() { /* init section */ }
>     this(int) { this(); }
> }
>
> class Derived : Base {
>     this(int x) {
>         // Base class ctor automatically called *before* any other statements
>         // user statements..
>     }
> }
>
> But this is only partially safe as the user could still call super()
> or super(int) after he's made some calls of his own, e.g.:
>
> class Base {
>     this() { /* init section */ }
>     this(int) { this(); }
>     void foo() { /* expects Base.this() having been already called */ }
> }
>
> class Derived : Base {
>     this(int x) {
>         foo();  // boom
>         super();  // or super(int);
>     }
> }
>
> So I'm looking for some techniques or tricks (or, dare I say, design
> patterns :x) you guys might have if you've ever ran into this kind of
> problem.

Maybe you can make the ctor private?  Then the derived class cannot call it directly, it needs to be implicit.

-Steve
October 11, 2011
Nope. Private ctors have to be called from within the same module, whether implicit or not:

test.d:
class Foo
{
    private this() { }  // Error: constructor main.Bar.this no match
for implicit super() call in constructor
}

import test;
class Bar : Foo
{
    this() { }
}

void main()
{
    auto bar = new Bar();
}
October 11, 2011
On Fri, 07 Oct 2011 23:02:33 +0100, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
> So I'm looking for some techniques or tricks (or, dare I say, design
> patterns :x) you guys might have if you've ever ran into this kind of
> problem.

The best I can come up with is a runtime solution:

import std.stdio;

class Base {
    private bool _init = false;
    this(int x) { _init = true; }
    void foo()
    {
        if (_init) writefln("ok");
        else writefln("not initialised");
    }
}

class DerivedWell : Base {
    this(int x) {
        super(x);
        foo();
    }
}

class DerivedBadly : Base {
    this(int x) {
        foo();
        super(x);
    }
}

void main()
{
    auto d1 = new DerivedWell(1);
    auto d2 = new DerivedBadly(1);
}

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
October 12, 2011
On Tue, 11 Oct 2011 12:40:29 -0400, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:

> Nope. Private ctors have to be called from within the same module,
> whether implicit or not:
>
> test.d:
> class Foo
> {
>     private this() { }  // Error: constructor main.Bar.this no match
> for implicit super() call in constructor
> }
>
> import test;
> class Bar : Foo
> {
>     this() { }
> }
>
> void main()
> {
>     auto bar = new Bar();
> }

Hm... that makes sense.

You can try mucking around with roll-your-own construction.  That is, ignore the constructor and use a mixture of public final initialize functions + protected virtual initialize functions.

It might just be something that you have to accept is not definable by the base class :(

C++ requires construction of base classes before the main body of a derived constructor is called.  And that has its own problems too...

-Steve