www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Differing semantics between multidimensional fixed-length array and

reply "Nicholas Smith" <nmsmith65 gmail.com> writes:
Hello there,

So I noticed something about the semantics of multidimensional 
fixed-length array vs slice initialization:

Code:

int[2][3] array;
writeln(array.length, " ", array[0].length);
int[][] slice = new int[][](2, 3);
writeln(slice.length, " ", slice[0].length);

Output:

3 2
2 3

So it seems that int[2][3] means "an array of 3 int arrays of 
length 2", while new int[][](2, 3) means "an array of 2 int 
arrays of length 3".

This seems like a direct conflict of semantics, and I was 
wondering whether this was an intentional design choice, or an 
oversight. Can anyone explain reasoning behind this?
Mar 31 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Nicholas Smith:

 Can anyone explain reasoning behind this?
To help confuse you a little more, this syntax is also allowed in D: int array[2][3]; Plus of course a mixed D/C (http://d.puremagic.com/issues/show_bug.cgi?id=5807 ): int[2] array[3]; Mixing fixed size arrays with dynamic ones is interesting: auto array1 = new int[3][](2); auto array2 = new int[][3][](2); D array definition syntax is one of the cases where I think the Ada/ObjectPascal syntax is better. Bye, bearophile
Mar 31 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/31/2013 06:36 PM, Nicholas Smith wrote:> Hello there,
 So I noticed something about the semantics of multidimensional
 fixed-length array vs slice initialization:

 Code:

 int[2][3] array;
Obviously, like C and C++, D does not have multi-dimensional arrays but D's array of array syntax is consistent. When we say A[3] a; we mean three As. Replacing A with an array gives us this: int[2][3] a; Now we mean three int[2]s. This is consistent, because 'int[2]' in there itself follows the same syntax.
 writeln(array.length, " ", array[0].length);
 int[][] slice = new int[][](2, 3);
That is very similar to a function API. It would make sense that the outer-most index came first if it truly were a function.
 writeln(slice.length, " ", slice[0].length);

 Output:

 3 2
 2 3

 So it seems that int[2][3] means "an array of 3 int arrays of length 2",
 while new int[][](2, 3) means "an array of 2 int arrays of length 3".

 This seems like a direct conflict of semantics, and I was wondering
 whether this was an intentional design choice, or an oversight. Can
 anyone explain reasoning behind this?
Ali
Mar 31 2013
next sibling parent reply "Nicholas Smith" <nmsmith65 gmail.com> writes:
Ali, thanks for the justification. It makes enough sense, and at 
least int[][](2, 3) matches the order in which you access the 
elements.

I agree with Bearophile though that the syntax is very messy when 
you're mixing array types and pre/postfix declarations. If you 
weren't shooting for C family syntax I'm sure array declarations 
could be handled more gracefully.
Apr 01 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 1 April 2013 at 08:42:45 UTC, Nicholas Smith wrote:
 Ali, thanks for the justification. It makes enough sense, and 
 at least int[][](2, 3) matches the order in which you access 
 the elements.

 I agree with Bearophile though that the syntax is very messy 
 when you're mixing array types and pre/postfix declarations. If 
 you weren't shooting for C family syntax I'm sure array 
 declarations could be handled more gracefully.
I think the idea is that a "new" syntax was introduced, which, arguably, is better. At the same time, the old syntax was kept, for compatibility. Keeping both makes things complicated, and *mixing* both, well that's just evil. IMO, it is a convenient and simple syntax if you decide to keep it that way. Just cause there are ways to make it complicated doesn't mean it's a good idea to do it that way. Just keep things consistent with what you are doing: Use new style, and only new style in D code. Use old style (and only old style), when interfacing with a C-api, or if the code was ported from C.
Apr 01 2013
parent reply "ixid" <nuaccount gmail.com> writes:
On Monday, 1 April 2013 at 09:30:23 UTC, monarch_dodra wrote:
 On Monday, 1 April 2013 at 08:42:45 UTC, Nicholas Smith wrote:
 Ali, thanks for the justification. It makes enough sense, and 
 at least int[][](2, 3) matches the order in which you access 
 the elements.

 I agree with Bearophile though that the syntax is very messy 
 when you're mixing array types and pre/postfix declarations. 
 If you weren't shooting for C family syntax I'm sure array 
 declarations could be handled more gracefully.
I think the idea is that a "new" syntax was introduced, which, arguably, is better. At the same time, the old syntax was kept, for compatibility. Keeping both makes things complicated, and *mixing* both, well that's just evil. IMO, it is a convenient and simple syntax if you decide to keep it that way. Just cause there are ways to make it complicated doesn't mean it's a good idea to do it that way. Just keep things consistent with what you are doing: Use new style, and only new style in D code. Use old style (and only old style), when interfacing with a C-api, or if the code was ported from C.
How can you call the new syntax better? You assign arrays' lengths in the opposite to that that you access them. It's a horrible design mistake.
Apr 02 2013
parent reply "Chris Cain" <clcain uncg.edu> writes:
On Wednesday, 3 April 2013 at 01:30:19 UTC, ixid wrote:
 How can you call the new syntax better? You assign arrays' 
 lengths in the opposite to that that you access them. It's a 
 horrible design mistake.
Unfortunately, I have to agree that the new syntax is better. int[5][6] is confusing as a type because it's read from right to left, but it makes much more sense than int[6][5]. Consider how you would read the "old style" It's a 6-long array of 5-long arrays of int. So, the new style is simply read from right to left. But using the other way ... it's read from the center to right, and finally to the front. How about throwing AAs into the mix? int[string][5][6] What would that mean? The old style would be incredibly confusing. It'd be an associative array mapping strings to 5-long arrays of 6-long arrays of ints. Right? Plus consider this: alias Dict = int[string] Dict[5][6] vs int[string][5][6] Using the new way, these two are the same. Using the "old style" ... they're not. Really though, bearophile has it right. C (and, D, transitively) made a huge mistake in type declarations. They ought to be read from left to right (like Pascal). C is crazy in that they've designed it so you read types in a spiral pattern. What's a int*? It's a pointer to an int. Why isn't it a *int, then? How about [5]int? It's a 5-long array of int. [5][6]int ... It's a 5-long array of 6-long arrays of integers. And so on.
Apr 02 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Chris Cain:

 Really though, bearophile has it right. C (and, D, 
 transitively) made a huge mistake in type declarations. They 
 ought to be read from left to right (like Pascal). C is crazy 
 in that they've designed it so you read types in a spiral 
 pattern.
Maybe you are talking more about Go here. I was talking more about Ada here :-) Bye, bearophile
Apr 02 2013
prev sibling next sibling parent reply "ixid" <nuaccount gmail.com> writes:
On Wednesday, 3 April 2013 at 02:28:55 UTC, Chris Cain wrote:
 On Wednesday, 3 April 2013 at 01:30:19 UTC, ixid wrote:
 How can you call the new syntax better? You assign arrays' 
 lengths in the opposite to that that you access them. It's a 
 horrible design mistake.
