www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - .dup ?

reply bobef <bobef_member pathlink.com> writes:
Why there is no .dup property of AAs? And if .dup is used for array of, lets
say, stucts that have another array as member is it duplicated too or if I
modify it in the dup array the original will be modified too?
Apr 25 2005
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
bobef wrote:
 Why there is no .dup property of AAs? And if .dup is used for array of, lets
 say, stucts that have another array as member is it duplicated too or if I
 modify it in the dup array the original will be modified too?

I agree that .dup on AAs would be nice. But you can build one by hand like this: foo[bar] dup(foo[bar] orig) { foo[bar] ret; foreach(bar key; orig.keys) ret[key] = orig[key]; return ret; } Now, for the harder question. You said that there was an array of structs, and each struct had an array member. So it's like this: struct Baz { Fred[] a; }; Baz[] orig_array; ...code sets orig_array... Baz[] copy_array = orig_array.dup; Now, what's going to happen when you dup the array is that you are going to get a new array, where all of the elements are copies of the original elements. When you copy structs, you are copying them by value (I think, though I'm not sure, that it's by binary copy). Thus, the 'a' member in each of the copied structs is a copy of the 'a' member in the original. Now, think about how a dynamic array works. A dynamic array may be thought of as a two-memeber ministruct; it has both a pointer to the array location, and a length value. When you copy the enclosing struct, you are just copying that pointer and that length information. So, the arrays in the copied structs point to the exact same physical locations as the arrays in the originals. So if you modify a variable in an array in a copied struct, you are also modifying the array in the original struct: copy_array[0].a[0] = 1; assert(orig_array[0].a[0] == 1); However, if you modify the array itself in the copy, you are not modifying the original array: copy_array[0].a.length = copy_array[0].a.length+1; assert(copy_array[0].a.length == orig_array[0].a.length+1); Now, while we're on the subject, lemme tell you about a couple of similar situations which work differently: 1) CLASSes If you use classes instead of structs, then the array contains references to class objects, not the objects themselves. Thus, when you 'dup' orig_array, you get a copied array which contains the same references as the original. Thus, modifying copy_array[0] would be exactly the same as modifying orig_array[0] 2) Fixed-Length arrays If you struct uses a fixed-length array (rather than a dynamic one), then the values of the array are stored directly in the struct rather than storing a pointer in the struct. (That is, it works like C.) So if Baz was declared like this: struct Baz { Fred[10] a; } Then when you copy the struct, you are also copying all 10 of the members of a. Then, changing copy_array would not impact orig_array in any way. 3) Associative arrays I will simply say that I have no idea what would happen if you copied an associative array. I would guess that it would probably work until you modified the array, after which I wouldn't be surprised if you got some corruption.
Apr 25 2005
parent reply David Medlock <amedlock nospam.org> writes:
even shorter(possibly faster) which grabs pairs instead of just keys:

foo[bar] dup( foo[bar] arr )
{
   foo[bar] copy;
   foreach( bar key, foo val ; arr ) copy[key]=val;
   return copy;
}

This should avoid the lookup orig[key] below.
-DavidM


Russ Lewis wrote:
 bobef wrote:
 
 Why there is no .dup property of AAs? And if .dup is used for array 
 of, lets
 say, stucts that have another array as member is it duplicated too or 
 if I
 modify it in the dup array the original will be modified too?

