Concatenating slices/subarrays?
A few languages which natively support slices also support concatenation, although the concatenation operator's varies.
EG:
uint[] some_array = {1,2,3};
uint[] another_array = {4,5,6};
//might consider using std::array::list<uint> as the output of the operation
uint[] result_array = some_array[0..1] + another_array[1..2];
//result_array = {1,2,5,6}
I've seen this in Hare and D. D relies on a GC to bring this functionality, I'm unsure what Hare does, but essentially it is required to build some sort of dynamic array into the runtime.
Your example illustrates the problem with doing it: who would manage the memory of result_array? From where is it allocated? Howe is the memory owned?
As C3 uses a subarray, these are plain array views. So if we look at the related string_view concept, no one really suggests that string_view1 + string_view2 should result in a new string_view of a hidden string.
While the uint[] some_array = { 1, 2, 3 } it's an array view of a hidden array, here but this array is placed on the stack so no memory management or ownership needs to be tracked.
Let's say we would have this functionality, how would it work? I can't really see how it does without a GC.
I suppose the problem here is that the semantics of [] is that of a non-owning view to something else, without a built in version of a "owning" view, concatenation doesn't make sense. std::array::list would work as that "owning" view, but it'll add allocation to the mix where it doesn't necessarily need to.
The other weird choice is for the resulting slice to be a slice of pointers*, eg: a pointer to 1,2,5 and 6 and for the concatenation operator to be shorthand for a constructor like:
= {&some_array[0], &some_array[1], &another_array[1], &another_array[2]};
I think you touch on another issue here:
but it'll add allocation to the mix where it doesn't necessarily need to.
It is hard to have conditional allocation without having automatic memory management, because while heap alloc needs deallocation, stack doesn't creating sufficient differences in semantics and performance that it's hard to unify them. You can also see in Swift how performance can drastically change due to subtle changes as the analysis becomes different allowing something be put on stack <-> having to be moved to the the heap.
A safe alternative would be to use the temporary allocator, so something like (*note this interface doesn't exist yet):
// Create a list using the temporary allocator
uint[] concat_list = array::tconcat(some_array, another_array);
What do you think?
I think that would work pretty well, there's a good chance the reason behind the concatenation is like your scratchbuffer in the compiler, it's likely temporary or short lived to do a group of operations.
array::concat and array::tconcat have been added BTW.