What's the point of static arrays ?

Stanislav Blinov stanislav.blinov at gmail.com
Fri Jul 10 11:13:51 UTC 2020


On Friday, 10 July 2020 at 10:13:23 UTC, wjoe wrote:
> So many awesome answers, thank you very much everyone!
>
> Less overhead,
> Using/needing it to interface with something else, and
> Efficiency are very good points.
>
> However stack memory needs to be allocated at program start. I 
> don't see a huge benefit in allocation speed vs. heap 
> pre-allocation, or is there?

Stack is allocated by the OS for the process when it's started. 
Reserving space for stack variables, including arrays, is 
effectively free, since the compiler assigns offsets statically 
at compile time.

> I mean 1 allocation vs 2 isn't going to noticeably improve 
> overall performance.

A GC allocation is way more complex than a mere bump-the-pointer. 
If your program is trivial enough you may actually find that one 
extra GC allocation is significant in its runtime. Of course, if 
you only ever allocate once and your program runs for ages, you 
won't really notice that allocation.

>>     a[]
> What happens here exactly ?

This:

int[10] a;
int[] slice = a[];
assert(slice.ptr == &a[0]);
assert(slice.length == 10);
assert(a.sizeof == 10 * int.sizeof);    // 40
assert(slice.sizeof == (int[]).sizeof); // 16 on 64 bit

> I read the chapters in Ali's book (thank you very much for such 
> a great book, Ali) on arrays and slicing prior to asking this 
> question and I came to the following conclusion:
>
> Because a static array is pre-allocated on the stack,
> doesn't have a pointer/length pair,
> is addressed via the stack pointer, and
> due to the fact that a slice is a pointer/length pair
>   and because a slice is technically the meta data of a dynamic 
> array, a view into (part) of a dynamic array,

No. A slice is just a pointer/length pair - a contiguous view 
into *some* memory, regardless of where that memory came from:

void takeASlice(scope void[] data) // can take any slice since 
any slice converts to void[]
{
     import std.stdio;
     writefln("%x %d", data.ptr, data.length);
}

int[10] a;
takeASlice(a); // a[]
takeASlice(a[1 .. $-1]); // a[1 .. 9]

struct S
{
     float x, y, z;
     float dx, dy, dz;
}

S s;
takeASlice((&s)[0 .. 1]); // Slicing a pointer, not @safe but can 
be done.
takeASlice(new int[10]); // Array, GC allocation
takeASlice([1, 2, 3, 4]); // Array literal, may or may not be 
GC-allocated

`takeASlice` has no knowledge of where the memory came from.

Dynamic arrays only ever come into the picture if you try to 
manipulate the slice itself: resize it, append to it, etc.

> that it's not possible to slice a static array because the 
> slice would technically be akin to a dynamic array and hence be 
> incompatible.

Incompatible to what?

int[10] a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
a[0 .. 2] = a[2 .. 4];
assert(a[0] == 3);
assert(a[1] == 4);
int[10] b = void;
b[] = a[];
assert(b == [3, 4, 3, 4, 5, 6, 7, 8, 9, 10]);

> struct SuperSpecializedArray(T, size_t S) if (S > 0)
> {
>    T[S] elements;
>
>    struct SuperSpecializedArrayRange
>    {
>       typeof(elements) e;
>
>       this(SuperSpecializedArray a)
>       {
>          e = a.elements; // copies
>       }
>
>       // ...
>    }
> }
>
> Upon creation of a SuperSpecializedArrayRange, the array is 
> copied, but more importantly, data which may not ever be needed 
> is copied and that's supposed to be a big selling point for 
> ranges - only ever touching the data when it's requested - am I 
> wrong ?

Ranges need not be lazy. They can be, and most of them should be 
indeed, but they need not be. And, as you yourself point out, in 
your case `e` can just be a slice, and your range becomes lazy.


More information about the Digitalmars-d-learn mailing list