February 06, 2015
On Friday, 6 February 2015 at 19:10:01 UTC, Iain Buclaw wrote:
> For debugging purposes, it must have a position on the stack pointer.

This sentence does not parse for me. "on the stack *pointer*"?

> For semantic purposes, comparing it as being equal to another value
> must be false.

That's not clear to me from the spec. One could argue that a zero-byte entity can by definition not have an identity.

In any case, my question was how to implement that behavior without allocating memory, which the spec currently prohibits.

David
February 06, 2015
On 6 February 2015 at 22:16, David Nadlinger via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Friday, 6 February 2015 at 19:10:01 UTC, Iain Buclaw wrote:
>>
>> For debugging purposes, it must have a position on the stack pointer.
>
>
> This sentence does not parse for me. "on the stack *pointer*"?
>
>> For semantic purposes, comparing it as being equal to another value must be false.
>
>
> That's not clear to me from the spec. One could argue that a zero-byte entity can by definition not have an identity.
>
> In any case, my question was how to implement that behavior without allocating memory, which the spec currently prohibits.
>
> David

Simple, you implement it by allocating no memory. :)

I'll have to see what goes on, I can't imagine that llvm won't provide some way to do this.  GDC's behaviour is incident in the backend rather than intent.

Iain.
February 06, 2015
On Friday, 6 February 2015 at 23:37:30 UTC, Iain Buclaw wrote:
> Simple, you implement it by allocating no memory. :)

Let me put it a different way. Imagine you have this in your program:

---
void foo() {
  int[0] a0;
  int[0] a1;
  ...
  int[0] a99;

  // Do something with them.
}
---

How do you choose the addresses for a0 through a99 so that they are distinct, but you don't end up allocating 100 bytes of stack memory?

David
February 07, 2015
On 2015-02-07 at 00:42, David Nadlinger wrote:
> Imagine you have this in your program:
>
> ---
> void foo() {
>    int[0] a0;
>    int[0] a1;
>    ...
>    int[0] a99;
>
>    // Do something with them.
> }
> ---
>
> How do you choose the addresses for a0 through a99 so that they are distinct, but you don't end up allocating 100 bytes of stack memory?


Forgive my ignorance and perhaps not seeing the whole picture, but when I read this:

> A static array with a dimension of 0 is allowed, but no space is allocated for it. It's useful as the last member of a variable length struct...

i am convinced that a0, ..., a99 are not variables but rather *labels* and should point to *the same address* of whatever could be put in that place (with 1-byte alignment). I do not understand why would they ever point to different places. Wouldn't that make them useless when used in structs like the following one (or to access stack, like above)?

    struct Packet {
        int a, b, c, length;
        ubyte[0] data;
        ubyte[0] payload;  // just a superfluous alias to data
    }
    unittest {
        Packet p;
        assert(p.sizeof == 16);
        assert(&p + 1 == cast(void*) &p.data);
        assert(&p + 1 == cast(void*) &p.payload);
    }

As for passing it around, it doesn't make sense, it is like passing an argument of type void, so shouldn't be allowed. Only a pointer to a zero-length array or a specified element would be fine:

    foo(&p.data)    // fine, ubyte*
    bar(p.data[i])  // fine, ubyte (or memory violation)
    xxx(p.data)     // ERROR, makes no sense, shouldn't compile
February 07, 2015
On 6 February 2015 at 23:42, David Nadlinger via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Friday, 6 February 2015 at 23:37:30 UTC, Iain Buclaw wrote:
>>
>> Simple, you implement it by allocating no memory. :)
>
>
> Let me put it a different way. Imagine you have this in your program:
>
> ---
> void foo() {
>   int[0] a0;
>   int[0] a1;
>   ...
>   int[0] a99;
>
>   // Do something with them.
> }
> ---
>
> How do you choose the addresses for a0 through a99 so that they are distinct, but you don't end up allocating 100 bytes of stack memory?
>
> David

There are no addresses for them, you can't do *anything* with them at runtime.

Some cod scenarios:
1. Comparisons of == fold into 'false'  (unless comparing to self)
2. Comparisons of != fold into 'true'  (unless comparing to self)
3. Conversion to dynamic arrays is { .length=0, .ptr=&arr0 }

You cannot assign memory/address to them directly, but you can assign it indirectly.  This 'indirect assignment' can only really work if it were the last member of a struct.  Example usage - http://goo.gl/uAbxKN - something like a pointer-based dynamic array.

Labels probably do best describe their exact behaviour.

