www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Multi dimensional array question.

reply dcoder <gtdegamo yahoo.com> writes:
Hello.

I'm wondering why in D if you declare a fixed multi dimensional array, you
have to reverse the index order to access an element.  I know it has something
to do with how tightly [] bind, but the consequence is that it seems so
different to other languages, it makes it error prone.  So here's some code
that compiles and works:



import std.stdio;

int main() {
  int[3][5] marr;
  int i = 0;

  foreach( j, ref a; marr) {
    writefln( "%s: a.length = %s", j, a.length);
    foreach( ref v; a) {
      v = i++;
    }
  }


  /* This doesn't work.  marr[0][>=3] is out of bounds!!

     writefln( "marr[0][0] = %s", marr[0][0]);
     writefln( "marr[0][1] = %s", marr[0][1]);
     writefln( "marr[0][2] = %s", marr[0][2]);
     writefln( "marr[0][3] = %s", marr[0][3]);
     writefln( "marr[0][4] = %s", marr[0][4]);


     writefln( "marr[1][0] = %s", marr[1][0]);
     writefln( "marr[1][1] = %s", marr[1][1]);
     writefln( "marr[1][2] = %s", marr[1][2]);
     writefln( "marr[1][3] = %s", marr[1][3]);
     writefln( "marr[1][4] = %s", marr[1][4]);
  */


  writefln( "marr[0][0] = %s", marr[0][0]);
  writefln( "marr[1][0] = %s", marr[1][0]);
  writefln( "marr[2][0] = %s", marr[2][0]);
  writefln( "marr[3][0] = %s", marr[3][0]);
  writefln( "marr[4][0] = %s", marr[4][0]);
  writefln( "");

  writefln( "marr[0][1] = %s", marr[0][1]);
  writefln( "marr[1][1] = %s", marr[1][1]);
  writefln( "marr[2][1] = %s", marr[2][1]);
  writefln( "marr[3][1] = %s", marr[3][1]);
  writefln( "marr[4][1] = %s", marr[4][1]);
  writefln( "");

  writefln( "marr[0][2] = %s", marr[0][2]);
  writefln( "marr[1][2] = %s", marr[1][2]);
  writefln( "marr[2][2] = %s", marr[2][2]);
  writefln( "marr[3][2] = %s", marr[3][2]);
  writefln( "marr[4][2] = %s", marr[4][2]);
  writefln( "");

  return 0;
}


Anyways, perhaps I am doing something wrong, or I have been writing too much C
code.  What are your thoughts?
Jul 11 2010
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
dcoder <gtdegamo yahoo.com> wrote:

 I'm wondering why in D if you declare a fixed multi dimensional array,  
 you
 have to reverse the index order to access an element.  I know it has  
 something
 to do with how tightly [] bind, but the consequence is that it seems so
 different to other languages, it makes it error prone.
The idea is that T[] is an array of T, for any T. if T == int[3], T[] would be int[3][]. Also, for indexing, given T[] arr. arr[i] peels off the first layer, giving you a T. If arr[i] used the first set of brackets, generic functions would be thoroughly borked, as a T passed to a template as int[3] would lead to different indexing from a T of int. -- Simen
Jul 11 2010
prev sibling next sibling parent BCS <none anon.com> writes:
Hello dcoder,

 Hello.
 
 I'm wondering why in D if you declare a fixed multi dimensional array,
 you have to reverse the index order to access an element.  
When declaring an array, the base type is getting wrapped. When using an array, the base types get unwrapped. Because both forms place the [] as a subfix and in both cases the sub-type/expression needs to be contiguous it end up the way it is. alias int[5] T T[7] aa; T a = aa[6]; int v = a[4]; or (int[5])[7] aa; int v = (aa[6])[4]; -- ... <IXOYE><
Jul 11 2010
prev sibling parent reply Heywood Floyd <soul8o8 gmail.com> writes:
This had me crazy. I ended up putting the brackets on the variable, like

  int marr[3][5];

then it worked like

  marr[2][4] = 9;