Unfortunately, I have to agree that the new syntax is better. int[5][6] is confusing as a type because it's read from right to left, but it makes much more sense than int[6][5]. Consider how you would read the "old style" It's a 6-long array of 5-long arrays of int. So, the new style is simply read from right to left. But using the other way ... it's read from the center to right, and finally to the front. How about throwing AAs into the mix? int[string][5][6] What would that mean? The old style would be incredibly confusing. It'd be an associative array mapping strings to 5-long arrays of 6-long arrays of ints. Right? Plus consider this: alias Dict = int[string] Dict[5][6] vs int[string][5][6] Using the new way, these two are the same. Using the "old style" ... they're not. Really though, bearophile has it right. C (and, D, transitively) made a huge mistake in type declarations. They ought to be read from left to right (like Pascal). C is crazy in that they've designed it so you read types in a spiral pattern. What's a int*? It's a pointer to an int. Why isn't it a *int, then? How about [5]int? It's a 5-long array of int. [5][6]int ... It's a 5-long array of 6-long arrays of integers. And so on.
I wasn't arguing for the old style, the new declarations should have read from left to right so [6][5][string]int and then you access the elements in the same order that you assigned them, that seems far less confusing and leaves less room for sleepy mistakes. It seems like a pointless mental overhead so have to keep swapping the order of your arguments.
Apr 03 2013
parent "Chris Cain" <clcain uncg.edu> writes:
On Wednesday, 3 April 2013 at 15:44:52 UTC, ixid wrote:
 I wasn't arguing for the old style, the new declarations should 
 have read from left to right so [6][5][string]int and then you 
 access the elements in the same order that you assigned them, 
 that seems far less confusing and leaves less room for sleepy 
 mistakes. It seems like a pointless mental overhead so have to 
 keep swapping the order of your arguments.
