Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

Qualified constructor revisited

Version 1
Created 2013-12-17
StatusDraft
Last modified 2013-12-17
Author Hara Kenji

Abstract

This DIP redesigns qualified constructor definitions.

Motivation

From 2.063, qualified constructor is implemented, and unique constructor
concept is added.

https://github.com/D-Programming-Language/dmd/pull/1726

However, current definition is very complex and hard to understand.

http://dlang.org/class#constructors\

> “Constructors can be overloaded with different attributes.” …

The issues in current unique constructor definition are:

This situation should be improved.

Description

In the ideal world, objects would have only one of the two qualifiers - mutable or immutable. So, there would be just two constructors:

However, in actual D code, there are two wildcard qualifiers, const and inout. Therefore, we would also need additional two ways to:

For those requests, provide additional two concepts, “inout constructor” and “const constructor”.

Mutable Constructor

If a constructor is unqualified, it will be used for mutable object construction.

struct S {     this(int) { ... } } void main() {     S sm = S(1); }

Immutable Constructor

If a constructor is qualified with immutable, it will be used for immutable object construction.

struct S {     this(int) immutable { ... } } void main() {     immutable S si = immutable S(1); }

Inout Constructor

If a constructor is qualified with inout, and has one or more inout parameters, it will become inout constructor.

struct S {     this(inout int[] a) inout { ... } } void main() {     int[] ma;     immutable int[] ia; \     auto sm = S(ma);            // OK     auto si = immutable S(ia);  // OK \   //auto sm = immutable S(ma);  // NG   //auto si = S(ia);            // NG }

// For classes, zero-arg inout constructor is allowed? // –> To reduce confusion, this DIP disallows such definition.

Const Constructor

If a constructor is qualified with const, it will be used to construct arbitrary qualified objects.

Inside const constuctor, you need to initialize the instance fields by Unique Expression (See DIP49).

struct S {     const int[] arr;     this(int[] a) const {       //this.arr = a;       // NG         this.arr = a.dup;   // OK, array.dup makes unique expression for int[]     } }

After construction finished, the generate object will be unique object - it means that the object owns no reference to the external state. So, it could also be called “unique constructor”, based on the concept.

Advantages with respect to the currently implemented definition:

Overloading of qualified constructors

If mutable constructor is defined,

If immutable constructor is defined,

If inout constructor is defined,

If const constructor is defined,

: This is necessary due to make unique constructor definition simple.
Issue 9665 - Structure constant members can not be initialized if have opAssign
–> Has been fixed in 2.064.
: Currently, const type qualifier always overrides inout.
But the behavior will sometimes accidentally hurt inout constructor concept.
struct Rebindable(T) {
    this(inout T initializer) inout { ... }
    // Intend to define inout constructor.
}
Rebindable!(const Object) r;
// Currently inout(const(int)) is shrinked to const(int),
// so the constructor would loose inout parameter, and
// will cause "inout constructor should have one or more inout parameters" error.
To resolve the issue, I think we need to fix issue 6930.
Issue 6930 - combined type of immutable(T) and inout(T) should be inout(const(T))

Why ‘const’ constructor will be called to create arbitrary qualified object?

When an object is constructed by const constructor, the object would have either mutable or immutable qualifier. And, const method is always callable on both mutable and immutable object.

struct S {     this(int) const { ... } } void main() {    // const constructor is callable on constructing mutable object    S sm = S(1); \    // const constructor is callable on constructing immutable object    immutable S si = immutable S(1); }

There’s no mutation against widely known “const method” concept.

Rationale

DIP49 is based on the same concept, and they are designed symmetry right now.

This document has been placed in the Public Domain.