Jul 12 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Heywood Floyd:
 This had me crazy. I ended up putting the brackets on the variable, like
   int marr[3][5];
 then it worked like
   marr[2][4] = 9;
That's present only for compatibility with C syntax, this means that you can use it to perform a quicker port of C code to D, but you are supposed to later convert it to D-style array definitions. See also: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=113185 Bye, bearophile
Jul 12 2010
parent reply Heywood Floyd <soul8o8 gmail.com> writes:
bearophile Wrote:

 Heywood Floyd:
 This had me crazy. I ended up putting the brackets on the variable, like
   int marr[3][5];
 then it worked like
   marr[2][4] = 9;
That's present only for compatibility with C syntax, this means that you can use it to perform a quicker port of C code to D, but you are supposed to later convert it to D-style array definitions. See also: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=113185 Bye, bearophile
Aha, good to know! Thanks! (So this might go away in the future? Or require a -cstyle compile flag?) *** I have a feeling this "backwards"-array stuff is gonna be one of the things my brain will repel for as long as it can. To me, it seems equal to saying "you declare a function like: void foo(string name, int age){ //... } And then call it by doing foo(90,"Benny") and this makes sense because the arguments are actually pushed on the stack in reverse at runtime, so they arrive in the correct order in the function. And this is especially important with tuples." or something. Ok, I understand this has some deep purpose that I still don't understand, I'm just, yeah. *tear* (Although this is way out of my league: For instance, if a T is an int[3][4], then why can't T[string] be a int[string][3][4], and be accessed with arr["a"][2][3]? Seems just like a matter of taste?) /HF PS. I was not the thread creator. I just used the creator's terminology to "stay on topic". Maybe too on topic : ) Not important really. Sorry for the confusion. DS.
Jul 12 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Heywood Floyd:
 Aha, good to know! Thanks!
 (So this might go away in the future? Or require a -cstyle compile flag?)
It's just an idea of mine, my weight in D design is near zero, and Walter doesn't love warnings. I don't know if C-style array definitions will ever go away from D, don't hold your breath :-) But in D code I suggest to replace them with D-style array definitions when possible.
 PS. I was not the thread creator. I just used the creator's terminology to
