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