Iain.
February 07, 2015
On 7 February 2015 at 10:56, FG via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 2015-02-07 at 00:42, David Nadlinger wrote:
>>
>> Imagine you have this in your program:
>>
>> ---
>> void foo() {
>>    int[0] a0;
>>    int[0] a1;
>>    ...
>>    int[0] a99;
>>
>>    // Do something with them.
>> }
>> ---
>>
>> How do you choose the addresses for a0 through a99 so that they are distinct, but you don't end up allocating 100 bytes of stack memory?
>
>
>
> Forgive my ignorance and perhaps not seeing the whole picture, but when I read this:
>
>> A static array with a dimension of 0 is allowed, but no space is allocated for it. It's useful as the last member of a variable length struct...
>
>
> i am convinced that a0, ..., a99 are not variables but rather *labels* and should point to *the same address* of whatever could be put in that place (with 1-byte alignment). I do not understand why would they ever point to different places. Wouldn't that make them useless when used in structs like the following one (or to access stack, like above)?
>
>     struct Packet {
>         int a, b, c, length;
>         ubyte[0] data;
>         ubyte[0] payload;  // just a superfluous alias to data
>     }
>     unittest {
>         Packet p;
>         assert(p.sizeof == 16);
>         assert(&p + 1 == cast(void*) &p.data);
>         assert(&p + 1 == cast(void*) &p.payload);
>     }
>
> As for passing it around, it doesn't make sense, it is like passing an argument of type void, so shouldn't be allowed. Only a pointer to a zero-length array or a specified element would be fine:
>
>     foo(&p.data)    // fine, ubyte*

This is OK - gets passed as ubyte*

>     bar(p.data[i])  // fine, ubyte (or memory violation)

This is OK - gets passed as ubyte - though will throw arrayBounds error unless -noboundschecks.

>     xxx(p.data)     // ERROR, makes no sense, shouldn't compile

This is OK - gets passed as ubyte[] - the dynamic array will have a length of '0' and the ptr to &p.data.

Iain.
February 07, 2015
On Saturday, 7 February 2015 at 12:10:45 UTC, Iain Buclaw wrote:
> Some cod scenarios:
> 1. Comparisons of == fold into 'false'  (unless comparing to self)
> 2. Comparisons of != fold into 'true'  (unless comparing to self)
> 3. Conversion to dynamic arrays is { .length=0, .ptr=&arr0 }

What does "arr0" refer to?

And assuming that a0.ptr and a1.ptr would end up being the same in your proposal, do you really want to have a situation where a0.ptr == a1.ptr && a0.length == a1.length but a0 != a1?

David
February 07, 2015
On 2015-02-07 at 13:21, Iain Buclaw via Digitalmars-d wrote:
>>
>>      foo(&p.data)    // fine, ubyte*
>
> This is OK - gets passed as ubyte*
>
>>      bar(p.data[i])  // fine, ubyte (or memory violation)
>
> This is OK - gets passed as ubyte - though will throw arrayBounds
> error unless -noboundschecks.
>
>>      xxx(p.data)     // ERROR, makes no sense, shouldn't compile
>
> This is OK - gets passed as ubyte[] - the dynamic array will have a
> length of '0' and the ptr to &p.data.

Oh, I see. That is quite a nice solution. Better than compilation error.
February 07, 2015
On 7 Feb 2015 12:50, "David Nadlinger via Digitalmars-d" < digitalmars-d@puremagic.com> wrote:
>
> On Saturday, 7 February 2015 at 12:10:45 UTC, Iain Buclaw wrote:
>>
>> Some cod scenarios:
>> 1. Comparisons of == fold into 'false'  (unless comparing to self)
>> 2. Comparisons of != fold into 'true'  (unless comparing to self)
>> 3. Conversion to dynamic arrays is { .length=0, .ptr=&arr0 }
>
>
> What does "arr0" refer to?
>

A zero length static array.

> And assuming that a0.ptr and a1.ptr would end up being the same in your
proposal, do you really want to have a situation where a0.ptr == a1.ptr && a0.length == a1.length but a0 != a1?
>
> David

a0.ptr == a1.ptr  // false, enforced by compiler. Comparison not actually
emitted.
a0.length == a1.length // true, both are 0
a0 != a1  // true, same effect as first.

Iain.


February 07, 2015
On Saturday, 7 February 2015 at 12:10:45 UTC, Iain Buclaw wrote:
> On 6 February 2015 at 23:42, David Nadlinger via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>> On Friday, 6 February 2015 at 23:37:30 UTC, Iain Buclaw wrote:
>>>
>>> Simple, you implement it by allocating no memory. :)
>>
>>
>> Let me put it a different way. Imagine you have this in your program:
>>
>> ---
>> void foo() {
>>   int[0] a0;
>>   int[0] a1;
>>   ...
>>   int[0] a99;
>>
>>   // Do something with them.
>> }
>> ---
>>
>> How do you choose the addresses for a0 through a99 so that they are
>> distinct, but you don't end up allocating 100 bytes of stack memory?
>>
>> David
>
> There are no addresses for them, you can't do *anything* with them at runtime.
>
> Some cod scenarios:
> 1. Comparisons of == fold into 'false'  (unless comparing to self)
> 2. Comparisons of != fold into 'true'  (unless comparing to self)

Why's that? Shouldn't _all_ 0 size variables compare equal? I'd say that follows from the definition:

    array1 == array2
        <=>
    all corresponding elements of both arrays are equal
        <=>
    no corresponding elements of both arrays are different

For the last one, it's obvious that this applies to empty arrays: they don't even contain elements that could compare unequal.

Or maybe you're only talking about the addresses here?