www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - back to arays

reply Max Samuha <maxter i.com.ua_spamless> writes:
I thought array references are similar to object references like in C#
(actually, thay are object references in C#) and that was my mistake:

int[] a = new int[20];
int[] b = a;

a.length = 40; // a is copied and b is not updated to point to a's
data;

Does it mean that anytime i change an array, i have to manually update
all references to it or should i wrap my array in an Array class so
that all references to any instance of that array remain valid?

If the question have been already discussed please refer me to the
right thread. Thanks
May 15 2006
next sibling parent "Regan Heath" <regan netwin.co.nz> writes:
On Mon, 15 May 2006 10:05:22 +0300, Max Samuha <maxter i.com.ua_spamless>  
wrote:
 I thought array references are similar to object references like in C#
 (actually, thay are object references in C#) and that was my mistake:

 int[] a = new int[20];
 int[] b = a;

 a.length = 40; // a is copied and b is not updated to point to a's
 data;

 Does it mean that anytime i change an array, i have to manually update
 all references to it or should i wrap my array in an Array class so
 that all references to any instance of that array remain valid?

 If the question have been already discussed please refer me to the
 right thread. Thanks

The D philosophy is "copy on write". Whenever you have several references to the same data and you decide to write to the data, you should make a copy and write to the copy. If you want to constantly have several references to the same data then yes, you will have to update the references whenever you make change or write a class to handle that for you. Regan
May 15 2006
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 15 May 2006 10:05:22 +0300, Max Samuha wrote:

 I thought array references are similar to object references like in C#
 (actually, thay are object references in C#) and that was my mistake:
 
 int[] a = new int[20];
 int[] b = a;
 
 a.length = 40; // a is copied and b is not updated to point to a's
 data;
 
 Does it mean that anytime i change an array, i have to manually update
 all references to it or should i wrap my array in an Array class so
 that all references to any instance of that array remain valid?
 
 If the question have been already discussed please refer me to the
 right thread. Thanks

I assume for some valid reason you want this behaviour... int[] a = new int[20]; int[] b = a; int[] c = a; a[0] = 17; writefln("%s %s", b[0], c[0]); // Displays 17 17 The simplest way to do this is ... int[] a = new int[20]; int[]* b = &a; int[]* c = &a; a[0] = 17; writefln("%s %s", b[0], c[0]); // Displays 17 17 I'm not sure why one would need this behaviour though. Why do you need two identifiers in the same scope to reference the same data? -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 15/05/2006 5:49:08 PM
May 15 2006
parent reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Derek Parnell wrote:
 On Mon, 15 May 2006 10:05:22 +0300, Max Samuha wrote:
 
 I thought array references are similar to object references like in C#
 (actually, thay are object references in C#) and that was my mistake:

 int[] a = new int[20];
 int[] b = a;

 a.length = 40; // a is copied and b is not updated to point to a's
 data;

 Does it mean that anytime i change an array, i have to manually update
 all references to it or should i wrap my array in an Array class so
 that all references to any instance of that array remain valid?

 If the question have been already discussed please refer me to the
 right thread. Thanks

I assume for some valid reason you want this behaviour... int[] a = new int[20]; int[] b = a; int[] c = a; a[0] = 17; writefln("%s %s", b[0], c[0]); // Displays 17 17

But... it will display '17 17'.
 The simplest way to do this is  ...
 
  int[] a = new int[20];
  int[]* b = &a;
  int[]* c = &a;
  a[0] = 17;
  writefln("%s %s", b[0], c[0]); // Displays 17 17

Nope, the earlier one :) As I understand it, he'd like this code: # int[] a = new int[20]; # int[] b = a; # b.length = 10; # writefln("%s %s", a.length, b.length); to output '20 20'. -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d-pu s+: a-->----- C+++$>++++ UL P+ L+ E--- W++ N++ o? K? w++ !O !M V? PS- PE- Y PGP t 5 X? R tv-- b DI- D+ G e>+++ h>++ !r !y ------END GEEK CODE BLOCK------ Tomasz Stachowiak /+ a.k.a. h3r3tic +/
May 15 2006
next sibling parent reply "Derek Parnell" <derek psych.ward> writes:
On Mon, 15 May 2006 20:24:39 +1000, Tom S  
<h3r3tic remove.mat.uni.torun.pl> wrote:

 Derek Parnell wrote:
 On Mon, 15 May 2006 10:05:22 +0300, Max Samuha wrote:

 I thought array references are similar to object references like in C#
 (actually, thay are object references in C#) and that was my mistake:

 int[] a = new int[20];
 int[] b = a;

 a.length = 40; // a is copied and b is not updated to point to a's
 data;

 Does it mean that anytime i change an array, i have to manually update
 all references to it or should i wrap my array in an Array class so
 that all references to any instance of that array remain valid?

 If the question have been already discussed please refer me to the
 right thread. Thanks

int[] a = new int[20]; int[] b = a; int[] c = a; a[0] = 17; writefln("%s %s", b[0], c[0]); // Displays 17 17

But... it will display '17 17'.
 The simplest way to do this is  ...
   int[] a = new int[20];
  int[]* b = &a;
  int[]* c = &a;
  a[0] = 17;
  writefln("%s %s", b[0], c[0]); // Displays 17 17

Nope, the earlier one :) As I understand it, he'd like this code: # int[] a = new int[20]; # int[] b = a; # b.length = 10; # writefln("%s %s", a.length, b.length); to output '20 20'.

That's what you get while trying to rush out of the office, late again for dinner. You are right. Here is my improved attempt and what I was trying to say earlier... import std.stdio; void main() { int[] a; int[]* b; int[]* c; b = &a; c = &a; a.length= 40; a[0] = 17; writefln("%d %d", c.length, b.length); writefln("%d %d", *c[0], *b[0]); } ------------------------- This displays 40 40 17 17 ------------------------- But I still don't know why one would want to do this? -- Derek Parnell Melbourne, Australia
May 15 2006
next sibling parent Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
Derek Parnell wrote:
 I'm not sure why one would need this behaviour though. Why do you need two
 identifiers in the same scope to reference the same data? 
 

Derek Parnell wrote:
 
 But I still don't know why one would want to do this?
 

I'll bet the identifiers are on the same scope just for simplification purposes. The case were you would want to have a dyn array to behave "wholly" like a reference type is quite common and necessary, just like associative arrays are now "wholly" a reference type. -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 15 2006
prev sibling parent reply Max Samuha <maxter i.com.ua_spamless> writes:
On Mon, 15 May 2006 23:08:26 +1000, "Derek Parnell" <derek psych.ward>
wrote:

void main()
{
    int[] a;
    int[]* b;
    int[]* c;

    b = &a;
    c = &a;
    a.length= 40;
    a[0] = 17;
    writefln("%d %d", c.length, b.length);
    writefln("%d %d", *c[0], *b[0]);
}

-------------------------
This displays
40 40
17 17
-------------------------

But I still don't know why one would want to do this?

No, i certainly don't want to do this. I just expected from D's dynamic arrays what was described here in a more readable English as arrays being reference types. That's clearer now. Thanks
May 15 2006
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Max Samuha wrote:
 On Mon, 15 May 2006 23:08:26 +1000, "Derek Parnell" <derek psych.ward>
 wrote:
 
 
void main()
{
   int[] a;
   int[]* b;
   int[]* c;

   b = &a;
   c = &a;
   a.length= 40;
   a[0] = 17;
   writefln("%d %d", c.length, b.length);
   writefln("%d %d", *c[0], *b[0]);
}

-------------------------
This displays
40 40
17 17
-------------------------

But I still don't know why one would want to do this?

No, i certainly don't want to do this. I just expected from D's dynamic arrays what was described here in a more readable English as arrays being reference types. That's clearer now. Thanks

I have made some similar mistakes before, to be sure. Essentially D's arrays are really structures, one of the fields of which being a pointer to the real data. Sometimes this means another array variable will be pointing to the same data, but this leaves you when you try to muck with the array. Although, in some (not all) cases you can get behavior like what you want by using inout parameters (or pointers), and in some other cases (still not all) you could probably use slice semantics. -- Chris Nicholson-Sauls
May 15 2006
prev sibling parent reply Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
Tom S wrote:
 
 
 As I understand it, he'd like this code:
 
 #    int[] a = new int[20];
 #    int[] b = a;
 #    b.length = 10;
 #    writefln("%s %s", a.length, b.length);
 
 to output '20 20'.
 
 

You mean "to output '10 10'", no? -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 15 2006
parent Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Bruno Medeiros wrote:
 You mean "to output '10 10'", no?

Arrrgh you're right :S -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d-pu s+: a-->----- C+++$>++++ UL P+ L+ E--- W++ N++ o? K? w++ !O !M V? PS- PE- Y PGP t 5 X? R tv-- b DI- D+ G e>+++ h>++ !r !y ------END GEEK CODE BLOCK------ Tomasz Stachowiak /+ a.k.a. h3r3tic +/
May 15 2006
prev sibling next sibling parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Max Samuha skrev:
 I thought array references are similar to object references like in C#
 (actually, thay are object references in C#) and that was my mistake:
 
 int[] a = new int[20];
 int[] b = a;
 
 a.length = 40; // a is copied and b is not updated to point to a's
 data;
 
 Does it mean that anytime i change an array, i have to manually update
 all references to it or should i wrap my array in an Array class so
 that all references to any instance of that array remain valid?
 
 If the question have been already discussed please refer me to the
 right thread. Thanks

The behavior of D's built in arrays have been the cause of much confusion. D's arrays actually have a kind of schizophrenic nature. They are value types referring to some portion of memory, and as such, they are not pure arrays (of course a matter of interpretation), but rather array slices. On the other hand they support append operations, and automatically copy and reallocate the data when the length is increased, which doesn't make sense for a pure slice type. So in the sense of being arrays, D's arrays neither fulfill the expected semantics of being a value type nor a reference type. This will probably make many D users cringe, by my suggestion is to use an array wrapper type with reference semantics. Something like this: (untested and incomplete code) class Array(T) { T[] data; this() {} this(int n) { length(n); } this(T[] data) { this.data = data; } void length(size_t n) { data.length = n; } size_t length() { return data.length; } Array dup() { return new Array(data.dup); } T opIndex(size_t i) { return data[i]; } T opIndexAssign(T v, size_t i) { return data[i] = v; } T[] opSlice(size_t a, size_t b) { return data[a..b]; } int opApply(...) {...} } Usage: Array!(int) a = new Array!(int)(20); Array!(int) b = a; a.length = 40; // a is NOT copied and b is updated to point to a's data Properly implemented this will work as you expect with one caveat. There is no reference return type for opIndex, making arrays of structs somewhat inconvenient. I think you can find a proper implementation in the ancient DTL library. Regards, Oskar
May 15 2006
prev sibling parent reply James Pelcis <jpelcis gmail.com> writes:
You can always "cheat" and do:

alias a b;

Max Samuha wrote:
 I thought array references are similar to object references like in C#
 (actually, thay are object references in C#) and that was my mistake:
 
 int[] a = new int[20];
 int[] b = a;
 
 a.length = 40; // a is copied and b is not updated to point to a's
 data;
 
 Does it mean that anytime i change an array, i have to manually update
 all references to it or should i wrap my array in an Array class so
 that all references to any instance of that array remain valid?
 
 If the question have been already discussed please refer me to the
 right thread. Thanks

May 15 2006
parent reply Max Samuha <maxter i.com.ua_spamless> writes:
There's one more question about arrays.

From D specs:

A pointer to the start of a garbage collected object need not be maintained if
a pointer to the interior of the object exists.
char[] p = new char[10];
char[] q = p[3..6];
// q is enough to hold on to the object, don't need to keep
// p as well.

If the garbage collector moves data referenced by p, i guess all pointers to slices of p will be updated correctly. What if i set p to null or p goes out of scope and q is still reachable, will the memory (before q.ptr and after q.ptr + q.length - 1) that was pointed to by p be reclaimed by the garbage collector?
May 17 2006
parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
I should note, currently, DMD's implementation won't move anything 
you're pointing to.

And... as you probably know, memory is allocated in chunks from the 
operating system.  Without making a copy, you can't deallocate just one 
part.  So DMD won't currently.

However, if the memory were to be copied I'd expect it to be perfectly 
reasonable that the GC might not keep the old array data (although that 
would certainly be non-trivial for the GC to do.)

I wouldn't depend on it - and it seems brittle anyway, even if it were 
guaranteed.

-[Unknown]


 There's one more question about arrays.
 
 From D specs:
 
 A pointer to the start of a garbage collected object need not be maintained if
a pointer to the interior of the object exists.
 char[] p = new char[10];
 char[] q = p[3..6];
 // q is enough to hold on to the object, don't need to keep
 // p as well.

If the garbage collector moves data referenced by p, i guess all pointers to slices of p will be updated correctly. What if i set p to null or p goes out of scope and q is still reachable, will the memory (before q.ptr and after q.ptr + q.length - 1) that was pointed to by p be reclaimed by the garbage collector?

May 17 2006
parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 17 May 2006 22:07:12 -0700, Unknown W. Brackets wrote:

 I should note, currently, DMD's implementation won't move anything 
 you're pointing to.

Even if the length is increased beyond the size that has been allocated for a dynamic array? I thought that DMD allocated a new block of the right size and copied data from the old block to it then released the old block back to the GC. I think that if the length is decreased then no copying goes on and that no memory is released back to the GC, but can be later reused if the length then is increased anywhere up to the original allocation size. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 18/05/2006 3:20:14 PM
May 17 2006
parent reply Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
Derek Parnell wrote:
 On Wed, 17 May 2006 22:07:12 -0700, Unknown W. Brackets wrote:
 
 I should note, currently, DMD's implementation won't move anything 
 you're pointing to.

Even if the length is increased beyond the size that has been allocated for a dynamic array? I thought that DMD allocated a new block of the right size and copied data from the old block to it then released the old block back to the GC.

Yes, that's what it does, but that resizing results from an explicit programmer action, and not from the GC. When W. Brackets mentioned "DMD's implementation" I believe he meant the GC only, which, as is known, indeed doesn't currently move anything.
 I think that if the length is decreased then no copying goes on and that no
 memory is released back to the GC, but can be later reused if the length
 then is increased anywhere up to the original allocation size.
 

-- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 18 2006
parent "Unknown W. Brackets" <unknown simplemachines.org> writes:
Right, sorry if I was unclear.

When you resize an array, it makes a copy - it still doesn't move 
anything.  When I was talking about moving, I was meaning a compacting 
(defragmenting) garbage collector.

DMD's garbage collector holds onto any pointer references which are 
still active, even if you change the length of a dynamic array - so that 
issue shouldn't affect this.

For slices to work properly, the above must be guaranteed afaik.  But 
holding onto the memory around said slices need not be guaranteed.

PS: I've been called a lot of different things (Uncle Brackets, Big U, 
etc.), but I hadn't ever heard "W. Brackets".  Heh.

-[Unknown]


 Derek Parnell wrote:
 On Wed, 17 May 2006 22:07:12 -0700, Unknown W. Brackets wrote:

 I should note, currently, DMD's implementation won't move anything 
 you're pointing to.

Even if the length is increased beyond the size that has been allocated for a dynamic array? I thought that DMD allocated a new block of the right size and copied data from the old block to it then released the old block back to the GC.

Yes, that's what it does, but that resizing results from an explicit programmer action, and not from the GC. When W. Brackets mentioned "DMD's implementation" I believe he meant the GC only, which, as is known, indeed doesn't currently move anything.

May 19 2006