## digitalmars.D.learn - Trying to understand multidimensional arrays in D

• Profile Anaysis (51/51) Jan 25 2017 I'm a bit confused by how D does arrays.
• Ivan Kazmenko (32/37) Jan 25 2017 In short, you are right, `int[4][4][]` is a dynamic array of
• Profile Anaysis (17/58) Jan 25 2017 Thanks, knowing the last element is important ; Basically I just
• Ivan Kazmenko (8/19) Jan 26 2017 This means that in `T a[4][5][6]`, the type `T[4][5][6]` is
• Jonathan M Davis via Digitalmars-d-learn (122/127) Jan 25 2017 Like in C/C++, types are mostly read outward from the variable name in D...
• Profile Anaysis (12/18) Jan 25 2017 Thanks. I'll just have to play around with them a bit until it
• Profile Anaysis (23/29) Jan 25 2017 Actually, I think the notation is simply wrong.
• Mike Parker (34/40) Jan 26 2017 No, there's no inconsistence and there's no bug. Shorten things
• Mike Parker (17/17) Jan 26 2017 Sorry. I mistyped some of my examples. Obviously dropped some
• =?UTF-8?Q?Ali_=c3=87ehreli?= (34/37) Jan 29 2017 I don't think using aliases is recommended yet. It can simplify things a...
Profile Anaysis <PA gotacha.com> writes:
```I'm a bit confused by how D does arrays.

I would like to create a array of matrices but I do not seem to
get the correct behavior:

int[][4][4] matrix_history;

What I would like is to have a 4x4 matrix and have a history of
it. Just n 4x4 matrices but each matrix is a fixed size but there
can be an arbitrary(dynamic) number.

I would like, for example,

matrix_history[0] to be the first 4x4 matrix,
matrix_history[1] to be the second 4x4 matrix,
...

and I would, in fact, like to be able to append a matrix like

matrix_history ~= some_4x4matrix.

I try to assign like

matrix_history[total-1] = new int[][](8,8);

or append

matrix_history ~= new int[][](4,4);

but the append fails with

Error: cannot append type int[][] to type int[][4][4]

which is confusing because the type per entry in the matrix
history is of type int[][].

e.g., I could wrap the int[][] in a struct and then just have a
singular array of these matrices and, to me, the logic should be
the same. e.g.,

struct matrix
{
int[4][4] data;
}

then

matrix[] matrix_history.

and

matrix_history ~= new matrix;

so, the logic should be the same between two. This method works
but the more direct method doesn't seem to.

If I do

auto x = matrix_history[0];

x is not a int[4][4] but of type int[4](as reported by the
debugger), which is very confusing.

it seems that the way D indexes multidimensional arrays is not
logical nor consistent from my perspective.

auto x = matrix_history[0] returns an array of size 4.
auto x = matrix_history[0][0] returns an 2d array of size 4x4.
auto x = matrix_history[0][0][0] returns an int(as expected).

does this mean that have

int[][4][4] matrix_history;

backwards?

int[4][4][] matrix_history;

this creates even a more set of problems.

I guess I will have to revert to wrapping the matrix in a struct
to get the natural extension of single arrays unless someone can
clue me in on what is going on.
```
Jan 25 2017
Ivan Kazmenko <gassa mail.ru> writes:
```On Thursday, 26 January 2017 at 01:47:53 UTC, Profile Anaysis
wrote:
does this mean that have

int[][4][4] matrix_history;

backwards?

int[4][4][] matrix_history;

this creates even a more set of problems.

In short, you are right, `int[4][4][]` is a dynamic array of
`int[4][4]`.  In turn, `int[4][4]` is a static length-4 array of
`int[4]`, and that is a static length-4 array of `int`.  It's
quite logical once you learn how to read it: if T is a type, then
T[] is a dynamic array of that type, and T[4] is a static
length-4 array of that type.

So, if I have `int[2][5][7] a;` somewhere, the very last element
is `a[6][4][1]`.  If you are inclined to think in terms of this
difference, the simple rule of thumb would be that the order of
dimensions in the declaration is reversed.

Also, note that if you want to have, for example, a dynamic array
of 5 dynamic arrays of the same length 7 (modeling a C
rectangular array, or a D static array, but with possibility to
change the length of each row, as well as the number of rows),
you would go with
`auto a = new int [] [] (5, 7);` (initialization)
The static array of 5 static arrays of length 7 is still
`int [7] [5] a;` (type declaration)
So the reverse only happens in type declarations.

(On the contrary, declarations in C or C++ looks rather
unintuitive from this perspective: `T a[4][5][6]` is means that
`a` is an array of 4 arrays of 5 arrays of 6 arrays of `T`.  Note
how we have to read left-to-right but then wrap around the string
to get the meaning.)

help:
https://dlang.org/spec/arrays.html

And more in-depth material about array slicing:
http://dlang.org/d-array-article.html

Ivan Kazmenko.
```
Jan 25 2017
Profile Anaysis <PA gotacha.com> writes:
```On Thursday, 26 January 2017 at 02:29:07 UTC, Ivan Kazmenko wrote:
On Thursday, 26 January 2017 at 01:47:53 UTC, Profile Anaysis
wrote:
does this mean that have

int[][4][4] matrix_history;

backwards?

int[4][4][] matrix_history;

this creates even a more set of problems.

In short, you are right, `int[4][4][]` is a dynamic array of
`int[4][4]`.  In turn, `int[4][4]` is a static length-4 array
of `int[4]`, and that is a static length-4 array of `int`.
It's quite logical once you learn how to read it: if T is a
type, then T[] is a dynamic array of that type, and T[4] is a
static length-4 array of that type.

So, if I have `int[2][5][7] a;` somewhere, the very last
element is `a[6][4][1]`.  If you are inclined to think in terms
of this difference, the simple rule of thumb would be that the
order of dimensions in the declaration is reversed.

Thanks, knowing the last element is important ; Basically I just
need to know the proper index. For me, having the array declared
in symbolic form that matches the indexing, like in C/C++, is
quicker, easier to remember, and harder to forget. I don't really
care too much beyond that. They could be declared any way... but
I find myself getting confused in D because of little things like
this that don't carry over while almost everything else is.

Also, note that if you want to have, for example, a dynamic
array of 5 dynamic arrays of the same length 7 (modeling a C
rectangular array, or a D static array, but with possibility to
change the length of each row, as well as the number of rows),
you would go with
`auto a = new int [] [] (5, 7);` (initialization)
The static array of 5 static arrays of length 7 is still
`int [7] [5] a;` (type declaration)
So the reverse only happens in type declarations.

(On the contrary, declarations in C or C++ looks rather
unintuitive from this perspective: `T a[4][5][6]` is means that
`a` is an array of 4 arrays of 5 arrays of 6 arrays of `T`.
Note how we have to read left-to-right but then wrap around the
string to get the meaning.)

lol, I don' tknow what the last sentence means. wrap around the
string? Do you mean look at the variable?

For me the interpretation above is the most logical because it is
a sequential operation in my mind, if you will. x of y of z and
the chain can be cut off anywhere and the interpretation still be
the same.

Since I am a native speaker of English, which is a left to right
language, it just makes sense. I, am, of coursed biased because I
started with C/C++ rather than D.

help:
https://dlang.org/spec/arrays.html

And more in-depth material about array slicing:
http://dlang.org/d-array-article.html

Ivan Kazmenko.

```
Jan 25 2017
Ivan Kazmenko <gassa mail.ru> writes:
```On Thursday, 26 January 2017 at 05:20:07 UTC, Profile Anaysis
wrote:
(On the contrary, declarations in C or C++ looks rather
unintuitive from this perspective: `T a[4][5][6]` is means
that `a` is an array of 4 arrays of 5 arrays of 6 arrays of
`T`.  Note how we have to read left-to-right but then wrap
around the string to get the meaning.)

lol, I don' tknow what the last sentence means. wrap around the
string? Do you mean look at the variable?

For me the interpretation above is the most logical because it
is a sequential operation in my mind, if you will. x of y of z
and the chain can be cut off anywhere and the interpretation
still be the same.

This means that in `T a[4][5][6]`, the type `T[4][5][6]` is
spread on both sides of the variable name `a`.  In the
interpretation,
"`a` is an array of 4 arrays of 5 arrays of 6 arrays of `T`",
note that 4, 5 and 6 are from the right side but T is from the
left side.  That's what I meant by wrap around.
```
Jan 26 2017
Jonathan M Davis via Digitalmars-d-learn writes:
```On Thursday, January 26, 2017 01:47:53 Profile Anaysis via Digitalmars-d-
learn wrote:
I'm a bit confused by how D does arrays.

I would like to create a array of matrices but I do not seem to
get the correct behavior:

int[][4][4] matrix_history;

Like in C/C++, types are mostly read outward from the variable name in D. In
both C/C++ and D,

int* foo;

is a pointer to an int. It's read outward from the variable name, so you get
the pointer and then what it points to. Similarly,

int** foo;

is a pointer to a pointer to an int. In C/C++, a static array would be
written like

int arr[4][3];

and again, it's read outward from the type. It's a static array of 4 static
arrays of 3 ints. This gets increasingly confusing as the types get more
complicated, but it's critical for understanding how function pointers are
written in C/C++. For D, it's a lot less critical, because we have a cleaner
function pointer declaration syntax, but the same basic rules mostly apply
(const, immutable, and shared is where they start breaking the rules a bit,
but they're pretty straightforward and consistent with just pointers and
arrays). That

int arr[4][3];

in C/C++ can then be accessed like so

arr[3][2] = 5;

and that would get the 3rd element in the first array and the second element
in the second array without exceeding the bounds of the array. D follows the
same declaration rules except that it has the array bounds all on the
left-hand side of the variable. So, in C/C++, you have

int arr[4][3];

whereas in D, the same array would be

int[3][4] arr;

and you would still access it like so

arr[3][2] = 5;

without exceeding the bounds of the array, whereas

arr[2][3] = 5;

_would_ exceed the bounds of the array, because the second array has 3
elements in it, and that asks for the 4th.

This tends to be very confusing at first, because most folks usually expect
the indices to always in the same order, when they're not. They are so long
as the sizes is always on the right-hand side, which occurs with dynamic
arrays, but in D, static arrays go on the left. C/C++ would have the exact
same ordering problem as D if it put the sizes on the left, because it uses
basically the same rules for how types are written. But they put it on the
right, separating from the type, which makes the indices clearer but splits
the type in two. So, both approaches have their pros and cons.

In any case, the idea that the type is read outward from the variable name
extends to types in general. In particular, if you have

int[][4][4] arr;

as in your example, you have a static array of 4 static arrays of 4 dynamic
arrays of int. You can append to the innermost static array

arr[3][3] ~= [1, 2, 3];

but you can't append to arr. If you want a dynamic array of static arrays,
then you need to do

int[4][4][] arr;

Then you can append a 4x4 static array to arr. However, your attempts at
creating a static array were not actually creating static arrays.

auto arr = new int[4];

and

auto arr = new int[](4);

both allocate a dynamic array of length 4. The code semantics are identical.
However, once we go beyond one dimension, it starts mattering - and getting
confusing. Take this

auto arr = new int[][](4, 5);
static assert(is(typeof(arr) == int[][]));
assert(arr.length == 4);

arr is a dynamic array of length 4 that contains dynamic arrays of length 5
of int. This on the other hand

auto arr = new int[4][](5);
static assert(is(typeof(arr) == int[4][]));
assert(arr.length == 5);

makes it so that arr is dynamic array of length 5 that contains static
arrays of length 4 of int.

auto arr = new int[4][5];
static assert(is(typeof(arr) == int[4][]));
assert(arr.length == 5);

has the exact same semantics. So, the right-most number is always the length
of the outer, dynamic array, and whether the interior is more dynamic arrays
or static arrays depends on whether the numbers are between the brackets or
the parens.

Another thing to note is that when you have int[][], it is a dynamic array,
whereas int[4][4] is a static array. So, whenever you see the compiler give
you the type int[][], it's talking about a dynamic array, not a static
array. The numbers have to be there for it to be a static array. When
looking at the type of an array (as opposed to a expression using new),
numbers between the subscripts mean a static array, whereas a lack of
numbers means a dynamic array, and the type of a dynamic array does not
change depending on its length.

Also, even if you had declared matrix_history correctly

int[4][4][] matrix_history;

this code would be wrong

matrix_history ~= new int[][](4,4);

because int[][](4, 4) is allocating a dynamic array of dynamic arrays of
ints, not a static array of 4 static arrays of 4 ints.

In addition, AFAIK, you can't just new up a static array of 4 static arrays
of int. You can new up dynamic arrays but not static arrays. The static
arrays need to be in something to be on the heap. But that's not really what
you wanted anyway. Take a simpler example.

int[] arr;
arr ~= 5;
arr ~= 42;

Note that you're not newing up the 5 or the 42. If you were newing up the
ints, you'd actually have

int*[] arr;

So, with your matrix_history, when you append a static array to it, you're
just appending a value - either a variable or an array literal. e.g.

int[4][4] sa;
matrix_history ~= sa;

or

matrix_history ~= [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]];

Well, hopefully that's not too much information at once, and hopefully it

https://dlang.org/spec/arrays.html
http://ddili.org/ders/d.en/arrays.html
http://dlang.org/d-array-article.html

to try and better understand arrays in general. The last one applies more to
dynamic arrays, but depending on your current understanding, it could really
help you figure out what's going on (be warned though that it does not use
the official terminology; per the language spec, int[] is a dynamic array no
matter what memory it points to, and there is no special term for the
GC-allocated buffer that the dynamic array points to when you use new int[],
whereas that article refers to int[] as a slice and the GC-allocated buffer
that you get with new int[] as the dynamic array; however, aside from that
problem with the terminology, it's a fantastic article and should be quite
enlightening).

- Jonathan M Davis
```
Jan 25 2017
Profile Anaysis <PA gotacha.com> writes:
```On Thursday, 26 January 2017 at 03:02:32 UTC, Jonathan M Davis
wrote:
On Thursday, January 26, 2017 01:47:53 Profile Anaysis via
Digitalmars-d- learn wrote:
[...]

Like in C/C++, types are mostly read outward from the variable
name in D. In both C/C++ and D,

[...]

Thanks. I'll just have to play around with them a bit until it
sinks in. I think my problem was declaring them wrong which would

I am using static arrays because the size of the matrix is fixed.
I need to allocate them though because that is what my
matrix_history contains.

I guess I can do that with new int[n][n] type of thing? (I think
I tried that before.

Anyways, probably would work fine now but I already move don to
wrapping it in a struct. It provides more flexibility in my case.
```
Jan 25 2017
Jonathan M Davis via Digitalmars-d-learn writes:
```On Thursday, January 26, 2017 05:44:04 Profile Anaysis via Digitalmars-d-
learn wrote:
I am using static arrays because the size of the matrix is fixed.
I need to allocate them though because that is what my
matrix_history contains.

If I understood correctly, you want a dynamic array of static arrays where
the static array is therefore an entry in your "matrix history." That does
not require that you allocate a static array. It just requires that you
allocate the dynamic array of static arrays. For instance, if you had an
integer instead of a matrix, you would have something like

int[] arr;

and when you appended to it, you would just append the value. e.g.

arr ~= 42;
arr ~= 77;
arr ~= 9;

No allocation of the values is required. The dynamic array may very well do
some reallocating to fit the new values (depending on its current capacity),
but the values themselves are not allocated. So, if you have a dynamic array
of static arrays

int[4][4][] arr;

then you just append each static array. e.g.

int[4][4] value;
// fill in value...

arr ~= value;

or

arr ~= [[9, 9, 9, 9], [7, 7, 7, 7], [2, 2, 2, 2], [3, 3, 3, 3]];

Again. You're not allocating the values that you're appending at all. At
most, the dynamic array ends up being reallocated to make room for more
elements.

- Jonathan M Davis
```
Jan 26 2017
Profile Anaysis <PA gotacha.com> writes:
```On Thursday, 26 January 2017 at 03:02:32 UTC, Jonathan M Davis
wrote:
On Thursday, January 26, 2017 01:47:53 Profile Anaysis via
Digitalmars-d- learn wrote:
[...]

Like in C/C++, types are mostly read outward from the variable
name in D. In both C/C++ and D,

[...]

Actually, I think the notation is simply wrong.

// Matrix order testing
auto x = new int[][][][](1,2,3,4);
auto y = new int[1][2][][](3,4);

for(int i = 0; i < 1; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 3; k++)
for(int l = 0; l < 4; l++)
{
x[i][j][k][l] = i*j*k*l;
//x[l][k][j][i] = i*j*k*l;

//y[i][j][k][l] = i*j*k*l;
//y[l][k][j][i] = i*j*k*l;
y[k][l][j][i] = i*j*k*l;
}

It is inconsistent with dynamic arrays and mixing them creates a
mess in the order of indices.

I best someone was asleep at the wheel when programming the code
for static arrays. (probably someone different than who
programmed the dynamic arrays)

This is a bug IMO.(unfortunately one that can't be fixed ;/)
```
Jan 25 2017
Mike Parker <aldacron gmail.com> writes:
```On Thursday, 26 January 2017 at 05:50:03 UTC, Profile Anaysis
wrote:

It is inconsistent with dynamic arrays and mixing them creates
a mess in the order of indices.

I best someone was asleep at the wheel when programming the
code for static arrays. (probably someone different than who
programmed the dynamic arrays)

This is a bug IMO.(unfortunately one that can't be fixed ;/)

No, there's no inconsistence and there's no bug. Shorten things
down a bit:

```
auto x = new int[][](3,4);
auto y = new int[3][](4);
writefln("%s, %s", x[0].length, y[0].length);
```
This will print 4, 3. Why?

auto a = int[](4);

In this case, a is an array of int. The allocation makes space
for 4 values of type int.

auto b = int[][](4);

Here, b is an array of int[]. The allocation makes space for
values of type int[].

The following are the equivalent declarations for static arrays:

auto c = int[4];
auto d = int[][4];

In other words  int[][4] is the static equivalent of new
int[][](4).

Following from that:

auto e = new int[][](4, 3);

This creates an array of 4 values of type int[], each of which is
an array that holds 3 values of type int. The static equivalent:

auto f = int[3][4];

So based on that, you should be able to see that the problem is
not in the implementation of static arrays in D, but a mismatch

auto x = new int[][][][](1,2,3,4);
auto y = new int[1][2][][](3,4); // Does not match declaration of
x

To get what you want, change the declaration of x:

auto x = new int[][][][](4, 3, 2, 1);
```
Jan 26 2017
Mike Parker <aldacron gmail.com> writes:
```Sorry. I mistyped some of my examples. Obviously dropped some
news:

auto a = new int[](4);
auto b = new int[][](4);

And the static arrays should be:
int[4] c;
int[][4] d;

And I would also like managed to overlook there is no static
array in sight here:

auto y = new int[1][2][][](3,4);

The 1 and 2 are not creating static arrays. They are dynamic
arrays. The following are exactly the same:

auto a1 = new int[](2);
auto a2 = new int[2];

The syntax in a2 is the original syntax for allocating space for
dynamic arrays. The () was added later.

```
Jan 26 2017
=?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
```On 01/25/2017 05:47 PM, Profile Anaysis wrote:

a 4x4 matrix and have a history of it. Just
n 4x4 matrices but each matrix is a fixed size but there can be an
arbitrary(dynamic) number.

I don't think using aliases is recommended yet. It can simplify things a
lot:

import std.stdio;

alias Row = int[4];
alias Matrix = Row[4];
alias History = Matrix[];

Row makeRow(int value) {
Row row;
row = value;    // Special array syntax; all elements are now 'value'
return row;
}

Matrix makeMatrix() {
Matrix matrix;
foreach (int i, ref row; matrix) {
row = makeRow(i + 1);
}
return matrix;
}

void main() {
History history;
foreach (i; 0..3) {
history ~= makeMatrix();
}
writeln(history);
}

As others have said, D's array definition is natural because unlike C's
inside-out (or is that outside-in?) syntax, it follows from the alias
syntax. Replacing History inside main with Matrix[], etc.:

History history;    // is the same as:
Matrix[] history;   // is the same as:
Row[4][] history;   // is the same as:
int[4][4][] history;

Ali
```
Jan 29 2017