On Monday, 20 October 2025 at 10:38:23 UTC, Serg Gini wrote:
>On Monday, 20 October 2025 at 09:50:35 UTC, Brother Bill wrote:
>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?
But I'm not sure about slice capacity. it doesn't make any sense for me when it is non-zero
https://dlang.org/spec/arrays.html#capacity-reserve
I've played with the code and think I understand D's rules for sharing or breaking sharing.
- Extending the base dynamic array up to (capacity – length) will continue to maintain sharing with derived slices.
- Extending the base dynamic array beyond (capacity – length) will make a copy of the base dynamic array and break sharing.
- Extending a derived slice will make a copy of the derived slice and break sharing.
source/app.d
import std.stdio;
void main()
{
extendingBaseArraySmallMaintainsSharing();
extendingBaseArrayLargeDoesNotMaintainSharing();
extendingSliceDoesNotMaintainSharing();
}
void extendingBaseArraySmallMaintainsSharing()
{
writeln("=== extendingBaseArraySmallMaintainsSharing ===");
int[] slice = [1, 3, 5, 7, 9, 11, 13, 15];
int[] tailSlice = slice[$ / 2 .. $];
writeln("slice: ", slice, " length: ", slice.length, " capacity: ", slice.capacity, ", &slice[4]: ", &slice[4]);
writeln("tailSlice: ", tailSlice, " length: ", tailSlice.length, " capacity: ", tailSlice.capacity, " &tailSlice[0]: ", &tailSlice[0]);
slice.length += (slice.capacity - slice.length); // extend to capacity
writeln("slice after: ", slice, " length: ", slice.length, " capacity: ", slice.capacity, ", &slice[4]: ", &slice[4]);
writeln("tailSlice after incrementing length by 1: ", tailSlice, " length: ", tailSlice.length, " capacity: ", tailSlice.capacity, " &tailSlice[0]: ", &tailSlice[0]);
tailSlice[0] = 888;
writeln("After tail slice length increase and changing tailSlice[0] to 888. ", " length: ", tailSlice.length, " capacity: ", tailSlice.capacity);
writeln("tailSlice: ", tailSlice);
writeln("slice : ", slice);
writeln;
}
void extendingBaseArrayLargeDoesNotMaintainSharing()
{
writeln("=== extendingBaseArrayLargeDoesNotMaintainSharing ===");
int[] slice = [1, 3, 5, 7, 9, 11, 13, 15];
int[] tailSlice = slice[$ / 2 .. $];
writeln("slice: ", slice, " length: ", slice.length, " capacity: ", slice.capacity, ", &slice[4]: ", &slice[4]);
writeln("tailSlice: ", tailSlice, " length: ", tailSlice.length, " capacity: ", tailSlice.capacity, " &tailSlice[0]: ", &tailSlice[0]);
slice.length += (1 + slice.capacity - slice.length); // extend just beyond capacity
writeln("slice after: ", slice, " length: ", slice.length, " capacity: ", slice.capacity, ", &slice[4]: ", &slice[4]);
writeln("tailSlice after incrementing length by 1: ", tailSlice, " length: ", tailSlice.length, " capacity: ", tailSlice.capacity, " &tailSlice[0]: ", &tailSlice[0]);
tailSlice[0] = 888;
writeln("After tail slice length increase and changing tailSlice[0] to 888. ", " length: ", tailSlice.length, " capacity: ", tailSlice.capacity);
writeln("tailSlice: ", tailSlice);
writeln("slice : ", slice);
writeln;
}
void extendingSliceDoesNotMaintainSharing()
{
writeln("=== extendingSliceDoesNotMaintainSharing ===");
int[] slice = [1, 3, 5, 7, 9, 11, 13, 15];
int[] tailSlice = slice[$ / 2 .. $];
writeln("slice: ", slice, " length: ", slice.length, " capacity: ", slice.capacity, ", &slice[4]: ", &slice[4]);
writeln("tailSlice: ", tailSlice, " length: ", tailSlice.length, " capacity: ", tailSlice.capacity, " &tailSlice[0]: ", &tailSlice[0]);
tailSlice.length += (tailSlice.capacity - tailSlice.length); // extend to capacity
writeln("slice after: ", slice, " length: ", slice.length, " capacity: ", slice.capacity, ", &slice[4]: ", &slice[4]);
writeln("tailSlice after incrementing length by 1: ", tailSlice, " length: ", tailSlice.length, " capacity: ", tailSlice.capacity, " &tailSlice[0]: ", &tailSlice[0]);
tailSlice[0] = 888;
writeln("After tail slice length increase and changing tailSlice[0] to 888. ", " length: ", tailSlice.length, " capacity: ", tailSlice.capacity);
writeln("tailSlice: ", tailSlice);
writeln("slice : ", slice);
writeln;
}
Console output:
=== extendingBaseArraySmallMaintainsSharing ===
slice: [1, 3, 5, 7, 9, 11, 13, 15] length: 8 capacity: 11, &slice[4]: 237935F1010
tailSlice: [9, 11, 13, 15] length: 4 capacity: 7 &tailSlice[0]: 237935F1010
slice after: [1, 3, 5, 7, 9, 11, 13, 15, 0, 0, 0] length: 11 capacity: 11, &slice[4]: 237935F1010
tailSlice after incrementing length by 1: [9, 11, 13, 15] length: 4 capacity: 0 &tailSlice[0]: 237935F1010
After tail slice length increase and changing tailSlice[0] to 888. length: 4 capacity: 0
tailSlice: [888, 11, 13, 15]
slice : [1, 3, 5, 7, 888, 11, 13, 15, 0, 0, 0]
=== extendingBaseArrayLargeDoesNotMaintainSharing ===
slice: [1, 3, 5, 7, 9, 11, 13, 15] length: 8 capacity: 11, &slice[4]: 237935F1040
tailSlice: [9, 11, 13, 15] length: 4 capacity: 7 &tailSlice[0]: 237935F1040
slice after: [1, 3, 5, 7, 9, 11, 13, 15, 0, 0, 0, 0] length: 12 capacity: 15, &slice[4]: 237935F2010
tailSlice after incrementing length by 1: [9, 11, 13, 15] length: 4 capacity: 7 &tailSlice[0]: 237935F1040
After tail slice length increase and changing tailSlice[0] to 888. length: 4 capacity: 7
tailSlice: [888, 11, 13, 15]
slice : [1, 3, 5, 7, 9, 11, 13, 15, 0, 0, 0, 0]
=== extendingSliceDoesNotMaintainSharing ===
slice: [1, 3, 5, 7, 9, 11, 13, 15] length: 8 capacity: 11, &slice[4]: 237935F1070
tailSlice: [9, 11, 13, 15] length: 4 capacity: 7 &tailSlice[0]: 237935F1070
slice after: [1, 3, 5, 7, 9, 11, 13, 15] length: 8 capacity: 11, &slice[4]: 237935F1070
tailSlice after incrementing length by 1: [9, 11, 13, 15, 0, 0, 0] length: 7 capacity: 7 &tailSlice[0]: 237935F0020
After tail slice length increase and changing tailSlice[0] to 888. length: 7 capacity: 7
tailSlice: [888, 11, 13, 15, 0, 0, 0]
slice : [1, 3, 5, 7, 9, 11, 13, 15]