On Tuesday, 14 November 2023 at 14:36:57 UTC, dhs wrote:
Just to clarify some more: isn't "s1 = ss1" similar to something like:

```d
    const(S1) s1;
    S1 ss1; // ss1 is now S1.init
    S1_copy_construct_const_in_const_out(ss1, s1);
```

If this is the case, the compile error is expected, but why/how/where do "implicit qualifer conversions" apply here?

The real answer is that constructors are special, and constructor calls follow different type-checking rules from normal function calls.

Here's an example:

```d
struct S
{
    int n;
    this(int n) const { this.n = n; }
    void fun() const {}
}

void main()
{
    S s;
    s.__ctor(123); // error
    s.fun(); // ok
}

```

Normally, it's fine to call a `const` method on a mutable object, because mutable implicitly converts to `const`. But when that method is a constructor, it's not allowed.

Why? Because constructors have a special "superpower" that no other functions in D have: they're allowed to write to `const` and `immutable` variables. This is documented in the spec under ["Field initialization inside a constructor"][1].

If you could call a `const` constructor on a mutable object, it would be possible to use that constructor to violate the type system by storing a pointer to `immutable` data in a mutable field:

```d
struct S2
{
    int* p;
    this(const int* p) const
    {
        // Ok - counts as initialization
        this.p = p;
    }
}

immutable int answer = 42;

void main()
{
    S2 s2;
    // If this were allowed to compile...
    s2.__ctor(&answer);
    // ...then this could happen
    *s2.p = 12345;
}
```

[1]: https://dlang.org/spec/struct.html#field-init

Reply via email to