www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why is it difficult to reference arrays in structs?

reply Brett <Brett gmail.com> writes:
struct Y { double q; }
struct X { Y[] a; }

X x;

auto r = x.a;

r is not a reference?!?!


When updating x.a, r is not updated ;/ [I'm not sure if it just 
creates a slice or what]

Ok, fine!

auto r = &x.a;

Now r is a reference, great!.

But now the semantics of using the array completely change and 
errors abound!

Normal D pointers tend to act very nice, e.g., we don't have to 
use the C++ -> BS....

But with arrays it seems things are all screwed up and do not 
work correctly.

I can't just use r like I used x.a. I can't even use *r as things 
then get even more screwed up.

I want to have a slice of an array that I can append to as a sort 
of temporary and have it append to the main array(the end of the 
slice always is the end of the main array)..

I've tried assumeSafeAppend but it does nothing to help.

The reason is because i have an algorithm that generates data and 
stores it in an array and it is more efficient and easier to code 
if I can just append data to a "slice" of the array(there are no 
issues with overwriting).

Essentially it just acts as an alias.

By using pointers it would work but it screws up the entire 
syntax of all the code and then still doesn't work.
Oct 02 2019
next sibling parent mipri <mipri minimaltype.com> writes:
On Thursday, 3 October 2019 at 04:32:52 UTC, Brett wrote:
 struct Y { double q; }
 struct X { Y[] a; }

 X x;

 auto r = x.a;

 r is not a reference?!?!
Arrays are (ptr,length) pairs. r is a copy of them: import std.stdio; struct X { int[] a; } void main() { auto test = X([0]); test.a.reserve(10); // for later auto r = test.a; writeln(test.a.ptr == r.ptr); // true writeln(test.a.length == r.length); // true } Mutate it and they're still using the same ptr: r ~= [1]; writeln(test.a.ptr == r.ptr); // true writeln(test.a.length == r.length); // false But r is still a copy of the ptr,length pair, and its length is updated separately. Consider: import std.stdio; struct X { int[] a; } void main() { X test; test.a.reserve(3); auto a = test.a; a ~= [1, 2, 3]; auto r = test.a.ptr[0..3]; writeln(r); // output: [1, 2, 3] } I have to slice the ptr directly as array operations are aware of all this. Consider: import std.stdio; struct X { int[] a; } void main() { X test; test.a.reserve(3); auto a = test.a; a ~= [1, 2, 3]; test.a.length = 3; writeln(test.a); // [0,0,0] writeln(a); // [1,2,3] } What you can do copy the (ptr,length) pair, do what you want with it, and then assign it back to the struct. Don't worry about tricky stuff.
 auto r = &x.a;

 Now r is a reference, great!.
look at it: writeln(typeid(a)); // output: int[]* It's a pointer to an int[]. It behaves like a pointer.
 I want to have a slice of an array that I can append to as a 
 sort of temporary and have it append to the main array(the end 
 of the slice always is the end of the main array)..

 I've tried assumeSafeAppend but it does nothing to help.
Learning D goes into tons of detail about slices and appending to copies and when you'd want assumeSafeAppend and so on.
Oct 02 2019
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On Thursday, 3 October 2019 at 04:32:52 UTC, Brett wrote:

 Ok, fine!

 auto r = &x.a;

 Now r is a reference, great!
No, r is a pointer, not a reference. D does not have reference variables.
 But now the semantics of using the array completely change and 
 errors abound!
Probably because you're trying to use r as if it were of type Y[] when it's really of type Y[]*, i.e. if you wanted to append to it you would need to first dereference the pointer: *r ~= Y(10.0);
 Normal D pointers tend to act very nice, e.g., we don't have to 
 use the C++ -> BS....

 But with arrays it seems things are all screwed up and do not 
 work correctly.
No, they're working as intended.
 I can't just use r like I used x.a. I can't even use *r as 
 things then get even more screwed up.
Appending to *r works as expected: https://run.dlang.io/is/IQa619 What sort of trouble did you encounter?
 I want to have a slice of an array that I can append to as a 
 sort of temporary and have it append to the main array(the end 
 of the slice always is the end of the main array)..
Your issue has nothing to do with structs. As per the documentation: https://dlang.org/spec/arrays.html#slicing the initialization of b here creates a slice referencing a: int[] a = [0, 1, 2]; int[] b = a; As a slice, b has its own .ptr and .length properties that are distinct from those of a. They are initialized with the values of a's properties, but they *are not references* to a's properties and b is *not a reference* to a. assert(b.ptr == a.ptr); assert(b.length == a.length); Because b.ptr and a.ptr point to the same memory, any updates to existing array elements through one will be reflected in the other: a[1] = 3; writeln(b); // prints [0, 3, 2] But any changes to the .ptr or .length of one will not be reflected in the other: a ~= 10; assert(a.length == 4); assert(b.length == 3); writeln(a); // prints [0, 3, 2, 10]; writeln(b); // prints [0, 3, 2]; Though at this point, depending on whether or not a reallocation took place, they might still be pointing to the same block of memory.
 I've tried assumeSafeAppend but it does nothing to help.
assumeSafeAppend is for telling the runtime that you want to reuse an existing memory block backing an array and there's no need to reallocate it in append. https://dlang.org/articles/d-array-article.html#slice-members-appender
 The reason is because i have an algorithm that generates data 
 and stores it in an array > and it is more efficient and easier 
 to code if I can just append data to a "slice" of the 
 array(there are no issues with overwriting).

 Essentially it just acts as an alias.

 By using pointers it would work but it screws up the entire 
 syntax of all the code and > then still doesn't work.
Could you adjust the signature of your algorithm to take the array by ref? void myAlgo(ref Y[] arr) { arr ~= Y(10.2); } Or to take x by ref (or as a pointer) and manipulate the array directly: void myAlgo(ref X x) { x.a ~= Y(10.2); }
Oct 02 2019