"stay on topic". Maybe too on topic : ) Not important really. Sorry for the
confusion. DS.
I am sorry, my error :-( Bye, bearophile
Jul 12 2010
prev sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Mon, 12 Jul 2010 17:23:16 -0400, Heywood Floyd wrote:

 bearophile Wrote:
 
 Heywood Floyd:
 This had me crazy. I ended up putting the brackets on the variable,
 like
   int marr[3][5];
 then it worked like
   marr[2][4] = 9;
That's present only for compatibility with C syntax, this means that you can use it to perform a quicker port of C code to D, but you are supposed to later convert it to D-style array definitions. See also: http://www.digitalmars.com/webnews/newsgroups.php?
art_group=digitalmars.D&article_id=113185
 
 Bye,
 bearophile
Aha, good to know! Thanks! (So this might go away in the future? Or require a -cstyle compile flag?) *** I have a feeling this "backwards"-array stuff is gonna be one of the things my brain will repel for as long as it can. To me, it seems equal to saying "you declare a function like: void foo(string name, int age){ //... } And then call it by doing foo(90,"Benny") and this makes sense because the arguments are actually pushed on the stack in reverse at runtime, so they arrive in the correct order in the function. And this is especially important with tuples." or something. Ok, I understand this has some deep purpose that I still don't understand, I'm just, yeah. *tear* (Although this is way out of my league: For instance, if a T is an int[3][4], then why can't T[string] be a int[string][3][4], and be accessed with arr["a"][2][3]? Seems just like a matter of taste?)
But then arrays would be different from all other types! If you have an array of 3 Ts, that is written T[3], regardless of what T is. Now consider these two cases: A. T is an int. Then T[3] becomes int[3]. B. T is an int[string]. Then T[3] becomes int[string][3]. In case A, the first element of the array is accessed like this: int[3] a; int firstA = a[0]; Since a is an array of int, firstA is of course an int. But then, since b is an array of int[string], we have int[string][3] b; int[string] firstB = b[0]; If we again want to access element "foo" of the associative array which is firstB, we write firstB["foo"]. And so we have the following three ways to get to that element, which *must* be equivalent because that's how the language is defined: // Using firstB as an intermediate step int[string] firstB = b[0]; int x = firstB["foo"]; // Drop the intermediate variable firstB int x = (b[0])["foo"]; // Drop the redundant parentheses int x = b[0]["foo"]; So you see, it can't be any other way than the way it is. :) -Lars
Jul 13 2010
parent reply Heywood Floyd <soul8o8 gmail.com> writes:
Lars T. Kyllingstad Wrote:

 
 But then arrays would be different from all other types!  If you have an 
 array of 3 Ts, that is written T[3], regardless of what T is.  Now 
 consider these two cases:
 
    A. T is an int.  Then T[3] becomes int[3].
 
    B. T is an int[string].  Then T[3] becomes int[string][3].
 
 In case A, the first element of the array is accessed like this:
 
    int[3] a;
    int firstA = a[0];
 
 Since a is an array of int, firstA is of course an int.
 
 But then, since b is an array of int[string], we have
 
    int[string][3] b;
    int[string] firstB = b[0];
 
 If we again want to access element "foo" of the associative array which 
 is firstB, we write firstB["foo"].  And so we have the following three 
 ways to get to that element, which *must* be equivalent because that's 
 how the language is defined:
 
    // Using firstB as an intermediate step
    int[string] firstB = b[0];
    int x = firstB["foo"];
 
    // Drop the intermediate variable firstB
    int x = (b[0])["foo"];
 
    // Drop the redundant parentheses
    int x = b[0]["foo"];
 
 So you see, it can't be any other way than the way it is. :)
 
 -Lars
Thank you for the elaborate answer! When you put it like that, it does make sense. But I'm sorry. I refuse. The reason I refuse is those examples are void of any higher semantic meaning. Once we add a semantic meaning, it simply becomes backwards: int[MAX_WIDTH][MAX_HEIGHT] map2d; map2d[x][y] = 9; // Wrong! At least in my head, this is cognitive dissonance. To me, the language acts as if it's low-level semantics outweighs my high-level semantics and I should correct my thinking for that. I refuse! Seems to me it could just as well work as: int[string][3] b; int[3] firstB = b["foo"]; int i = firstB[0]; int j = (b["foo"])[0]; int k = b["foo"][0]; But I feel like I'm the only one feeling this, so I'll just let it go and hope my dear C-style arrays stay in :) BR /HF PS. Never thought I'd find a reason to love C.. DS.
Jul 14 2010
next sibling parent reply Jonathan M Davis <jmdavisprog gmail.com> writes:
On Wednesday, July 14, 2010 13:57:13 Heywood Floyd wrote:
 
 Thank you for the elaborate answer!
 
 When you put it like that, it does make sense. But I'm sorry. I refuse. The
 reason I refuse is those examples are void of any higher semantic meaning.
 Once we add a semantic meaning, it simply becomes backwards:
 
 int[MAX_WIDTH][MAX_HEIGHT] map2d;
 map2d[x][y] = 9; // Wrong!
 
 At least in my head, this is cognitive dissonance. To me, the language acts
 as if it's low-level semantics outweighs my high-level semantics and I
 should correct my thinking for that. I refuse! Seems to me it could just
 as well work as:
 
 int[string][3] b;
 int[3] firstB = b["foo"];
 int i = firstB[0];
 int j = (b["foo"])[0];
 int k = b["foo"][0];
 
 But I feel like I'm the only one feeling this, so I'll just let it go and
 hope my dear C-style arrays stay in :)
 
 BR
 /HF
 
 PS. Never thought I'd find a reason to love C.. DS.
