Thread overview
deep copy or shallow copy?
Dec 08, 2011
RenatoL
Dec 08, 2011
Timon Gehr
Dec 09, 2011
Ali Çehreli
Dec 09, 2011
Timon Gehr
Dec 09, 2011
Jonathan M Davis
Dec 09, 2011
Ali Çehreli
Dec 09, 2011
Jonathan M Davis
Dec 09, 2011
Ali Çehreli
December 08, 2011
snippet 1)
	auto arr1 = [1,2,3];
	auto arr2 = arr1;
	arr1[1] = 22;
	arr2[2] = 33;
	foreach (i; 0..arr1.length) write(arr1[i], " ");
	writeln();
	foreach (i; 0..arr2.length) write(arr2[i], " ");

output:
1 22 33
1 22 33
OK

snippet 2)

	int[3] arr1 = [1,2,3];
	int[3] arr2 = arr1;
	arr1[1] = 22;
	arr2[2] = 33;
	foreach (i; 0..arr1.length) write(arr1[i], " ");
	writeln();
	foreach (i; 0..arr2.length) write(arr2[i], " ");

output:

1 22 3
1 2 33

that's unclear to me... i "agree" with the behaviour of the dynamic array... but if we have a static array we have a deep copy?
December 08, 2011
On 12/08/2011 09:50 PM, RenatoL wrote:
> snippet 1)
> 	auto arr1 = [1,2,3];
> 	auto arr2 = arr1;
> 	arr1[1] = 22;
> 	arr2[2] = 33;
> 	foreach (i; 0..arr1.length) write(arr1[i], " ");
> 	writeln();
> 	foreach (i; 0..arr2.length) write(arr2[i], " ");
>
> output:
> 1 22 33
> 1 22 33
> OK
>
> snippet 2)
>
> 	int[3] arr1 = [1,2,3];
> 	int[3] arr2 = arr1;
> 	arr1[1] = 22;
> 	arr2[2] = 33;
> 	foreach (i; 0..arr1.length) write(arr1[i], " ");
> 	writeln();
> 	foreach (i; 0..arr2.length) write(arr2[i], " ");
>
> output:
>
> 1 22 3
> 1 2 33
>
> that's unclear to me... i "agree" with the behaviour of the
> dynamic array... but if we have a static array we have a deep copy?

Both copies are 'shallow', but static arrays are value types.
December 09, 2011
On 12/08/2011 12:52 PM, Timon Gehr wrote:
> On 12/08/2011 09:50 PM, RenatoL wrote:
>> snippet 1)
>> auto arr1 = [1,2,3];
>> auto arr2 = arr1;
>> arr1[1] = 22;
>> arr2[2] = 33;
>> foreach (i; 0..arr1.length) write(arr1[i], " ");
>> writeln();
>> foreach (i; 0..arr2.length) write(arr2[i], " ");
>>
>> output:
>> 1 22 33
>> 1 22 33
>> OK
>>
>> snippet 2)
>>
>> int[3] arr1 = [1,2,3];
>> int[3] arr2 = arr1;
>> arr1[1] = 22;
>> arr2[2] = 33;
>> foreach (i; 0..arr1.length) write(arr1[i], " ");
>> writeln();
>> foreach (i; 0..arr2.length) write(arr2[i], " ");
>>
>> output:
>>
>> 1 22 3
>> 1 2 33
>>
>> that's unclear to me... i "agree" with the behaviour of the
>> dynamic array... but if we have a static array we have a deep copy?
>
> Both copies are 'shallow', but static arrays are value types.

'shallow' would be misleading for a fixed-length (static) array because there is nothing else but the elements for fixed-length arrays:

void main()
{
    int[3] a;
    assert(cast(void*)&a == cast(void*)&a[0]);
}

Fixed-length array storage is similar to C arrays. These are different:

- they don't decay to a 'pointer to first element' when passed to functions (being value types, the whole array is copied)

- a.length is a convenience, equivalent to a.sizeof / a[0].sizeof

So it is impossible to do anything shallow with them unless we explicitly maintain a pointer to a fixed-length array ourselves.

Ali

December 09, 2011
On 12/09/2011 09:32 PM, Ali Çehreli wrote:
> On 12/08/2011 12:52 PM, Timon Gehr wrote:
>  > On 12/08/2011 09:50 PM, RenatoL wrote:
>  >> snippet 1)
>  >> auto arr1 = [1,2,3];
>  >> auto arr2 = arr1;
>  >> arr1[1] = 22;
>  >> arr2[2] = 33;
>  >> foreach (i; 0..arr1.length) write(arr1[i], " ");
>  >> writeln();
>  >> foreach (i; 0..arr2.length) write(arr2[i], " ");
>  >>
>  >> output:
>  >> 1 22 33
>  >> 1 22 33
>  >> OK
>  >>
>  >> snippet 2)
>  >>
>  >> int[3] arr1 = [1,2,3];
>  >> int[3] arr2 = arr1;
>  >> arr1[1] = 22;
>  >> arr2[2] = 33;
>  >> foreach (i; 0..arr1.length) write(arr1[i], " ");
>  >> writeln();
>  >> foreach (i; 0..arr2.length) write(arr2[i], " ");
>  >>
>  >> output:
>  >>
>  >> 1 22 3
>  >> 1 2 33
>  >>
>  >> that's unclear to me... i "agree" with the behaviour of the
>  >> dynamic array... but if we have a static array we have a deep copy?
>  >
>  > Both copies are 'shallow', but static arrays are value types.
>
> 'shallow' would be misleading for a fixed-length (static) array because
> there is nothing else but the elements for fixed-length arrays:

