Confusing behaviour of array member assignment when calling local function
Steven Schveighoffer
schveiguy at gmail.com
Sun Jan 5 02:33:51 UTC 2025
On Saturday, 4 January 2025 at 23:11:58 UTC, Sahan Fernando wrote:
> Hello all,
>
> I've encountered an unexpected behaviour in the D language,
> where assigning the result of a function that grows an array to
> a value in that array ends up modifying the old memory used
> previously by that array. This seems counterintuitive to me in
> the sense that it feels logical that the lvalue to be assigned
> to should be evaluated after the function has been evaluated,
> but this behaviour implies that part of the lvalue was
> evaluated before the function.
>
> A minimal reproduction of the issue I'm describing is attached
> below:
>
> ```d
> import std.exception;
>
> void main() {
> auto v = new ulong[1];
> size_t appendAndGetLength() {
> v ~= [10, 10, 10, 10, 10, 10, 10, 10, 10, 10];
> return v.length;
> }
> v[0] = appendAndGetLength();
> // Works if we do the following instead
> // auto v0 = appendAndGetLength();
> // v[0] = v0;
> enforce(v[0] == v.length);
> }
> ```
So what is happening here is the left side of the assignment is
being evaluated first. Then the right side. The right side alters
`v` by appending (it must reallocate to accomodate the new
values), and therefore you assign to the *old* `v`.
This can be demonstrated:
```d
void main() {
auto v = new ulong[1];
auto oldv = v;
size_t appendAndGetLength() {
v ~= [10, 10, 10, 10, 10, 10, 10, 10, 10, 10];
return v.length;
}
v[0] = appendAndGetLength();
enforce(oldv.ptr !is v.ptr);
enforce(oldv[0] == v.length);
}
```
A dynamic array (or slice) is simply a pointer and a length. It
is *not* a reference into an array object (many other languages
are like this, D is not).
You can read more about how arrays work here:
https://dlang.org/articles/d-array-article.html
-Steve
More information about the Digitalmars-d
mailing list