Questions: 1. Why not enable mutations to the substring? 2. Can we generalize this to a slice for any container? Is the intention behind this design to generalize to other containers, such as seq?
As for strings having to end at '0' not enable slicing with O(1). I would argue that conversion to/from a C string is less common of an operation than slicing, i.e. just copy to a new string if you need convert to a C string. On the ABI design: where is the capacity stored (is there a capacity?). An alternative design is to use a single pointer (`char*`) to declare the string. You can then over-allocate memory for additional fields w.r.t metadata. The pointer you return will have to be offset to start at the start of the buffer string. In stb headers they use this trick for stb_array, i.e. you can do the following float* myarr = NULL; stb_arr_push(my_array, 0.0f); stb_arr_push(my_array, 1.0f); stb_arr_push(my_array, 2.0f); for (int i = 0; i < stb_arr_len(my_array); ++i) { printf("%f\n", my_array[i]); // NOTE: you can index like a regular array in C } Run For this case, you would store `(len, capacity, is_slice)` (is_slice in len if preferred). Of course, since this is at the language level, this is probably not necessary since we have operator overloading. One other consideration: if generalizing to slices, you could store the stride as well - I imagine this would be a handy feature.