Initialization

Initialization

For class initialization semantics, first the object is zeroed-out, then the root class field initializers are executed in declaration order, then the root class constructor is run, then executing proceeds to the derived class’s field initializers and constructor and so on. Virtual method calls will dispatch to the fully derived type even when invoked in a base class’s constructor, which can result in a method being called in a type whose constructor has not yet executed.

class Person
{
    public String mFirstName = GetFirstName();
    public String mLastName = GetLastName();

    public this()
    {
        AddPerson();
    }
}

class Student : Person
{
    public School mSchool = GetSchool();

    public this()
    {
        RegisterStudent();
    }
}

/* When constructing a Student, the initializations will occur in this order:
    mFirstName = GetFirstName()
    mLastName = GetLastName()
    AddPerson();
    mSchool = GetSchool()
    RegisterStudent();
 */

For struct initialization semantics, the struct is not automatically zeroed out – the fields initializers and constructor together must fully initialize all the struct fields. Users of a struct can also choose to not execute a constructor and just manually initialize all the fields directly. Uses of structs that are not fully initialized will be disallowed via simple static analysis, which can be overriden via the explicit “?” uninitialized expression.

/* In this case, we know "UseVec" will initialize the Vector2 value so we use '?' to avoid a "Not initialized" error */
Vector2 vec = ?;
UseVec(&vec);

Arrays initilization at allocation time is also supported.

/* Zero-initialize ending 7 elements */
int[] iArr = new int[10] (1, 2, 3, );

/* Leave ending 7 elements uninitializezd */
int[] iArr = new int[10] (1, 2, 3, ?);

/* Throws an initializer size mismatch error - ending comma is required to zero-initialize is desired */
int[] iArr = new int[10] (1, 2, 3);

Types can also define static fields and static constructors. Static initialization order is defined by alphanumeric order of the fully-qualified type name. This order can be overriden with type attributes such as [StaticInitPriority(…)] and [StaticInitAfter(…)]. Static initialization that refer to static fields in other types will cause that type’s static initializers to execute on-demand before the access. This on-demand initialization can cause circular dependencies, however, which are resolved by simply skipping any reentrant initializer calls.

Destruction

Classes can define destructors. In general, destruction occurs in reverse order from initialization.

class Person
{
    public String mFirstName = GetFirstName() ~ delete _;
    public String mLastName = GetLastName() ~ delete _;

    public this()
    {
        AddPerson();
    }

    public ~this()
    {
        RemovePerson();
    }
}

class Student : Person
{
    public School mSchool = GetSchool() ~ ReleaseSchool(_);

    public this()
    {
        RegisterStudent();
    }

    public ~this()
    {
        UnregisterStudent();
    }
}

/* When deleting a Student, the deinitialization will occur in this order:
    UnregisterStudent()
    ReleaseSchool(mSchool)
    RemovePerson()
    delete mLastName
    delete mFirstName
*/

Structs cannot define destructors, but they can define a ‘Dispose’ method which can contain deinitialization code. Dispose can be used in ‘RAII-style’ (called on scope exit) with using statements or defer statements.