Personally, I don't like it, but I also don't think that it necessarily makes sense to change it. From the point of view of how the compiler deduces types, it's exactly how it should work. The problem, of course, is that it doesn't match how we think. However, in order for us to be able to deduce complicated types, the compiler must be totally consistent in how it deduces the type. A prime example would be function pointers (particularly using the C syntax). To be able to pick it apart properly, you're going to have to understand how the compiler does it. The type is complicated enough that you're stuck. To read arrays in the reverse order that is done now, you'd have to read everything else in the reverse order to be consistent, which would really mean types like this: [5](int) const a; The whole thing is ugly. There's no question of that. But to "fix" it breaks other stuff. Types are read right to left. Being consistent with that makes it possible to understand more complicated types. The downside is that some simpler types become harder to understand. However, as long as you use dynamic arrays, this really isn't a problem. int[][] a = new int[][](MAX_WIDTH, MAX_HEIGHT); is totally clear and it works in the order that you think. The problem is when you use statically-allocated arrays. Personally, I'd advise you to just use dynamic arrays unless you do some profiling and find that a static array is better in a particular case. Doing things that way makes it so that the weird ordering in declarations isn't generally a problem. I agree that this particular syntactic faux pas is a problem, but I don't think that anyone has come up with an appropriate solution. Simply reversing how it works now would make reading more complex types much harder. A more complex solution would likely be required. As it stands, it's a problem, but it's only a problem if you're declaring statically-allocated arrays. It's unpleasant, but it should be manageable. - Jonathan M Davis
Jul 14 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:
 [5](int) const a;
Go language uses something similar, and I find it a bit better than D syntax. Bye, bearophile
Jul 15 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:
 Personally, I'd advise you to just use dynamic arrays unless you do
 some profiling and find that a static array is better in a particular case.
To program you need a less naive view. I sometimes start using dynamic arrays everywhere because they are handy, then I profile code and then replace some critical allocations of dynamic arrays with static arrays, and I usually see good speed-ups. With some brain you can often find a static size (or a way to compute it statically) that is good for the algorithm/problem you are working on. In such cases using a static array is often better, the GC doesn't need to deallocate it, and heap activity is one of the most important causes of low performance in programs (or if they are allocated inside class/struct instances you remove some heap allocations, coalescing them). Static arrays are simpler, so in some situations they can make the code simpler. Bye, bearophile
Jul 15 2010
parent Jonathan M Davis <jmdavisprog gmail.com> writes:
On Thursday 15 July 2010 22:20:17 bearophile wrote:
 Jonathan M Davis:
 Personally, I'd advise you to just use dynamic arrays unless you do
 some profiling and find that a static array is better in a particular
 case.
To program you need a less naive view. I sometimes start using dynamic arrays everywhere because they are handy, then I profile code and then replace some critical allocations of dynamic arrays with static arrays, and I usually see good speed-ups. With some brain you can often find a static size (or a way to compute it statically) that is good for the algorithm/problem you are working on. In such cases using a static array is often better, the GC doesn't need to deallocate it, and heap activity is one of the most important causes of low performance in programs (or if they are allocated inside class/struct instances you remove some heap allocations, coalescing them). Static arrays are simpler, so in some situations they can make the code simpler. Bye, bearophile
Well, like I said: Use dynamic arrays unless profiling shows that static arrays would be better in a particular situation. If you really expect a section of code to need it, then it makes sense to use a static array up front. But for the most part, dynamic arrays should be fine, and personally, I find them easier to use since you have less to worry about when dealing with them. However, it's certainly true that sections critical to efficiency may require static arrays, and there's nothing wrong with choosing static arrays in either case. But I see no reason to use static arrays normally unless profiling shows that it would be of benefit. Most of the programs that I do for my own use probably wouldn't care either way. If I were using D at work (efficiency matters a lot more with what I do there), it might be different. But regardless, I wouldn't generally use static arrays unless it were clear that they were necessary. If anything though, I'm likely to be switch to use Array more now that we have it. - Jonathan M Davis
Jul 15 2010
prev sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Wed, 14 Jul 2010 16:57:13 -0400, Heywood Floyd wrote:

 Lars T. Kyllingstad Wrote:
 
 
 But then arrays would be different from all other types!  If you have
 an array of 3 Ts, that is written T[3], regardless of what T is.  Now
 consider these two cases:
 
    A. T is an int.  Then T[3] becomes int[3].
 
    B. T is an int[string].  Then T[3] becomes int[string][3].
 
 In case A, the first element of the array is accessed like this:
 
    int[3] a;
    int firstA = a[0];
 
 Since a is an array of int, firstA is of course an int.
 
 But then, since b is an array of int[string], we have
 
    int[string][3] b;
    int[string] firstB = b[0];
 
 If we again want to access element "foo" of the associative array which
 is firstB, we write firstB["foo"].  And so we have the following three
 ways to get to that element, which *must* be equivalent because that's
 how the language is defined:
 
    // Using firstB as an intermediate step int[string] firstB = b[0];
    int x = firstB["foo"];
 
    // Drop the intermediate variable firstB int x = (b[0])["foo"];
 
    // Drop the redundant parentheses
    int x = b[0]["foo"];
 
 So you see, it can't be any other way than the way it is. :)
 
 -Lars
