June 08, 2011
On 06/08/2011 01:49 AM, Jonathan M Davis wrote:

> No, people don't normally look at declarations such as
>
> int* a;
>
> as being right to left. But from the compiler's perspective, they are.

I will go a little bit off topic here. If we need to think about what the compiler does or how a specific language feature is implemented, that language is a failed abstraction. D is not. There shouldn't be any need to get into implementation details to describe a language feature.

This used to happen with D slices: some people would point to pictures of slices where .ptr pointed to the beginning of some elements in memory. That way of describing slices would not work on beginners who have no idea on what a pointer is, especially in a language where pointers can be avoided for a long time.

> As for static arrays in D, the problem is the disjoint between declarations
> and indexing.

That's very normal: declaration and indexing are separate. Why should they have any resemblance? Perhaps they both use the [] characters. That is unfortunate, similar to '*' being used in declaration and dereferencing; very different things.

> They're flipped between the two. Most people expect that the
> dimensions read left to right for both the declaration and the indexing, but
> they don't.

I am not one of those people. I am used to C's weird inside-out array syntax since 1989. I've always cringed at that and I've always introduced typedefs to remedy the problem.

// C code
#include <stdio.h>

int main()
{
    char a[4][3];
    printf("%zu\n", sizeof(a[0]));  // prints 3
}

// C code with typedef
#include <stdio.h>

int main()
{
    typedef char Row[4];
    Row a[3];
    printf("%zu\n", sizeof(a[0]));  // NOW PRINTS 4! TIME BOMB?
}

The problem there is the necessity to know that Row is a typedef of some other array, so that we should now "see" 'a' as a definition of char a[3][4].

I am very happy that D solved that problem:

import std.stdio;

void main()
{
    char[4][3] a;
    writeln(typeof(a[0]).sizeof);   // prints 4
}

import std.stdio;

void main()
{
    alias char[4] Row;
    Row[3] a;
    writeln(typeof(a[0]).sizeof);   // STILL PRINTS 4!
}

I call that consistency.

> They think that
>
> int[4][3] a;
> auto b = a[3][2];
>
> is legal, because they view the left dimension in the declaration as being the
> left when indexing. But it's not. If you used the C syntax,
>
> int a[4][3];
> auto b = a[3][2];
>
> then the dimensions _do_ match.

They match in that way, but it is inconsistent. The following declaration is in the order of type, size, name:

T[3] a;

And indexing is always array[index]:

a[2];  // a reference to T

Now I am going to replace T with int[4]. It is still in the order of type, size, name (I am putting inserting a space to distinguish):

int[4] [3] a;

And indexing is still array[index]:

a[2]; // a reference to int[4];

Since a[2] is a reference to int[4], now I can further index it:

a[2][3];

Consistent.

What I don't agree is seeing [2][3] as a single operation. They are two separate indexing operations.

That's how I think to be happy. :)

Ali

June 08, 2011
On 06/08/2011 10:38 AM, Ali Çehreli wrote:

> If we need to think about what
> the compiler does or how a specific language feature is implemented,
> that language is a failed abstraction. D is not. There shouldn't be any
> need to get into implementation details to describe a language feature.
>
> This used to happen with D slices: some people would point to pictures
> of slices where .ptr pointed to the beginning of some elements in
> memory. That way of describing slices would not work on beginners who
> have no idea on what a pointer is, especially in a language where
> pointers can be avoided for a long time.

Allow me to contradict myself: I've tried to pinpoint the semantics of D's slices in the past, but have failed. I remember focusing on "discretionary sharing semantics."

The apparent non-deterministic behavior related to non-stomping makes it hard ("impossible" for me) to describe the semantics of slices. Steve had to get into implementation details in his "D Slices" article to describe that non-determinism. I think that strengthens my view that slices cannot be fully described without getting into implementation details.

Ali

June 08, 2011
Timon Gehr Wrote:

> It is more convenient for the compiler to read the declaration left to right to construct the type. (just like for people)