I agree that .dup on AAs would be nice. But you can build one by hand like this: foo[bar] dup(foo[bar] orig) { foo[bar] ret; foreach(bar key; orig.keys) ret[key] = orig[key]; return ret; } Now, for the harder question. You said that there was an array of structs, and each struct had an array member. So it's like this: struct Baz { Fred[] a; }; Baz[] orig_array; ...code sets orig_array... Baz[] copy_array = orig_array.dup; Now, what's going to happen when you dup the array is that you are going to get a new array, where all of the elements are copies of the original elements. When you copy structs, you are copying them by value (I think, though I'm not sure, that it's by binary copy). Thus, the 'a' member in each of the copied structs is a copy of the 'a' member in the original. Now, think about how a dynamic array works. A dynamic array may be thought of as a two-memeber ministruct; it has both a pointer to the array location, and a length value. When you copy the enclosing struct, you are just copying that pointer and that length information. So, the arrays in the copied structs point to the exact same physical locations as the arrays in the originals. So if you modify a variable in an array in a copied struct, you are also modifying the array in the original struct: copy_array[0].a[0] = 1; assert(orig_array[0].a[0] == 1); However, if you modify the array itself in the copy, you are not modifying the original array: copy_array[0].a.length = copy_array[0].a.length+1; assert(copy_array[0].a.length == orig_array[0].a.length+1); Now, while we're on the subject, lemme tell you about a couple of similar situations which work differently: 1) CLASSes If you use classes instead of structs, then the array contains references to class objects, not the objects themselves. Thus, when you 'dup' orig_array, you get a copied array which contains the same references as the original. Thus, modifying copy_array[0] would be exactly the same as modifying orig_array[0] 2) Fixed-Length arrays If you struct uses a fixed-length array (rather than a dynamic one), then the values of the array are stored directly in the struct rather than storing a pointer in the struct. (That is, it works like C.) So if Baz was declared like this: struct Baz { Fred[10] a; } Then when you copy the struct, you are also copying all 10 of the members of a. Then, changing copy_array would not impact orig_array in any way. 3) Associative arrays I will simply say that I have no idea what would happen if you copied an associative array. I would guess that it would probably work until you modified the array, after which I wouldn't be surprised if you got some corruption.

Apr 26 2005
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Good catch!  But since foo might be a complex type, here's a version 
that would be even faster for some types:

foo[bar] dup( foo[bar] arr )
{
   foo[bar] copy;
   foreach( bar key, inout foo val ; arr ) copy[key]=val;
   return copy;
}

TAG!  You're it! :)

David Medlock wrote:
 even shorter(possibly faster) which grabs pairs instead of just keys:
 
 foo[bar] dup( foo[bar] arr )
 {
   foo[bar] copy;
   foreach( bar key, foo val ; arr ) copy[key]=val;
   return copy;
 }
 
 This should avoid the lookup orig[key] below.
 -DavidM
 
 
 Russ Lewis wrote:
 
 bobef wrote:

 Why there is no .dup property of AAs? And if .dup is used for array 
 of, lets
 say, stucts that have another array as member is it duplicated too or 
 if I
 modify it in the dup array the original will be modified too?

I agree that .dup on AAs would be nice. But you can build one by hand like this: foo[bar] dup(foo[bar] orig) { foo[bar] ret; foreach(bar key; orig.keys) ret[key] = orig[key]; return ret; } Now, for the harder question. You said that there was an array of structs, and each struct had an array member. So it's like this: struct Baz { Fred[] a; }; Baz[] orig_array; ...code sets orig_array... Baz[] copy_array = orig_array.dup; Now, what's going to happen when you dup the array is that you are going to get a new array, where all of the elements are copies of the original elements. When you copy structs, you are copying them by value (I think, though I'm not sure, that it's by binary copy). Thus, the 'a' member in each of the copied structs is a copy of the 'a' member in the original. Now, think about how a dynamic array works. A dynamic array may be thought of as a two-memeber ministruct; it has both a pointer to the array location, and a length value. When you copy the enclosing struct, you are just copying that pointer and that length information. So, the arrays in the copied structs point to the exact same physical locations as the arrays in the originals. So if you modify a variable in an array in a copied struct, you are also modifying the array in the original struct: copy_array[0].a[0] = 1; assert(orig_array[0].a[0] == 1); However, if you modify the array itself in the copy, you are not modifying the original array: copy_array[0].a.length = copy_array[0].a.length+1; assert(copy_array[0].a.length == orig_array[0].a.length+1); Now, while we're on the subject, lemme tell you about a couple of similar situations which work differently: 1) CLASSes If you use classes instead of structs, then the array contains references to class objects, not the objects themselves. Thus, when you 'dup' orig_array, you get a copied array which contains the same references as the original. Thus, modifying copy_array[0] would be exactly the same as modifying orig_array[0] 2) Fixed-Length arrays If you struct uses a fixed-length array (rather than a dynamic one), then the values of the array are stored directly in the struct rather than storing a pointer in the struct. (That is, it works like C.) So if Baz was declared like this: struct Baz { Fred[10] a; } Then when you copy the struct, you are also copying all 10 of the members of a. Then, changing copy_array would not impact orig_array in any way. 3) Associative arrays I will simply say that I have no idea what would happen if you copied an associative array. I would guess that it would probably work until you modified the array, after which I wouldn't be surprised if you got some corruption.


