www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how to append (ref) int[] to int[][]?

reply mw <mingwu gmail.com> writes:
Hi,

I have this program:
----------------------------------------------------
import std.stdio;

void f(ref int[] arr) {
         arr ~= 3;
}

void main() {
         int[][] arrs;
         int[] arr;
         foreach (i; 0 .. 3) {
                 arr = new int[0];
                 arrs ~= arr; //(a) [[], [], []]
                 f(arr);
                 // arrs ~= arr; //(b) [[3], [3], [3]]
         }

         writeln(arrs);
}
----------------------------------------------------

This program will print out [[], [], []].

If I comment out (a), and use (b), it will print out [[3], [3], 
[3]]

So based on this behavior, looks like "~=" will append a copy of 
`arr`; but what I really want in (a) is append `ref arr` and 
output [[3], [3], [3]], i.e. the real `arr` be appended instead 
of its copy.

I have to say this semantics surprised me.

I tried to change arrs' decl to:

     (ref (int[]))[] arrs;  // the intended semantics I want

But I got compiler error out: "found ( when expecting function 
literal following ref".

1) I'm wondering how to achieve what I want? and
2) why "~=" here will append a copy rather than the real `arr` 
itself to arrs?


Thanks.
Jun 07 2020
next sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Monday, 8 June 2020 at 06:13:36 UTC, mw wrote:
 Hi,

 I have this program:
 ----------------------------------------------------
 import std.stdio;

 void f(ref int[] arr) {
         arr ~= 3;
 }

 void main() {
         int[][] arrs;
         int[] arr;
         foreach (i; 0 .. 3) {
                 arr = new int[0];
                 arrs ~= arr; //(a) [[], [], []]
                 f(arr);
                 // arrs ~= arr; //(b) [[3], [3], [3]]
         }

         writeln(arrs);
 }
 ----------------------------------------------------

 This program will print out [[], [], []].

 If I comment out (a), and use (b), it will print out [[3], [3], 
 [3]]

 So based on this behavior, looks like "~=" will append a copy 
 of `arr`; but what I really want in (a) is append `ref arr` and 
 output [[3], [3], [3]], i.e. the real `arr` be appended instead 
 of its copy.

 I have to say this semantics surprised me.

 I tried to change arrs' decl to:

     (ref (int[]))[] arrs;  // the intended semantics I want

 But I got compiler error out: "found ( when expecting function 
 literal following ref".

 1) I'm wondering how to achieve what I want? and
 2) why "~=" here will append a copy rather than the real `arr` 
 itself to arrs?
Arrays (technically, slices) in D are essentially this struct: struct Array(T) { T* ptr; size_t length; // operator overloads } So when you have int[][], each element of the outer array is an Array!int. These, as simple structs, are copied about, so that changing one does not change another. The simple solution here is to call f not on arr, but on arrs[$-1] (the last element of arrs). If that is not possible you will need arrs to be an int[]*[]. -- Simen
Jun 07 2020
parent reply mw <mingwu gmail.com> writes:
On Monday, 8 June 2020 at 06:42:44 UTC, Simen Kjærås wrote:
 Arrays (technically, slices) in D are essentially this struct:

 struct Array(T) {
     T* ptr;
     size_t length;
     // operator overloads
 }

 So when you have int[][], each element of the outer array is an 
 Array!int. These, as simple structs, are copied about, so that 
 changing one does not change another.
Thank you for the reply, I think this explanation should be added to the top of https://dlang.org/spec/arrays.html Then people (esp with C/C++ background) can easily understand D's array behavior.
Jun 07 2020
parent Paul Backus <snarwin gmail.com> writes:
On Monday, 8 June 2020 at 06:52:36 UTC, mw wrote:
 On Monday, 8 June 2020 at 06:42:44 UTC, Simen Kjærås wrote:
 Arrays (technically, slices) in D are essentially this struct:

 struct Array(T) {
     T* ptr;
     size_t length;
     // operator overloads
 }

 So when you have int[][], each element of the outer array is 
 an Array!int. These, as simple structs, are copied about, so 
 that changing one does not change another.
Thank you for the reply, I think this explanation should be added to the top of https://dlang.org/spec/arrays.html Then people (esp with C/C++ background) can easily understand D's array behavior.
A good explanation of D's arrays (which should really be called "slices") is available in the "Articles" section of dlang.org: https://dlang.org/articles/d-array-article.html
Jun 08 2020
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Monday, 8 June 2020 at 06:13:36 UTC, mw wrote:
 what I really want in (a) is append `ref arr` and output [[3], 
 [3], [3]], i.e. the real `arr` be appended instead of its copy.

 I tried to change arrs' decl to:

     (ref (int[]))[] arrs;  // the intended semantics I want

 1) I'm wondering how to achieve what I want? and
 2) why "~=" here will append a copy rather than the real `arr` 
 itself to arrs?


 Thanks.
``` import std.stdio; void f(ref int[] arr) { arr ~= 3; } void main() { import std.algorithm; int[]*[] arrs; int[]* arr; foreach (i; 0 .. 3) { //stack allocated array pointer&length would expire on end of scope, so must allocate the them on heap since we're keeping refeerences on them. auto arrayAllocation = new int[][1]; arr = &arrayAllocation[0]; *arr = new int[0]; arrs ~= arr; f(*arr); } //will print an array of addresses otherwise arrs.map!(ptr => *ptr).writeln; } ``` But I must say I would generally prefer just calling `f()` on `arrs[i]` directly after appending, or calling the function before appending. One reason is that needless heap usage is generally less efficient than using the stack.
Jun 08 2020