Thank you for the elaborate answer! When you put it like that, it does make sense. But I'm sorry. I refuse. The reason I refuse is those examples are void of any higher semantic meaning. Once we add a semantic meaning, it simply becomes backwards: int[MAX_WIDTH][MAX_HEIGHT] map2d; map2d[x][y] = 9; // Wrong! At least in my head, this is cognitive dissonance. To me, the language acts as if it's low-level semantics outweighs my high-level semantics and I should correct my thinking for that. I refuse! Seems to me it could just as well work as: int[string][3] b; int[3] firstB = b["foo"]; int i = firstB[0]; int j = (b["foo"])[0]; int k = b["foo"][0]; But I feel like I'm the only one feeling this, so I'll just let it go and hope my dear C-style arrays stay in :) BR /HF PS. Never thought I'd find a reason to love C.. DS.
I do agree that, if possible, the language should match how most people think. But in this case, it is impossible, because of templates. How would the following example work with T = int[3], if arrays worked the way you want? struct MyArray(T) { T[] a; } C doesn't have this issue, because it doesn't have templates. And I'll have my templates over C-style array declarations any time, thank you. :) -Lars
Jul 15 2010
parent reply Heywood Floyd <soul8o8 gmail.com> writes:
Lars T. Kyllingstad Wrote:
 
 I do agree that, if possible, the language should match how most people 
 think.  But in this case, it is impossible, because of templates.  How 
 would the following example work with T = int[3], if arrays worked the 
 way you want?
 
   struct MyArray(T)
   {
       T[] a;
   }
 
 C doesn't have this issue, because it doesn't have templates.  And I'll 
 have my templates over C-style array declarations any time, thank you. :)
 
 -Lars
Well, I suppose the obvious way is to introduce array as a proper type, and not just as syntactical sugar. For instance, consider: array[11] int myArr; The array "wraps around" a more basic type. It's simply read from left to right. This should feel "right" for most people. Now it's easy extend this to multidimensional arrays. We just allow arrays to wrap arrays: array[3] array[11] int myArr2d; This way it's clear what's happening. It's "true" to what's going on at the compiler level. We have an "outer" array that holds 3 "inner" arrays of 11 ints. And, it's "true" to our high level semantics—when we later access the elements, the order is kept intact, as we traverse down the array stack: myArr2d[outer][inner] = 9; It's then not too far of a stretch to allow this array-keyword to accept multidimensional declarations, without reversing the order. Here, it's still quite clear what's happening: (At least if we have seen the above.) array[3][11] int myArr2d; myArr2d[0][10] = 9; //ok When we introduce templates, this should still work: struct MyArray(T){ array[3] T a; } // Let's try T == array[11] int array[3] T a; array[3] (array[11] int) a; array[3] array[11] a; array[3][11] a; a[0][10] = 9; //ok This makes a lot more sense, for me anyway. It's closer to what's actually happening, and it doesn't reverse things at a higher level. BR /HF
Jul 16 2010
next sibling parent Tim Verweij <tjverweij gmail.com> writes:
On 16 July 2010 11:12, Heywood Floyd <soul8o8 gmail.com> wrote:

 Lars T. Kyllingstad Wrote:
 (...)

 When we introduce templates, this should still work:

 struct MyArray(T){
   array[3] T a;
 }

 // Let's try
 T == array[11] int

 array[3] T a;
 array[3] (array[11] int) a;
 array[3] array[11] a;
 array[3][11] a;

 a[0][10] = 9; //ok
