[Issue 5207] Immutability is broken in constructors
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Mon Mar 22 16:43:18 UTC 2021
https://issues.dlang.org/show_bug.cgi?id=5207
--- Comment #7 from hsteoh at quickfur.ath.cx ---
Here's an example of a problematic case:
----------
import std;
struct S {
int x;
}
immutable S s;
immutable(S)* ptr;
void fun(immutable(S)* p) {
ptr = p;
}
shared static this() {
fun(&s);
writeln(ptr.x); // prints 0
s.x = 1;
writeln(ptr.x); // prints 1
s.x = 2;
writeln(ptr.x); // prints 2: immutability broken
}
----------
Since `ptr` points to an immutable value, one expects that `ptr.x` should not
change. Correspondingly, an optimizing compiler reserves the right to elide
subsequent loads, thus causing different output.
And indeed, if the above code is refactored as follows:
----------
import std;
struct S {
int x;
}
immutable S s;
immutable S* ptr;
shared static this() {
ptr = &s;
writeln(ptr.x); // prints 0
s.x = 1;
writeln(ptr.x); // prints 1
s.x = 2;
writeln(ptr.x); // prints 2: immutability broken
}
void main() {
writeln(ptr.x);
}
----------
Then the output becomes:
----------
0
0
0
2
----------
Clearly, the compiler has optimized away the loads of `ptr.x` because of the
immutability of `ptr`, but actually that was a wrong assumption because the
supposedly immutable value *did* change, as proven by what main() sees
afterwards. This causes inconsistent behaviour in either case, the root cause
of which is an immutable value being assignable multiple times inside a ctor.
Immutable values should not be readable before initialization (the first
writeln should be illegal), and should only be initializable once.
--
More information about the Digitalmars-d-bugs
mailing list