digitalmars.D.learn - a struct as an multidimensional array index
- Chris Katko (12/12) Jun 10 2022 Is it somehow possible to use a struct as a [multidimensional]
- =?UTF-8?Q?Ali_=c3=87ehreli?= (29/30) Jun 10 2022 index:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (12/14) Jun 10 2022 Fixed it by changing one of the lambdas to take by reference:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (21/23) Jun 10 2022 Ok, now I see the very sinister problem: It is a disaster to combine
- H. S. Teoh (5/22) Jun 10 2022 See: https://dlang.org/spec/operatoroverloading.html#array-ops
- z (23/35) Jun 10 2022 AFAIK no.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (29/37) Jun 10 2022 I've written about this multiple times in the past but D's way is
- Chris Katko (15/57) Jun 10 2022 This is an interesting discussion. I had noticed multi-dim arrays
- z (13/85) Jun 11 2022 I rechecked and it should be `X Y Z` for static array, but `Z Y
- =?UTF-8?Q?Ali_=c3=87ehreli?= (18/20) Jun 11 2022 How so? I wrote the following program:
- z (5/10) Jun 11 2022 i meant with the syntax in (1), the spec's documentation appears
- =?UTF-8?Q?Ali_=c3=87ehreli?= (11/15) Jun 11 2022 Thank you. I see now: The values in parentheses are the lengths from the...
- Salih Dincer (37/40) Jun 11 2022 I think so too...
- =?UTF-8?Q?Ali_=c3=87ehreli?= (40/46) Jun 11 2022 Yet, there are no rows or columns because neither D nor C (nor C++) have...
Is it somehow possible to use a struct as a [multidimensional] array index: ````D struct indexedPair { size_t x, y; } bool isMapPassable[100][100]; auto p = indexedPair(50, 50); if(isMapPassable[p]) return true; ```` Probably not, but I'm curious.
Jun 10 2022
On 6/10/22 01:08, Chris Katko wrote:Is it somehow possible to use a struct as a [multidimensional] arrayindex: You can define an opIndex that takes any index type if the array is defined by you: import std.stdio; import std.format; struct indexedPair { size_t x, y; } struct MyArray { bool[3][3] elements; ref opIndex(indexedPair i) { return elements[i.y][i.x]; } // void toString(scope void delegate(in char[]) sink) const { // import std.algorithm; // sink.formattedWrite!"%-(%-(%s %)\n%)"( // elements[].map!(row => row[].map!(column => column ? 'T' : 'f'))); // } } void main() { auto arr = MyArray(); auto p = indexedPair(1, 1); arr[p] = true; writeln(arr); } I played with that toString function but for some reason it prints all Ts. (?) Ali
Jun 10 2022
On 6/10/22 07:38, Ali Çehreli wrote:I played with that toString function but for some reason it prints all Ts. (?)Fixed it by changing one of the lambdas to take by reference: void toString(scope void delegate(in char[]) sink) const { import std.algorithm; sink.formattedWrite!"%-(%-(%s %)\n%)"( elements[].map!((ref row) => row[].map!(column => column ? 'T' : 'f'))); // ^^^ } I still don't understand the reason though. The rows would be copied without ref but should retain their type as bool[3], a static array. (?) Ali
Jun 10 2022
On 6/10/22 08:01, Ali Çehreli wrote:I still don't understand the reason though. The rows would be copied without ref but should retain their type as bool[3], a static array. (?)Ok, now I see the very sinister problem: It is a disaster to combine static array lambda parameters with the laziness of range algorithms. The following program prints garbage because by the time writeln prints the elements, those elements are on invalid places on the stack: import std; void main() { int[3][3] arr; writeln( arr[] // Have to slice .map!(row => row[] // Have to slice .map!(element => element)) ); } The output is garbage element values. The programmer must take the parameter of the outer map by reference so that the elements are referring to actual elements in 'arr': .map!((ref row) => /* ... */ I don't think I realized this issue before, which may be caught by various combinations of safety compiler switches, which I haven't tried yet. Ali
Jun 10 2022
On Fri, Jun 10, 2022 at 08:08:45AM +0000, Chris Katko via Digitalmars-d-learn wrote:Is it somehow possible to use a struct as a [multidimensional] array index: ````D struct indexedPair { size_t x, y; } bool isMapPassable[100][100]; auto p = indexedPair(50, 50); if(isMapPassable[p]) return true; ```` Probably not, but I'm curious.See: https://dlang.org/spec/operatoroverloading.html#array-ops T -- It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
Jun 10 2022
On Friday, 10 June 2022 at 08:08:45 UTC, Chris Katko wrote:Is it somehow possible to use a struct as a [multidimensional] array index: ````D struct indexedPair { size_t x, y; } bool isMapPassable[100][100]; auto p = indexedPair(50, 50); if(isMapPassable[p]) return true; ```` Probably not, but I'm curious.AFAIK no. I admit it's an area D could improve on, it creates a lot of confusion because of the ordering and the lack of an integrated solution. (arrays of arrays has different order for declaration and addressing, and declaring array of arrays has different order depending on how you declare it and wether it's static or dynamic array, *oof*) To give you an idea of the situation : ```D int[3][1] a;//one array of 3 int writeln(a[0][2]);//first "column", third "row" ``` One thing you could do however is make the array accept a multidimensional argument through operator overloading(opIndex) if it is the only array from a struct, but that gets unviable when you have multiple arrays that would benefit from it. To summarize, there does not appear to be an easy solution that has no drawbacks. I'd recommend saving yourself the trouble of array of arrays(of arrays?) and using a single array of length x*y with a function to index into it `(x+(xlength*y)` or `( (x+(xlength*y)) + ((xlength*ylength)*z)) )` if that is desirable.
Jun 10 2022
On 6/10/22 08:13, z wrote:arrays of arrays has different order for declaration and addressing, and declaring array of arrays has different order depending on how you declare it and wether it's static or dynamic array, *oof*) To give you an idea of the situation : ```D int[3][1] a;//one array of 3 int writeln(a[0][2]);//first "column", third "row" ```I've written about this multiple times in the past but D's way is consistent for me. That must be because I always found C's syntax to be very illogical on this. To me, C's problem starts with putting the variable name in the middle: // C code: int a[1][3]; // Why? So, first, D moves the variable to its consistent place: after the type: int i; int[N] arr; Both of those are in the form of "type and then name". Good... And then, here is the consistency with arrays: "type and then square brackets". int[] dynamicArray; int[N] staticArray; So, here is where you and I differ: int[3][1] arr; // Ali likes int[1][3] arr; // z wants I like it because it is consistently "type and then square brackets". (It so happens that the type of each element is int[N] in this case.) If it were the other way, than array syntax would be inconsistent with itself. :) Or, we would have to accept that it is inside-out like in C. But of course I understand how it is seen as consistent from C's point of view. :) And this is consistent with static vs dynamic as well because again it's "type and then square brackets": int[1][] a; // A dynamic array of int[1] int[][3] b; // A static array of 3 int[]s Ali
Jun 10 2022
On Friday, 10 June 2022 at 17:26:48 UTC, Ali Çehreli wrote:On 6/10/22 08:13, z wrote:This is an interesting discussion. I had noticed multi-dim arrays seemed backwards but I assumed I was doing something wrong and had other thing to worry about. I had no idea it was DIFFERENT for static vs dynamic arrays? That's horrifying! Also you reminded me of a possible D bug that I ran into. I had classes that had circular dependencies. One had to know about the other, and vice-versa. And I had derived classes. But somehow, they would explode. I would send one reference to the others constructor to 'link' them together, but the reference would be NULL. But if I accessed the exact same variable through a global reference, it worked fine. I tried ripping the affected code into a new file but the bug wasn't replicated. Even if I matched the compiler/linker options. It was super frustrating.arrays of arrays has different order for declaration andaddressing,and declaring array of arrays has different order dependingon how youdeclare it and wether it's static or dynamic array, *oof*) To give you an idea of the situation : ```D int[3][1] a;//one array of 3 int writeln(a[0][2]);//first "column", third "row" ```I've written about this multiple times in the past but D's way is consistent for me. That must be because I always found C's syntax to be very illogical on this. To me, C's problem starts with putting the variable name in the middle: // C code: int a[1][3]; // Why? So, first, D moves the variable to its consistent place: after the type: int i; int[N] arr; Both of those are in the form of "type and then name". Good... And then, here is the consistency with arrays: "type and then square brackets". int[] dynamicArray; int[N] staticArray; So, here is where you and I differ: int[3][1] arr; // Ali likes int[1][3] arr; // z wants I like it because it is consistently "type and then square brackets". (It so happens that the type of each element is int[N] in this case.) If it were the other way, than array syntax would be inconsistent with itself. :) Or, we would have to accept that it is inside-out like in C. But of course I understand how it is seen as consistent from C's point of view. :) And this is consistent with static vs dynamic as well because again it's "type and then square brackets": int[1][] a; // A dynamic array of int[1] int[][3] b; // A static array of 3 int[]s Ali
Jun 10 2022
On Saturday, 11 June 2022 at 03:56:32 UTC, Chris Katko wrote:On Friday, 10 June 2022 at 17:26:48 UTC, Ali Çehreli wrote:I rechecked and it should be `X Y Z` for static array, but `Z Y X` for indexing/dynamic array creating with `new` (e.g. `float[][][] arr = new float[][][](third_dimension,second_dimension,first_dimension;`) The dillema is that alone, the orders are sound byproducts of the language rules, it's when they are put in relation to each other that it can become weird. The bug could also be one of those implementation-specific bugs that are seemingly impossible to reproduce minimally because they require unknown very specific conditions to occur. Self and inter referencing appears unstable whenever it is not in the module/global scope.On 6/10/22 08:13, z wrote:This is an interesting discussion. I had noticed multi-dim arrays seemed backwards but I assumed I was doing something wrong and had other thing to worry about. I had no idea it was DIFFERENT for static vs dynamic arrays? That's horrifying! Also you reminded me of a possible D bug that I ran into. I had classes that had circular dependencies. One had to know about the other, and vice-versa. And I had derived classes. But somehow, they would explode. I would send one reference to the others constructor to 'link' them together, but the reference would be NULL. But if I accessed the exact same variable through a global reference, it worked fine. I tried ripping the affected code into a new file but the bug wasn't replicated. Even if I matched the compiler/linker options. It was super frustrating.arrays of arrays has different order for declaration andaddressing,and declaring array of arrays has different order dependingon how youdeclare it and wether it's static or dynamic array, *oof*) To give you an idea of the situation : ```D int[3][1] a;//one array of 3 int writeln(a[0][2]);//first "column", third "row" ```I've written about this multiple times in the past but D's way is consistent for me. That must be because I always found C's syntax to be very illogical on this. To me, C's problem starts with putting the variable name in the middle: // C code: int a[1][3]; // Why? So, first, D moves the variable to its consistent place: after the type: int i; int[N] arr; Both of those are in the form of "type and then name". Good... And then, here is the consistency with arrays: "type and then square brackets". int[] dynamicArray; int[N] staticArray; So, here is where you and I differ: int[3][1] arr; // Ali likes int[1][3] arr; // z wants I like it because it is consistently "type and then square brackets". (It so happens that the type of each element is int[N] in this case.) If it were the other way, than array syntax would be inconsistent with itself. :) Or, we would have to accept that it is inside-out like in C. But of course I understand how it is seen as consistent from C's point of view. :) And this is consistent with static vs dynamic as well because again it's "type and then square brackets": int[1][] a; // A dynamic array of int[1] int[][3] b; // A static array of 3 int[]s Ali
Jun 11 2022
On 6/11/22 00:09, z wrote:I rechecked and it should be `X Y Z` for static array, but `Z Y X` for indexing/dynamic array creating with `new`How so? I wrote the following program: import std.stdio; void main() { enum X = 2; enum Y = 3; enum Z = 4; int[X][Y][Z] s; int[X][Y][] d = new int[X][Y][Z]; pragma(msg, typeof(s)); pragma(msg, typeof(d)); } It outputs the following for the static and the dynamic arrays: int[2][3][4] int[2][3][] Consistent elements, except the static array has a compile-time known length. Ali
Jun 11 2022
On Saturday, 11 June 2022 at 15:01:05 UTC, Ali Çehreli wrote:On 6/11/22 00:09, z wrote:i meant with the syntax in (1), the spec's documentation appears to say they are equivalent in result with `new *type*[X][Y]` form. (1) https://dlang.org/spec/expression#new_multidimensional (3. multiple argument form)I rechecked and it should be `X Y Z` for static array, but `ZY X` forindexing/dynamic array creating with `new`How so?
Jun 11 2022
On 6/11/22 13:36, z wrote:i meant with the syntax in (1), the spec's documentation appears to say they are equivalent in result with `new *type*[X][Y]` form. (1) https://dlang.org/spec/expression#new_multidimensional (3. multiple argument form)Thank you. I see now: The values in parentheses are the lengths from the outermost to the innermost: new int[][][](5, 20, 30) // The equivalent of int[30][20][5] Although, I can see how it had to be that way so that when one used less number of lengths, the syntax always works from outer to inner in that new expression: new int[][][](5) // The equivalent of int[][][5] Ali
Jun 11 2022
On Friday, 10 June 2022 at 17:26:48 UTC, Ali Çehreli wrote:I've written about this multiple times in the past but D's way is consistent for me. That must be because I always found C's syntax to be very illogical on this. [...]I think so too... I think D is very consistent with our feelings. That is, the order in memory is in the form of rows x columns. But yes, in reverse(column x row) when you set it up statically. This sample code working on pointers can be a proof: ```d void main() { enum { Row = 2, Column = 3 } size_t cal = Row * Column * int.sizeof; auto alloc = new ubyte[cal]; size_t m = Column * int.sizeof; int[][] aSlice; foreach (i; 0 .. Row) { size_t n = i * m; aSlice ~= cast(int[])alloc[n .. n + m]; } auto row = 2; auto column = 3; aSlice[row-1][column-1] = 1; // last element assert( *( &aSlice[0][0] // first element pointer + (row * column - 1) ) ); // no error... //If you want to see it with your eyes: import std.stdio; aSlice.writefln!"%-(%-(%s %)\n%)"; } ``` SDB 79
Jun 11 2022
On 6/11/22 04:16, Salih Dincer wrote:I think D is very consistent with our feelings. That is, the order in memory is in the form of rows x columns.Yet, there are no rows or columns because neither D nor C (nor C++) have multip-dimensional arrays. They all have arrays where elements are layed out in memory consecutively. The type of the elements and what they represent is entilery up to the programmer.But yes, in reverse(column x row) when you set it up statically.If you mean we can set up the memory in any way we want, I agree but again, since there are no mult-dimensional arrays, there cannot be the reverse of the order.This sample code working on pointers can be a proof:If it's prooving that elemets are side-by-side, then it's by spec. Here is an example where I have array where each element is a column: import std.stdio; import std.range; import std.algorithm; void main() { // I decide that this array represents // Three rows of two columns. int[][] arr; arr.length = 2; foreach (ref column; arr) { column.length = 3; } setFirstColumn(arr, 1); printArray(arr); } void setFirstColumn(int[][] arr, int value) { // The first element is my first column. arr[0][] = value; } void printArray(int[][] arr) { // Because stdout takes line-by-line, // we print a transposition. arr.transposed.writefln!"%-(%-(%s %)\n%)"; } You may think that the final transposition is a trick. No, it was needed only because stdout takes line-by-line. If I used a library like ncurses, I could have printed my array exactly the way I used it. The point is, there are no multi-dimensional arrays. Programmers use arrays as they need and sometimes the elements are arrays. Ali
Jun 11 2022