Dynamic array ot not

Ali Çehreli acehreli at yahoo.com
Sun Jan 16 11:43:40 UTC 2022


On 1/16/22 01:43, forkit wrote:
 > On Sunday, 16 January 2022 at 04:58:21 UTC, Ali Çehreli wrote:
 >>
 >> I have a problem with calling type[] a dynamic array because it is a
 >> slice, which may be providing access to the elements of a dynamic array.
 >>
 >
 > Yes. A more useful way of describing [] would be to say:
 >
 > "[] represents a dynamic array except when it represents a slice

I still don't agree with that. :) To me, [] is always a slice. (Again, 
some other members of the community like to name it a "dynamic array" 
instead "slice".)

 > - in
 > which case it is merely shorthand for a slice that is referencing data
 > stored somewhere else."

A slice always references data stored somewhere else.

 > Something that still confuese me in my example then:
 >   mArr[] is actually a slice, and not a dynamic array. That is, my slice
 > is referencing data located somewhere else. But where exactly is that
 > other data located?

Can be anywhere:

a) On the stack (as in my earlier example of int[2] static array)

b) In "dynamic memory" (i.e. "GC memory")

c) In malloc'ed memory (e.g. allocated by a C function)

d) etc.

 > It seems to me, I have a slice of data that doesn't
 > actually exist once I have that slice.

It would be a bug if the slice references non-existing data. Slice 
consist of two things:

1) A pointer to the beginning of data

2) The number of elements that are being referenced at that location

Going back to the three example of data I listed above:

a) The data is on the stack and will die when the scope is exited. It 
would be a bug to refer to that data longer that its lifetime:

int[] foo() {
   int[2] dataOnTheStack;
   return dataOnTheStack[];
}

Luckily, dmd catches that bug in that case:

Error: returning `dataOnTheStack[]` escapes a reference to local 
variable `dataOnTheStack`

b) This is the most common case: The data is in dynamic memory. This is 
owned and managed by druntime. druntime includes the GC, which 
occasionally performs a cleanup to free unused memory.

int[] bar(int[] input) {
   int[] output = input ~ 42;
   return output;
}

void main() {
   bar([ 1, 2 ]);
}

The first line of bar() appends 42 to an existing slice. That operation 
causes druntime to allocate new memory, copy the existing elements of 
'input' there and also write 42 at the end of those elements. After 
bar's first line, this is a picture of 'input' and 'output' during bar():

input.ptr --> [ (some data) ]

output.ptr --> [ (copy of 'input's data in dynamic memory) 42 ]

Note that while 'input's elements may be e.g. on the stack, 'output's 
elements are definitely in dynamic memory. The data that is in dynamic 
memory will be alive as long as there is at least one reference to it.

c) The data may be allocated by malloc:

import std.stdio;
import core.stdc.stdlib;

void main() {
   enum count = 7;

   // Allocate some memory
   void* rawData = malloc(int.sizeof * count);

   // Access that data as int[]
   int[] slice = (cast(int*)rawData)[0..count];

   // Yet another slice of half of those
   int[] half = slice[0..$/2];

   // Free the memory
   free(rawData);

   // Ouch! Accessing dead data
   writeln(slice);
   writeln(half);
}

So, in all three examples it is the same D feature, a slice, that 
references data but the data is managed in different ways.

Ali



More information about the Digitalmars-d-learn mailing list