It is not misleading since the array might be an array of references. (and if it does not contain references, shallow and deep are the same thing anyway)

>
> void main()
> {
> int[3] a;
> assert(cast(void*)&a == cast(void*)&a[0]);
> }
>
> Fixed-length array storage is similar to C arrays. These are different:
>
> - they don't decay to a 'pointer to first element' when passed to
> functions (being value types, the whole array is copied)
>
> - a.length is a convenience, equivalent to a.sizeof / a[0].sizeof
>
> So it is impossible to do anything shallow with them unless we
> explicitly maintain a pointer to a fixed-length array ourselves.
>
> Ali
>

You can always slice it, of course

int[3] a;
int[] b = a[]; // b now is a dynamic array that aliases a's contents


December 09, 2011
On Friday, December 09, 2011 22:09:15 Timon Gehr wrote:
> On 12/09/2011 09:32 PM, Ali Çehreli wrote:
> > So it is impossible to do anything shallow with them unless we explicitly maintain a pointer to a fixed-length array ourselves.
> > 
> > Ali
> 
> You can always slice it, of course
> 
> int[3] a;
> int[] b = a[]; // b now is a dynamic array that aliases a's contents

Though, of course, you have to be careful with that, since the static array then owns the memory for that dynamic array, and if the static array goes out of scope before the dynamic array does, then the dynamic array points to garbage and will result in bugs.

- Jonathan M Davis
December 09, 2011
On 12/09/2011 01:18 PM, Jonathan M Davis wrote:
> On Friday, December 09, 2011 22:09:15 Timon Gehr wrote:
>> On 12/09/2011 09:32 PM, Ali Çehreli wrote:
>>> So it is impossible to do anything shallow with them unless we
>>> explicitly maintain a pointer to a fixed-length array ourselves.
>>>
>>> Ali
>>
>> You can always slice it, of course
>>
>> int[3] a;
>> int[] b = a[]; // b now is a dynamic array that aliases a's contents
>
> Though, of course, you have to be careful with that, since the static array
> then owns the memory for that dynamic array, and if the static array goes out
> of scope before the dynamic array does, then the dynamic array points to
> garbage and will result in bugs.
>
> - Jonathan M Davis

That's news to me. Don't the static array elements belong to the runtime, managed by the garbage collector, and will be kept alive as long as the slice is alive?

Ali

December 09, 2011
On Friday, December 09, 2011 14:33:38 Ali Çehreli wrote:
> On 12/09/2011 01:18 PM, Jonathan M Davis wrote:
> > On Friday, December 09, 2011 22:09:15 Timon Gehr wrote:
> >> On 12/09/2011 09:32 PM, Ali Çehreli wrote:
> >>> So it is impossible to do anything shallow with them unless we explicitly maintain a pointer to a fixed-length array ourselves.
> >>> 
> >>> Ali
> >> 
> >> You can always slice it, of course
> >> 
> >> int[3] a;
> >> int[] b = a[]; // b now is a dynamic array that aliases a's contents
> > 
> > Though, of course, you have to be careful with that, since the static
> 
> array
> 
> > then owns the memory for that dynamic array, and if the static array
> 
> goes out
> 
> > of scope before the dynamic array does, then the dynamic array points
> > to
> > garbage and will result in bugs.
> > 
> > - Jonathan M Davis
> 
> That's news to me. Don't the static array elements belong to the runtime, managed by the garbage collector, and will be kept alive as long as the slice is alive?

Goodness no. The static array is on the stack, not on the heap. If you append to a dynamic array which refers to a static array, then it'll reallocate that memory onto the heap (leaving the original static array alone) so that the dynamic array is then managed by the runtime, but the static array never is, since it's on the stack, and as long as the dynamic array is a slice of the static array, it's going to be pointing to the wrong thing if the static array leaves scope.

So, slicing a static array to pass it to a function which isn't going to keep the memory around isn't a big deal, but doing something like

int[] func()
{
 int[5] a;
 return a[];
}

is as bad as

int* func()
{
 int a;
 return &a;
}

though at least in the second case, the compiler will give you an error. The first probably should as well, but it doesn't currently. It _is_ escaping a reference to a local variable though, which is a bug.

- Jonathan M Davis
December 09, 2011
On 12/09/2011 02:58 PM, Jonathan M Davis wrote:
> On Friday, December 09, 2011 14:33:38 Ali Çehreli wrote:
[...]
>> That's news to me. Don't the static array elements belong to the
>> runtime, managed by the garbage collector, and will be kept alive as
>> long as the slice is alive?
>
> Goodness no. The static array is on the stack, not on the heap. If you append
> to a dynamic array which refers to a static array, then it'll reallocate that
> memory onto the heap (leaving the original static array alone) so that the
> dynamic array is then managed by the runtime, but the static array never is,
> since it's on the stack, and as long as the dynamic array is a slice of the
> static array, it's going to be pointing to the wrong thing if the static array
> leaves scope.
>
> So, slicing a static array to pass it to a function which isn't going to keep
> the memory around isn't a big deal, but doing something like
>
> int[] func()
> {
>   int[5] a;
>   return a[];
> }
>
> is as bad as
>
> int* func()
> {
>   int a;
>   return&a;
> }
>
> though at least in the second case, the compiler will give you an error. The
> first probably should as well, but it doesn't currently. It _is_ escaping a
> reference to a local variable though, which is a bug.
>
> - Jonathan M Davis

Thank you. Opened:

  http://d.puremagic.com/issues/show_bug.cgi?id=7087

Ali