February 08, 2023
module main;

void changeContent(Arr)(Arr arr)
{
	arr[] = 10;
}

void changeSizeAndContent(Arr)(Arr arr)
{
	enum RESIZE = 10;
	arr.length = RESIZE;
	int c = RESIZE;
	foreach (ref e; arr)
	{
		e = c--;
	}
}

void main()
{
	import std.container.array;
	import std.stdio;

	auto builtinArr = [1, 2, 3, 4];
	changeContent(builtinArr);
	writeln(builtinArr); // prints [10, 10, 10, 10]
	changeSizeAndContent(builtinArr);
	writeln(builtinArr); // prints [10, 10, 10, 10]

	auto stdArr = Array!int([1, 2, 3, 4]);
	changeContent(stdArr);
	writeln(stdArr); // prints Array!int(Payload(4, [10, 10, 10, 10]))
	changeSizeAndContent(stdArr);
	writeln(stdArr); // prints Array!int(Payload(10, [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]))
}

For builtin array, when reallocation happens, we basically get a new array. Any changes to it do not affect the original.
*On the other hand, when reallocation doesn't happen, the original can be modified.

For std Array, the payload is always shared, it works as if we are passing "ref T[]" all the time, except when it's reassigned with: arr = Array!int([]) -- probably the reason why no opAssign(R)(R range) is implemented for std Array, so that the coder understands new payload is being created?

I assume it's possible to implement std Array to work more like the builtin - new payload is created if it grows over capacity, which will make "ref" actually useful here. Perhaps also have Array.opSlice return an Array, instead of a "view" that can't be augmented.