July 15, 2010
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
July 15, 2010
Jonathan M Davis:
> [5](int) const a;

Go language uses something similar, and I find it a bit better than D syntax.

Bye,
bearophile
July 16, 2010
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
July 16, 2010
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
July 16, 2010
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


July 16, 2010
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


July 16, 2010
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];
July 16, 2010
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


July 17, 2010
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


July 17, 2010
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
1 2
Next ›   Last »