Apr 26 2005
parent David Medlock <amedlock nospam.org> writes:
Russ Lewis wrote:
 Good catch!

Likewise. :) I thought that foreach parameters were always inout though?? Its actually a little disconcerting that in my opApply method a caller might overwrite my index variable! (eg. foreach over an array) -DavidM But since foo might be a complex type, here's a version
 that would be even faster for some types:
 
 foo[bar] dup( foo[bar] arr )
 {
   foo[bar] copy;
   foreach( bar key, inout foo val ; arr ) copy[key]=val;
   return copy;
 }
 
 TAG!  You're it! :)
 
 David Medlock wrote:
 
 even shorter(possibly faster) which grabs pairs instead of just keys:

 foo[bar] dup( foo[bar] arr )
 {
   foo[bar] copy;
   foreach( bar key, foo val ; arr ) copy[key]=val;
   return copy;
 }

 This should avoid the lookup orig[key] below.
 -DavidM


 Russ Lewis wrote:

 bobef wrote:

 Why there is no .dup property of AAs? And if .dup is used for array 
 of, lets
 say, stucts that have another array as member is it duplicated too 
 or if I
 modify it in the dup array the original will be modified too?

I agree that .dup on AAs would be nice. But you can build one by hand like this: foo[bar] dup(foo[bar] orig) { foo[bar] ret; foreach(bar key; orig.keys) ret[key] = orig[key]; return ret; } Now, for the harder question. You said that there was an array of structs, and each struct had an array member. So it's like this: struct Baz { Fred[] a; }; Baz[] orig_array; ...code sets orig_array... Baz[] copy_array = orig_array.dup; Now, what's going to happen when you dup the array is that you are going to get a new array, where all of the elements are copies of the original elements. When you copy structs, you are copying them by value (I think, though I'm not sure, that it's by binary copy). Thus, the 'a' member in each of the copied structs is a copy of the 'a' member in the original. Now, think about how a dynamic array works. A dynamic array may be thought of as a two-memeber ministruct; it has both a pointer to the array location, and a length value. When you copy the enclosing struct, you are just copying that pointer and that length information. So, the arrays in the copied structs point to the exact same physical locations as the arrays in the originals. So if you modify a variable in an array in a copied struct, you are also modifying the array in the original struct: copy_array[0].a[0] = 1; assert(orig_array[0].a[0] == 1); However, if you modify the array itself in the copy, you are not modifying the original array: copy_array[0].a.length = copy_array[0].a.length+1; assert(copy_array[0].a.length == orig_array[0].a.length+1); Now, while we're on the subject, lemme tell you about a couple of similar situations which work differently: 1) CLASSes If you use classes instead of structs, then the array contains references to class objects, not the objects themselves. Thus, when you 'dup' orig_array, you get a copied array which contains the same references as the original. Thus, modifying copy_array[0] would be exactly the same as modifying orig_array[0] 2) Fixed-Length arrays If you struct uses a fixed-length array (rather than a dynamic one), then the values of the array are stored directly in the struct rather than storing a pointer in the struct. (That is, it works like C.) So if Baz was declared like this: struct Baz { Fred[10] a; } Then when you copy the struct, you are also copying all 10 of the members of a. Then, changing copy_array would not impact orig_array in any way. 3) Associative arrays I will simply say that I have no idea what would happen if you copied an associative array. I would guess that it would probably work until you modified the array, after which I wouldn't be surprised if you got some corruption.



Apr 26 2005