www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - going beyond your bounds

reply MLT <none anon.com> writes:
After a discussion on digitalmars.D I played with arrays a bit. Look at the
following code:
		int[] a = [1,2,3,4,5,6,7,8,9] ;
		int[] b = a ;
		a ~= 10 ;
                b ~= 11 ;
		b[0] = 12 ;
		Stdout(b).newline ;
		Stdout(a).newline ;

The result is:
[12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
[12, 2, 3, 4, 5, 6, 7, 8, 9, 11]

Which means that even though b was set only to a[0..10], after expanding b,
also has direct access to element a[10]. But
		int[] a = [1,2,3,4,5,6,7,8,9] ;
		int[] b = a ;
		a ~= 10 ;
		b.length = b.length+1 ;
		b[0] = 11 ;
		Stdout(b).newline ;
		Stdout(a).newline ;

Gives 
[11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
[11, 2, 3, 4, 5, 6, 7, 8, 9, 0]


Now b is expanded in length, but a side effect is that a[10] is set to 0 (i.e.
initialized).

In the end, I think b can only see things that happen to a[10] after it
expanded, but not before. It seems there is no way for the following to work:
		int[] a = [1,2,3,4,5,6,7,8,9] ;
		int[] b = a ;
		a ~= 10 ;

At this point, element a[10]=10 will never be visible to b. b can expand to it,
but by doing that, a[10] will be overwritten.

Is this on purpose? It could also be useful to have b.length=b.length+1 which
only initializes memory that has not been initialized before.
May 21 2009
parent reply Derek Parnell <derek psych.ward> writes:
On Thu, 21 May 2009 04:51:16 -0400, MLT wrote:

 After a discussion on digitalmars.D I played with arrays a bit. Look at the
following code:
 		int[] a = [1,2,3,4,5,6,7,8,9] ;
 		int[] b = a ;
 		a ~= 10 ;
                 b ~= 11 ;
 		b[0] = 12 ;
 		Stdout(b).newline ;
 		Stdout(a).newline ;
 
 The result is:
 [12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
 [12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
 
 Which means that even though b was set only to a[0..10], after expanding b,
also has direct access to element a[10]. But
 		int[] a = [1,2,3,4,5,6,7,8,9] ;
 		int[] b = a ;
 		a ~= 10 ;
 		b.length = b.length+1 ;
 		b[0] = 11 ;
 		Stdout(b).newline ;
 		Stdout(a).newline ;
 
 Gives 
 [11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
 [11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
 
 Now b is expanded in length, but a side effect is that a[10] is set to 0 (i.e.
initialized).
 
 In the end, I think b can only see things that happen to a[10] after it
expanded, but not before. It seems there is no way for the following to work:
 		int[] a = [1,2,3,4,5,6,7,8,9] ;
 		int[] b = a ;
 		a ~= 10 ;
 
 At this point, element a[10]=10 will never be visible to b. b can expand to
it, but by doing that, a[10] will be overwritten.
 
 Is this on purpose? It could also be useful to have b.length=b.length+1 which
only initializes memory that has not been initialized before.
Yes it is on purpose. Here is what is happening ... The contents of the array variable is actually a 2-element struct {addr, length}. When you assign one array to another, that struct is what is copied, not the array data itself. int[] a = [1,2,3,4,5,6,7,8,9] ; // Now 'a' contains {adr, 9} int[] b = a ; // Now 'b' contains {adr, 9} a ~= 10 ; // Now 'a' contains {adr, 10} -- The address doesn't change -- because the buffer allocation -- still enough room for another element. b ~= 11 ; // Now 'b' contains {adr, 10} -- The address doesn't change -- because the buffer allocation -- still enough room for another element -- And that new element overwrote the '10' -- appended to 'a'. b[0] = 12 ; // The element at address 'adr' is modified. // As both 'a' and 'b' point to the same area // it appears that updating 'b' changes 'a'. The safe way to copy the data of an array is to do ... int[] a = [1,2,3,4,5,6,7,8,9] ; int[] b = a.dup ; // COPY a's data to to b. a ~= 10 ; b ~= 11 ; b[0] = 12 ; The result should now be: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [12, 2, 3, 4, 5, 6, 7, 8, 9, 11] So remember, assigning one array to another is just creating an alias to the original array. You end up with two arrays pointing to the same data buffer. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 21 2009
parent reply MLT <none anon.com> writes:
Derek Parnell Wrote:

 
 So remember, assigning one array to another is just creating an alias to
 the original array. You end up with two arrays pointing to the same data
 buffer.
Yes. My question relates to what happens when you go beyond the bounds originally assigned. Why does an extension of an array b.length = b.length+1 ; erase (initialize) the data that b extends to?
May 21 2009
parent reply Derek Parnell <derek psych.ward> writes:
On Thu, 21 May 2009 05:37:59 -0400, MLT wrote:

 Derek Parnell Wrote:
 
 
 So remember, assigning one array to another is just creating an alias to
 the original array. You end up with two arrays pointing to the same data
 buffer.
Yes. My question relates to what happens when you go beyond the bounds originally assigned. Why does an extension of an array b.length = b.length+1 ; erase (initialize) the data that b extends to?
Because new elements are pre-initialized in D. Just by increasing the length, you 'create' a new element (from the 'b' point of view) so D initializes it. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 21 2009
parent reply MLT <none anon.com> writes:
 Because new elements are pre-initialized in D.
 
 Just by increasing the length, you 'create' a new element (from the 'b'
 point of view) so D initializes it.
(We were talking about something like int a[] = [1,2,3,4,5] ; b = a ; a ~= 6 ; b.length = b.length+1;) Hmmm... yes, that has some logic to it. D does keep track of the actual array of integers that both a and b point to and knows when to allocate new memory for the array. So in theory it could be possible that when b.length increases, initialization only happens if this memory is uninitialized. On the other hand, I guess that if you get an array, say b, in a function, you might rely on the fact that when you extend b.length, the area will be initialized...
May 21 2009
parent Derek Parnell <derek psych.ward> writes:
On Thu, 21 May 2009 05:58:04 -0400, MLT wrote:

 Because new elements are pre-initialized in D.
 
 Just by increasing the length, you 'create' a new element (from the 'b'
 point of view) so D initializes it.
(We were talking about something like int a[] = [1,2,3,4,5] ; b = a ; a ~= 6 ; b.length = b.length+1;) Hmmm... yes, that has some logic to it. D does keep track of the actual array of integers that both a and b point to
Not really. The original data is a literal so it is supposed to be unmodifiable (I think Linux enforces it but not sure).
 and knows when to allocate new memory for the array. 
It allocates new RAM when the current buffer allocation will not be large enough to hold the new elements. When it does this, it allocates the new buffer and copies the old data to it. This means that you cannot rely on the alias 'feature' to work all the time. For example ... int[] a = [ some data ]; int[] b = a; // Ok, so both 'a' and 'b' point to the data now. a ~= newone; // This can't fit in so an allocation occurs // and the data copied, then 'a' is set to the // the new buffer. // BUT 'b' still points to the old buffer.
So in theory it could be possible that when b.length increases,
 initialization only happens if this memory is uninitialized.
Theoreticaly yes, but it isn't going to happen.
 On the other hand, I guess that if you get an array, say b,
 in a function, you might rely on the fact that when you
 extend b.length, the area will be initialized...
This is also a trap. If the function increases the length of the array passed to it, there will be so initialization happening, but when the function returns, the array variable passed to the function is unchanged. Its length is not modified so the new initialized data is not part of the array. This is because when you pass an array to a function, it's that small struct that is passedon the stack, so changing that will not change the argument's properties. eg. void func(int[] x) { x.length = x.length + 1; } int a[] = [1,2,3]; func(a); writefln("%s", a) //--> [1,2,3] and not [1,2,3,0] -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
May 21 2009