On Saturday, 3 July 2021 at 16:06:33 UTC, Alexandru Ermicioi wrote:
3. An edge case. Ex: You need to mutate some data and then assume it is immutable in a constructor.

Can you give a valid example where that is necessary? The main examples that I can think of either can be `@safe` with the right API, or are motivated by a desire to avoid the GC and/or druntime, thus falling under (1).

4. Functionality that doesn't account for @safe/immutable or any other features when it can in standard library.

True, although it's just another example of my point (2). The standard library and druntime are dependencies, too...

Take for example array.dup, there is no inout alternative for it, and you're pretty much stuck with trusted code, when you'd like to dup an array that is inout.

`inout` is usually just a convenient way to use one implementation to handle mutable, `const` and `immutable` cases. In those rare cases where `inout` itself won't work, it is almost always possible to accomplish the same thing using `template this` or separate overloads:

```D
import std.traits : Unqual, CopyConstness;

struct A {
    int*[] arr;
    this(this This, Arr)(Arr arr) scope pure @safe nothrow
if(is(Arr : E[], E) && is(E : CopyConstness!(This, Unqual!E)))
    {
        this.arr = arr.dup;
    }
}

void main()
{
    A ma = new int*[5];
    const(A) ca = new const(int*[3]);
    const(A) ia = new immutable(int*[4]);
}
```

Again, it's certainly not obvious how to do this, or why it is necessary, but it is *possible*.

The one exception here is when the array is already typed `inout` before it is passed to the constructor. But, that's an example of (2) since this logic applies transitively throughout the call stack: if you need to call `dup` anywhere, don't erase the constness with `inout`.

Reply via email to