Sorry for the misunderstanding, then. But to be fair, I'm sure that monarch_dodra meant that the new style is better than the old style, so my inference that you disagreeing with him saying the new style is better than the old style meant that you thought the old style was better isn't entirely unfounded. I do have to agree that an even better syntax would have been to read types from left to right. However, that ship has sailed long ago (plus, I think the decision was made to make it more C-like in nature, which has its benefits as well).
Apr 03 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/02/2013 07:28 PM, Chris Cain wrote:> On Wednesday, 3 April 2013 at 
01:30:19 UTC, ixid wrote:

 What's a int*? It's a pointer to an int. Why isn't it a *int, then?
I wonder whether it would complicate syntax? (But * already has so many meanings that maybe that would not be too bad.)
 How about [5]int? It's a 5-long array of int. [5][6]int ... It's a 
5-long
 array of 6-long arrays of integers. And so on.
[5] is already an array literal of one element. I would have to be an exception to the current syntax. Still confusing... Ali
Apr 03 2013
parent "Chris Cain" <clcain uncg.edu> writes:
On Wednesday, 3 April 2013 at 15:56:31 UTC, Ali Çehreli wrote:
 I wonder whether it would complicate syntax? (But * already has 
 so many meanings that maybe that would not be too bad.)
I doubt it, but maybe. Plenty of languages exist that do a left-to-right reading of types and they seem to work out okay. Plus, reversing the order doesn't seem like it'd make a difference.
 How about [5]int? It's a 5-long array of int. [5][6]int ...
It's a 5-long
 array of 6-long arrays of integers. And so on.
[5] is already an array literal of one element. I would have to be an exception to the current syntax. Still confusing...
It's no different than the current syntax from that regard. An type named int followed by an array literal of one element is no less confusing than an array literal of one element followed by a type named int. It has an overloaded meaning in both cases. That said, many other languages say things like "array (0..5) of Integer" and such, which removes that overloaded meaning, but it has the problem of being a bit too verbose (IMO). It does make a difference if you're reading/writing many thousands of lines of code. Heck, even the current syntax is verbose enough to warrant type inference in many cases.
Apr 03 2013
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 4/1/13, Ali =C7ehreli <acehreli yahoo.com> wrote:
 Obviously, like C and C++, D does not have multi-dimensional arrays but
 D's array of array syntax is consistent.
Does not have *rectangular* multi-dimensional arrays. :)
Apr 01 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 1 April 2013 at 10:52:34 UTC, Andrej Mitrovic wrote:
 On 4/1/13, Ali Çehreli <acehreli yahoo.com> wrote:
 Obviously, like C and C++, D does not have multi-dimensional 
 arrays but
 D's array of array syntax is consistent.
Does not have *rectangular* multi-dimensional arrays. :)
Actually, D does have partial support for multidimensional rectangular arrays: int[5][] rect = new int[5][](20); ...and there. A dynamic rectangular array of 20 by 5. Also, D supports 1-line initialization for jagged rectangular arrays, which is very convenient (but somewhat misleading in what it does). You can't do that in C++, due to the initialization syntax. That said, in C++, if you use std::array ("semi-built-in"), then you can do that. Further more, you can also allocate a single static array on the heap with it. You can't do that with D (at least, there is no standard container that emulates std::array, which I think is a shame, it's very useful and efficient). In any case, none of these languages support native rectangular arrays of arbitrary sizes (let alone dimension). And none offer a built-in container to do it either (though I think boost has multi-dim something, but it requires a phd to use...)
Apr 01 2013