Jump to page: 1 2
Thread overview
a struct as an multidimensional array index
Jun 10, 2022
Chris Katko
Jun 10, 2022
Ali Çehreli
Jun 10, 2022
Ali Çehreli
Jun 10, 2022
Ali Çehreli
Jun 10, 2022
H. S. Teoh
Jun 10, 2022
z
Jun 10, 2022
Ali Çehreli
Jun 11, 2022
Chris Katko
Jun 11, 2022
z
Jun 11, 2022
Ali Çehreli
Jun 11, 2022
z
Jun 11, 2022
Ali Çehreli
Jun 11, 2022
Salih Dincer
Jun 11, 2022
Ali Çehreli
June 10, 2022

Is it somehow possible to use a struct as a [multidimensional] array index:


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.

June 10, 2022
On 6/10/22 01:08, Chris Katko wrote:
> Is it somehow possible to use a struct as a [multidimensional] array index:

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


June 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
June 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

June 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:


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 :

    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.

June 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

June 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

June 11, 2022
On Friday, 10 June 2022 at 17:26:48 UTC, Ali Çehreli wrote:
> 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

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.
June 11, 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:

>

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 :

     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

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.

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.

June 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:

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

« First   ‹ Prev
1 2