Jump to page: 1 2
Thread overview
We need to define the semantics of block initialization of arrays
Jun 03, 2013
Don
Jun 03, 2013
Peter Alexander
Jun 03, 2013
Andrej Mitrovic
Jun 03, 2013
Simen Kjaeraas
Jun 03, 2013
Timon Gehr
Jun 03, 2013
David Nadlinger
Jun 04, 2013
Jonathan M Davis
Jun 04, 2013
deadalnix
Jun 04, 2013
Kenji Hara
Jun 04, 2013
Don
Jun 04, 2013
bearophile
Jun 04, 2013
Kenji Hara
Jun 04, 2013
Jesse Phillips
Jun 04, 2013
bearophile
June 03, 2013
DMD has always accepted this initializer syntax for static arrays:

float [50] x = 1.0;

If this declaration happens inside a function, or in global scope, the compiler sets all members of x to 1.0.  That is, it's the same as:

float [50] x = void;
x[] = 1.0;

In my DMD pull requests, I've called this 'block initialization', since there was no standard name for it.

A lot of code relies on this behaviour, but the spec doesn't mention it!!!

The problem is not simply that this is unspecified. A long time ago, if this same declaration was a member of a struct declaration, the behaviour was completely different. It used to set x[0] to 1.0, and leave the others at float.init. I'll call this "first-element-initialization", and it still applies in many cases, for example when you use a struct static initializer. Ie, it's the same as:

float [50] x;
x[0] = 1.0;

Note however that this part of the compiler has historically been very bug-prone, and the behaviour has changed several times.


I didn't know about first-element-initialization when I originally did the CTFE code, so when CTFE is involved, it always does block initialization instead.
Internally, the compiler has two functions, defaultInit() and defaultInitLiteral(). The first does first-element-init, the second does block-init.
There are several other situations which do block initialization (not just CTFE). There are a greater number of situations where first-init can happen, but the most frequently encountered situations use block-init. There are even some foul cases, like bug 10198, where due to a bug in CTFE, you currently get a bizarre mix of both first-init and block-init!


So, we have a curious mix of the two behaviours. Which way is correct?

Personally I'd like to just use block-init everywhere. I personally find first-element-init rather unexpected, but maybe that's just me. I don't know when it would be useful. But regardless, we need to get this sorted out.
It's a blocker for my CTFE work.


Here's an example of some of the oddities:
----
struct S {
   int [3] x;
}

struct T {
    int [3] x = 8;
}

struct U {
   int [3][3] y;
}

void main()
{
   int [3][4] w = 7;
   assert( w[2][2] == 7); // Passes, it was block-initialized

   S s =  { 8 }; // OK, struct static initializer. first-element-init
   S r = S( 8 ); // OK, struct literal, block-init.
   T t;          // Default initialized, block-init
   assert( s.x[2] == 8); // Fails; it was first-element-initialized
   assert( r.x[2] == 8); // Passes; all elements are 8. Block-init.
   assert( t.x[2] == 8); // Passes; all elements are 8. Block-init.

   U u = { 9 };  // Does not compile
   // Error: cannot implicitly convert expression (9) of type int to int[3LU][3LU]
}
---
June 03, 2013
On Monday, 3 June 2013 at 09:06:25 UTC, Don wrote:
> Personally I'd like to just use block-init everywhere. I personally find first-element-init rather unexpected, but maybe that's just me. I don't know when it would be useful.

+1

I see no point in just initialising the first member. If you want that, just default init then set the first member.
June 03, 2013
On 6/3/13, Don <turnyourkidsintocash@nospam.com> wrote:
> A lot of code relies on this behaviour, but the spec doesn't mention it!!!

I didn't know about it until Walter mentioned the syntax to me. I've found it quite useful since then. E.g.:

char[100] buffer = 0;

Without this buffer is normally initialized with 0xFF, and this could break C functions when you pass a pointer to such an array.

> Personally I'd like to just use block-init everywhere.

Me too. You get my vote.
June 03, 2013
On 2013-06-03, 11:06, Don wrote:

> Personally I'd like to just use block-init everywhere. I personally find first-element-init rather unexpected, but maybe that's just me. I don't know when it would be useful. But regardless, we need to get this sorted out.
> It's a blocker for my CTFE work.

Votes++;

-- 
Simen
June 03, 2013
On 06/03/2013 11:06 AM, Don wrote:
>
> Personally I'd like to just use block-init everywhere. I personally find
> first-element-init rather unexpected, but maybe that's just me. I don't
> know when it would be useful. But regardless, we need to get this sorted
> out.
> It's a blocker for my CTFE work.

Agreed, kill first-element init.
June 03, 2013
On Monday, 3 June 2013 at 19:41:35 UTC, Timon Gehr wrote:
> On 06/03/2013 11:06 AM, Don wrote:
>>
>> Personally I'd like to just use block-init everywhere. […]
>
> Agreed, kill first-element init.

Kill it with a vengeance!

