> At the moment I don't have further ideas on this.
Sorry, another solution I've used to solve that problem is to split the array
arr of structs in two parallel arrays, one with just the mutable fields and one
with just the immutable ones. But this increases the program complexity, makes
the program a bit more bug-prone, and in your program all your contracts have
to assert the two parallel arrays have the same length:
struct FooA {
int x;
// other mutable fields here
}
struct FooB {
bool b;
// other immutable fields here
}
FooA[] generateA() pure nothrow {
auto arra = new FooA[10];
foreach (i; 0 .. 10)
arra[i].x = i;
return arra;
}
immutable(FooB[]) generateB() pure nothrow {
auto arrb = new FooB[10];
arrb[3].b = true;
return arrb;
}
void main() {
auto a1 = generateA();
auto a2 = generateB();
}
--------------------
In the end what's the difference between code like this:
struct Foo {
immutable bool b;
}
Foo[] generate() pure nothrow {
Foo[] arr;
foreach (i; 0 .. 10) {
if (i == 3)
arr ~= Foo(true);
else
arr ~= Foo(false);
}
return arr;
}
void main() {
auto a = generate();
}
And code like this?
struct Foo {
immutable bool b;
}
Foo[] generate() pure nothrow {
auto arr = new Foo[10];
arr[3].b = true;
return arr;
}
void main() {
auto a = generate();
}
In the first case, by code construction the compiler has guarantees that you
will not write each struct more than one time (because appending never appends
two times on the same array slot), and you will not read array slots that are
not yet initialized (because the array items yet to be appended can't be read
in any way, they don't exist yet). For the compiler it's hard to understand
that the second program has the same qualities (well, arr[3] gets initialized
twice, but structs don't allow argument-less constructors, so I think the
constructor is like a pure function, so what matters is just the latest value
assigned to arr[3]).
Bye,
bearophile