The 'int' goes missing there. I guess you meant to write: array[3] T a; array[3] (array[11] int) a; array[3] array[11] int a; array[3][11] int a; Right? Pretty nice. I must say that I quite like this. It does feel 'right'. Groet, Tim
Jul 16 2010
prev sibling parent reply Mafi <mafi example.org> writes:
Am 16.07.2010 11:12, schrieb Heywood Floyd:
 Lars T. Kyllingstad Wrote:

 I do agree that, if possible, the language should match how most people
 think.  But in this case, it is impossible, because of templates.  How
 would the following example work with T = int[3], if arrays worked the
 way you want?

    struct MyArray(T)
    {
        T[] a;
    }

 C doesn't have this issue, because it doesn't have templates.  And I'll
 have my templates over C-style array declarations any time, thank you. :)

 -Lars
Well, I suppose the obvious way is to introduce array as a proper type, and not just as syntactical sugar. For instance, consider: array[11] int myArr;
... I don't really like it. Of course the order of indices feels better but it breaks the rule of reading types from right to left. It also introduces more parenthesis and a new keyword into types (amongst const, immutable and delegate etc). Consider: shared array[3](const( array[5] immuttable((SList!(int)*)[]) )) WTF, that doesn't look good. I would be a real type if your answer was accepted. It was shared const( immutable(Slist!(int)*[])[5] )[3] which reads perfectly from right to left. What about this: // int[width,height] as sugar for int[height][width] int[width,height] arr = ...; // arr[x,y] as sugar for arr[x][y] int element = arr[x,y]; // then this works as expected int[height] column = arr[x];
Jul 16 2010
next sibling parent Tim Verweij <tjverweij gmail.com> writes:
On 16 July 2010 20:11, Mafi <mafi example.org> wrote:

 Am 16.07.2010 11:12, schrieb Heywood Floyd:

  Lars T. Kyllingstad Wrote:
  I do agree that, if possible, the language should match how most people
 think.  But in this case, it is impossible, because of templates.  How
 would the following example work with T = int[3], if arrays worked the
 way you want?

   struct MyArray(T)
   {
       T[] a;
   }

 C doesn't have this issue, because it doesn't have templates.  And I'll
 have my templates over C-style array declarations any time, thank you. :)

 -Lars
Well, I suppose the obvious way is to introduce array as a proper type, and not just as syntactical sugar. For instance, consider: array[11] int myArr;
... I don't really like it. Of course the order of indices feels better but it breaks the rule of reading types from right to left. It also introduces more parenthesis and a new keyword into types (amongst const, immutable and delegate etc). Consider: shared array[3](const( array[5] immuttable((SList!(int)*)[]) )) WTF, that doesn't look good. I would be a real type if your answer was accepted. It was shared const( immutable(Slist!(int)*[])[5] )[3] which reads perfectly from right to left.
So why all the extra parenthesis? Do you think they are required? Instead of: shared array[3](const( array[5] immutable((SList!(int)*)[]) )) consider this: shared array[3] const array[5] immutable array (SList!(int)*) (or array[] instead of just array) Actually, tbh I think they all look horrible. :-P I hope I never encounter such an impractical beast.
 What about this:
  // int[width,height] as sugar for int[height][width]
  int[width,height] arr = ...;
  // arr[x,y] as sugar for arr[x][y]
  int element = arr[x,y];
  // then this works as expected
  int[height] column = arr[x];
