c3c icon indicating copy to clipboard operation
c3c copied to clipboard

Concatenating slices/subarrays?

Open Andersama opened this issue 3 years ago • 1 comments

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}

Andersama avatar Aug 13 '22 16:08 Andersama

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.

lerno avatar Aug 13 '22 17:08 lerno

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]};

Andersama avatar Aug 17 '22 04:08 Andersama

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?

lerno avatar Aug 17 '22 07:08 lerno

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.

Andersama avatar Aug 18 '22 04:08 Andersama

array::concat and array::tconcat have been added BTW.

lerno avatar Aug 18 '22 14:08 lerno