a real example in the go language :)

hello := []byte("hello, world\n")
June 08, 2011
On 2011-06-08 10:38, Ali Çehreli wrote:
> On 06/08/2011 01:49 AM, Jonathan M Davis wrote:
> > No, people don't normally look at declarations such as
> > 
> > int* a;
> > 
> > as being right to left. But from the compiler's perspective, they are.
> 
> I will go a little bit off topic here. If we need to think about what the compiler does or how a specific language feature is implemented, that language is a failed abstraction. D is not. There shouldn't be any need to get into implementation details to describe a language feature.

It's not really a matter of understanding how the compiler implements a specific feature so much as understanding type semantics. But yes, type declarations can be hard to read, and understanding fully does pretty much require understanding how the compiler looks at them.

It's like operotor associativity and precedence. You need to understand that

auto i = 7 + 12 * 2;

gives i a value of 31, not 38. Type declarations are the same. You need to understand how they're constructed. They're just a more complicated example and one which you can actually misunderstand on some level but generally understand well enough to program just fine. It's more complicated type declarations (such as C-style function pointers, const pointers in C/C++, and to some extent static array declarations in D) which tend to force you to have a better understanding of type declaration semantics. Complicated type declarations are complicated, and so deciphering them can be complicated.

- Jonathan M Davis
June 08, 2011
Kagamin wrote:
> Timon Gehr Wrote:
>
> > It is more convenient for the compiler to read the declaration left to right to construct the type. (just like for people)
>
> a real example in the go language :)
>
> hello := []byte("hello, world\n")

In your example the compiler has to parse the type "[]byte" from right to left, not left to right, to make sense out of it.

That is not an example for what I was referring to.

Timon
June 08, 2011
On 2011-06-08 11:48, Kagamin wrote:
> Timon Gehr Wrote:
> > It is more convenient for the compiler to read the declaration left to right to construct the type. (just like for people)
> 
> a real example in the go language :)
> 
> hello := []byte("hello, world\n")

That seems so unnatural, though I expect that you'd get used to it. I find it more horrifying that a string is typed as an array of bytes.

- Jonathan M Davis
June 08, 2011
On 2011-06-08 12:03, Timon Gehr wrote:
> Kagamin wrote:
> > Timon Gehr Wrote:
> > > It is more convenient for the compiler to read the declaration left to right to construct the type. (just like for people)
> > 
> > a real example in the go language :)
> > 
> > hello := []byte("hello, world\n")
> 
> In your example the compiler has to parse the type "[]byte" from right to left, not left to right, to make sense out of it.

Does it really? It's an array of bytes, not a byte of arrays. I fully expect that it looks at it from left-to-right. But I don't know how they implemented it.

- Jonathan M Davis
June 08, 2011
Jonathan M Davis wrote:
> On 2011-06-08 12:03, Timon Gehr wrote:
> > Kagamin wrote:
> > > Timon Gehr Wrote:
> > > > It is more convenient for the compiler to read the declaration left to right to construct the type. (just like for people)
> > >
> > > a real example in the go language :)
> > >
> > > hello := []byte("hello, world\n")
> >
> > In your example the compiler has to parse the type "[]byte" from right to left, not left to right, to make sense out of it.
>
> Does it really? It's an array of bytes, not a byte of arrays. I fully expect that it looks at it from left-to-right. But I don't know how they implemented it.
>
> - Jonathan M Davis

True, I think the input is consumed left-to-right. But as they are using a standard recursive descent parser, it will go like this:

Find []                                               ("look" at [])
 -> Recursively parse another type                    ("look" at byte)
Create [] Expression and link it to the parsed type.  ("look" at [])

So actually the parser looks at them in _both_ orders =).

Timon



June 08, 2011
On 6/8/2011 12:00 PM, Jonathan M Davis wrote:
> I find it
> more horrifying that a string is typed as an array of bytes.

Yeah, I separated chars from byte types in D because in C it was always irksome to conflate the two.

1 2 3
Next ›   Last »