That doesn't look too bad. Groet, Tim
Jul 16 2010
prev sibling parent reply Heywood Floyd <soul8o8 gmail.com> writes:
Mafi Wrote:

 
 I don't really like it. Of course the order of indices feels better but 
 it breaks the rule of reading types from right to left. It also 
 introduces more parenthesis and a new keyword into types (amongst const, 
 immutable and delegate etc). Consider:
    shared array[3](const( array[5] immuttable((SList!(int)*)[]) ))
 WTF, that doesn't look good. I would be a real type if your answer was 
 accepted.
 
 It was
    shared const( immutable(Slist!(int)*[])[5] )[3]
 which reads perfectly from right to left.
 
 What about this:
    // int[width,height] as sugar for int[height][width]
    int[width,height] arr = ...;
    // arr[x,y] as sugar for arr[x][y]
    int element = arr[x,y];
    // then this works as expected
    int[height] column = arr[x];
Interesting! First of all, I definitely think that how arrays are declared now would have to stay just the way it is, no matter what. I don't think stuff like that is changeable this late in a language. But, seems to me these two methods of declaring arrays could coexist. One is the shorter syntactical "sugar" method, the other is the elaborate, but perhaps clearer method. These kinds of long way/shortcuts are already in the language, I believe. Like how void()() is automatically a template, comes to mind. (Or did that make sense?) Then, I simply can't resist commenting this exceptional beauty. I'm gonna call it theThing: shared const( immutable(Slist!(int)*[])[5] )[3] theThing; Well. I have to confess, to me, it doesn't read perfectly from right to left. I might be reading it wrong, but to me it reads from right to left, and from left to right, at the same time. Is it a shared const array of something, or a shared array of const something? You can't really tell unless you go back and forth, and almost count the parenthesis. For instance, by looking at the declaration above, what type is a theThing[0][1] ::= ?? It's really not easy to say, for me anyway. I'm sure you get better at reading these things. So it might not be fair to say that it's "unclear". It's just my subjective opinion, and that may be biased by my lack of experience in the matter. Now back to the other thing: shared array[3] const array[5] immutable array[] (SList!(int)*) Sure, this is too verbose. I agree. Still, I think it's clearer. Much clearer. Verbose, but clear. Here I couldn't help but making an interesting obvservation: Those storage classes could also be seen as types. What if we allowed the storage classes to have some syntactical sugar too, for arrays? We could have: shared[3] const[5] immutable[] SList!(int)* theThing; That does read from left to right in one go, and to me, it's still clear what's going on, and, it's not verbose. In fact, it's less verbose than the parenthesis-sprinkled version we saw first. Further, it's almost magically easy to read: We have a shared array of 3 const arrays of 5 immutable dynamic arrays of Slist!(int)*. It just reads, like you read text, quite naturally. (I'm not sure this would actually be the same type as the first declaration, erh, but yes. You get my intention.) So again, what type is a theThing[0][1] ::= ?? Well, if we look at the declaration above it's quite easy: We just cut the line after the second array, const[5], and the rest of the line, that's our type. theThing[0][1] ::= immutable[] SList!(int)* Now, to me, that's just plain beautiful. *** And last, the int[x,y] arr; I like it. Simple. Nice. Maybe it becomes weird when we have mixed array types, like int[uint,,5] arr? Well at least the illusion of an intact order is maintained. BR /HF
Jul 16 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Heywood Floyd:
 First of all, I definitely think that how arrays are declared now would have
to stay just the way it is,
 no matter what. I don't think stuff like that is changeable this late in a
language.
Recently I have suggested to remove the syntax: new int[20]; And allow only: new int[](20);
    shared array[3] const array[5] immutable array[] (SList!(int)*)
 
 Sure, this is too verbose. I agree. Still, I think it's clearer. Much clearer.
Verbose, but clear.
I don't know how you can write that in a Go-language-like syntax, maybe it's a bit worse.
 And last, the
    int[x,y] arr;
 
 I like it. Simple. Nice. 
It's nice, but unfortunately the comma syntax is present in C too, where: int[10] arr; int element = arr[x, y]; Equals to: int[10] arr; int element = arr[y]; So in D the usage of comma inside [] was recently forbidden. Keeping some kind of backward compatibility with C is something a kind of damnation (see also switch syntax, tuple syntax, etc). Bye, bearophile
Jul 16 2010