On Tuesday, 29 November 2022 at 18:59:46 UTC, DLearner wrote:
To me, it appears that there are really two (_entirely
separate_) concepts:
A. Supporting the useful concept of variable length (but
otherwise entirely conventional) arrays;
B. Supporting a language feature that acts as a window to an
array, through which that array can be manipulated.
And currently these two concepts are combined.
Suggestion: it would be clearer if the two concepts were
separated:
1. Convert 'int[] VarArr;' so it produces a straightforward
_value-type_ variable array, called 'VarArr';
2. Implement a new concept 'int slice Window;' to produce an
object of type 'int slice', called 'Window'.
'Window' is a 'slice' into an int array, not an array itself
or even a variable.
Opinions?
I have implemented that in
[styx](https://gitlab.com/styx-lang/styx).
1. You have the type for dynamic arrays, called TypeRcArray,
syntax is `Type[+]`
2. You have the type for slices (what you describe as a window),
syntax is `Type[]`
but it is mostly obtained using expressions, e.g `mySlice =
myRcArray[lo .. hi]` or
`myStaticArray[lo .. hi]` or `myPointer[lo .. hi]`.
This sounded like a good idea but it [has appeared very
quickly](https://styx-lang.gitlab.io/styx/type.html#noteonlifetime) that slices are not so useful, especially when management is based on reference counting because then slices requires a form of management too. Here is why:
Main caracteristics of a slice are
- they cannot modify the identity of their sources. The identity
of the source is what makes the integrity of a dynamic array,
what makes their references countable. So it is the content
pointer and the length. In consequence you cannot change the
length of the source, you can only reduce the view. You can
change the elements in the view.
- the length and the pointer are cached as a value on the stack
while for a dynamic array this is stored before that data, on the
heap.
Problems start happening when you escape a slice
```d
struct S
{
var s32[] memberSlice;
}
function f(var S s): auto
{
var s32[+] a = (new s32[+])(2);
// problem 1 : `s` lifetime > `a` lifetime
s = (a[]).tupleof; // note: tuples are used in pace of
struct literals
// problem 2
return a[1 .. $]; // a is automatically decref'd on return
// so the caller pulls a dead heap block.
}
```
Essentially slices are only useful to be consumed locally,
typically
```d
while mySlice.length do
{
slice = slice[1..$];
}
```
And that's it. So at first glance slices are some cool,
simplified, functionally stripped down arrays but they introduce
new problems, at least when management of dynamic arrays is based
on reference counting. Those new problems can only be solved
using lifetime analysis (so a compile-time check... still better
than runtime ref counting however).