Honestly, I can't see how that could have ever been intended as a feature, and while fixing an issue in LDC a while back, I already removed that one instance with a first-element struct initializer from the test suite: https://github.com/ldc-developers/dmd-testsuite/blob/ldc/runnable/test42.d#L3226

David
June 04, 2013
On Monday, June 03, 2013 11:06:22 Don wrote:
> So, we have a curious mix of the two behaviours. Which way is correct?
> 
> Personally I'd like to just use block-init everywhere. I
> personally find first-element-init rather unexpected, but maybe
> that's just me. I don't know when it would be useful. But
> regardless, we need to get this sorted out.
> It's a blocker for my CTFE work.

I honestly didn't know about either, but first element init seems very wrong to me, whereas block init makes sense.

- Jonathan M Davis
June 04, 2013
On Monday, 3 June 2013 at 09:06:25 UTC, Don wrote:
> Personally I'd like to just use block-init everywhere. I personally find first-element-init rather unexpected, but maybe that's just me. I don't know when it would be useful. But regardless, we need to get this sorted out.
> It's a blocker for my CTFE work.
>

KILL IT WITH FIRE !
June 04, 2013
On Mon, 03 Jun 2013 05:06:22 -0400, Don <turnyourkidsintocash@nospam.com> wrote:

> DMD has always accepted this initializer syntax [with unexplained black magic behavior that is inconsistent from one usage to the next]

BURRRRRN IT!!!!

Seriously, I had no idea this was going on.  It would surprise the hell out of me if I had discovered it!

-Steve
June 04, 2013
2013/6/3 Don <turnyourkidsintocash@nospam.com>

> DMD has always accepted this initializer syntax for static arrays:
>
> float [50] x = 1.0;
>
> If this declaration happens inside a function, or in global scope, the compiler sets all members of x to 1.0.  That is, it's the same as:
>
> float [50] x = void;
> x[] = 1.0;
>
> In my DMD pull requests, I've called this 'block initialization', since there was no standard name for it.
>
> A lot of code relies on this behaviour, but the spec doesn't mention it!!!
>
> The problem is not simply that this is unspecified. A long time ago, if this same declaration was a member of a struct declaration, the behaviour was completely different. It used to set x[0] to 1.0, and leave the others at float.init. I'll call this "first-element-initialization"**, and it still applies in many cases, for example when you use a struct static initializer. Ie, it's the same as:
>
> float [50] x;
> x[0] = 1.0;
>
> Note however that this part of the compiler has historically been very bug-prone, and the behaviour has changed several times.
>
>
> I didn't know about first-element-initialization when I originally did the
> CTFE code, so when CTFE is involved, it always does block initialization
> instead.
> Internally, the compiler has two functions, defaultInit() and
> defaultInitLiteral(). The first does first-element-init, the second does
> block-init.
> There are several other situations which do block initialization (not just
> CTFE). There are a greater number of situations where first-init can
> happen, but the most frequently encountered situations use block-init.
> There are even some foul cases, like bug 10198, where due to a bug in CTFE,
> you currently get a bizarre mix of both first-init and block-init!
>
>
> So, we have a curious mix of the two behaviours. Which way is correct?
>
> Personally I'd like to just use block-init everywhere. I personally find
> first-element-init rather unexpected, but maybe that's just me. I don't
> know when it would be useful. But regardless, we need to get this sorted
> out.
> It's a blocker for my CTFE work.
>

First-element-init is definitely a bug. I can argue that nobody wants the strange behavior.


Here's an example of some of the oddities:
> ----
> struct S {
>    int [3] x;
> }
>
> struct T {
>     int [3] x = 8;
> }
>
> struct U {
>    int [3][3] y;
> }
>
> void main()
> {
>    int [3][4] w = 7;
>    assert( w[2][2] == 7); // Passes, it was block-initialized
>

Currently block-initialization for multi-dimensional static array is just
only allowed for variable declaration in statement scope.
I'm planning to fix bug 3849 and 7019, but changing this behavior might
affect them. As my hope, I'd like to keep this as-is so I've not finished
thinking about it well.

   S s =  { 8 }; // OK, struct static initializer. first-element-init
>

This is definitely a bug. Instead, block-init should occur.


>    S r = S( 8 ); // OK, struct literal, block-init.
>    T t;          // Default initialized, block-init
>

OK.


>    assert( s.x[2] == 8); // Fails; it was first-element-initialized
>

Also, definitely a bug.


>    assert( r.x[2] == 8); // Passes; all elements are 8. Block-init.
>    assert( t.x[2] == 8); // Passes; all elements are 8. Block-init.
>

OK.


>    U u = { 9 };  // Does not compile
>    // Error: cannot implicitly convert expression (9) of type int to
> int[3LU][3LU]
>

For reasons I've already mentioned in `int [3][4] w = 7;`, I'd like to keep this current behavior.


> }
> ---
>

Kenji Hara


« First   ‹ Prev
1 2