On Monday, 20 October 2025 at 09:03:28 UTC, Kapendev wrote:
On Sunday, 19 October 2025 at 20:44:39 UTC, Brother Bill wrote:
But incrementing the length of tailSlice by 1 breaks sharing.
This is unexpected.
This is not really unexpected.
It's easier to think about it if you treat slices as structs
with 2 members, a pointer and a length. The important member is
the pointer.
```d
int[] slice = [1, 3, 5, 7, 9, 11, 13, 15];
```
Here you create a "struct" with a pointer provided by the GC.
The GC keeps track of the amount of items this pointer is
pointing to. It's not really important how it is tracked. The
safest assumption a user can make in any language is that the
pointer owns the memory.
```d
int[] tailSlice = slice[$ / 2 .. $];
```
Here you create a new "struct" whose pointer differs from
`slice`. The layout of the data now looks like this:
```
`slice` pointer : ...*########...
`tailSlice` pointer: .......*####...
```
The pointer of `tailSlice` doesn't own the memory. It's a view
into the memory owned by the `slice` pointer.
```
tailSlice.length += 1;
```
You are now changing the length of struct `tailSlice`. There is
really no good way to know if the pointer of `tailSlice` is an
item of `slice` or if the last item of `tailSlice` is the last
item of `slice`, so the GC will copy the data to a new memory
block and append one new item.
That's kinda it. If you try to append or remove items in cases
like this, you will probably get a new pointer. If you want to
use a slice as a dynamic array, it's a good idea to pass it by
`ref` or pointer. Hope this helps.
So all that guidance of tail appending using 'length' and
'capacity' is obsolete.
That is, if the capacity > length, then one can safely extend the
tail by (capacity - length) elements.
The new advice is to just not append to slices either for the
base array or any tail slice array. Otherwise, breakage or
termination of slice sharing may result.
Do I have that correct?