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`.