| |
| Posted by Ali Çehreli in reply to forkit | PermalinkReply |
|
Ali Çehreli
Posted in reply to forkit
| 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
|