digitalmars.D - We need to define the semantics of block initialization of arrays
- Don (71/71) Jun 03 2013 DMD has always accepted this initializer syntax for static arrays:
- Peter Alexander (4/7) Jun 03 2013 +1
- Andrej Mitrovic (7/10) Jun 03 2013 I didn't know about it until Walter mentioned the syntax to me. I've
- Simen Kjaeraas (4/9) Jun 03 2013 Votes++;
- Timon Gehr (2/7) Jun 03 2013 Agreed, kill first-element init.
- David Nadlinger (8/12) Jun 03 2013 Kill it with a vengeance!
- Jonathan M Davis (4/12) Jun 03 2013 I honestly didn't know about either, but first element init seems very w...
- deadalnix (2/7) Jun 03 2013 KILL IT WITH FIRE !
- Steven Schveighoffer (6/8) Jun 03 2013 BURRRRRN IT!!!!
- Kenji Hara (17/77) Jun 03 2013 First-element-init is definitely a bug. I can argue that nobody wants th...
- Don (18/69) Jun 04 2013 Good, it seems that everyone agrees. It's therefore a bug in
- bearophile (5/8) Jun 04 2013 I hope it keeps being disallowed, to avoid programmer's mistakes.
- Kenji Hara (13/22) Jun 04 2013 Oh! I did not know it is currently accepted.
- Jesse Phillips (3/6) Jun 03 2013 I would expect block initialization and have never considered
- bearophile (10/10) Jun 04 2013 Sometimes I'd like to write code like this:
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] } ---
Jun 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.
Jun 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.
Jun 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
Jun 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.
Jun 03 2013
On Monday, 3 June 2013 at 19:41:35 UTC, Timon Gehr wrote:On 06/03/2013 11:06 AM, Don wrote: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 DavidPersonally I'd like to just use block-init everywhere. […]Agreed, kill first-element init.
Jun 03 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
Jun 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. But regardless, we need to get this sorted out. It's a blocker for my CTFE work.KILL IT WITH FIRE !
Jun 03 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
Jun 03 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-initializedCurrently 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-initThis is definitely a bug. Instead, block-init should occur.S r = S( 8 ); // OK, struct literal, block-init. T t; // Default initialized, block-initOK.assert( s.x[2] == 8); // Fails; it was first-element-initializedAlso, 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
Jun 03 2013
On Tuesday, 4 June 2013 at 02:33:54 UTC, Kenji Hara wrote:Good, it seems that everyone agrees. It's therefore a bug in todt.c, StructInitializer::todt()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.Yeah, there's difficulties with things like: int [3][4] = [7, 7, 7]; which could be a block initialization -- is this allowed or not? Though I think we have already dealt with such issues for block assignment.void main() { int [3][4] w = 7; assert( w[2][2] == 7); // Passes, it was block-initializedCurrently 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-initGood.This is definitely a bug. Instead, block-init should occur.There is still one problem, bug 10198. This currently compiles, and does something stupid: --- struct U { int [3][3] y; } U u = U(4); --- What do you think should happen here?S r = S( 8 ); // OK, struct literal, block-init. T t; // Default initialized, block-initOK.assert( s.x[2] == 8); // Fails; it was first-element-initializedAlso, 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.
Jun 04 2013
Don:Yeah, there's difficulties with things like: int [3][4] = [7, 7, 7]; which could be a block initialization -- is this allowed or not?I hope it keeps being disallowed, to avoid programmer's mistakes. (Maybe this is acceptable: int [3][4] = [7, 7, 7][]; ) Bye, bearophile
Jun 04 2013
2013/6/4 Don <turnyourkidsintocash nospam.com>There is still one problem, bug 10198. This currently compiles, and does something stupid: --- struct U { int [3][3] y; } U u = U(4); --- What do you think should happen here?Oh! I did not know it is currently accepted. I think accepting multi-dimensional block initializing on StructLiteralExp arguments is very bug-prone behavior. Different from variable declaration in statement scope, there is no target type we can look for. So inferring the cost of static array construction is difficult. struct U { int[3][3][3][3] w; } U u = U(1); // looks trivial, but actually costly operation. int[3][3][3][3] w = 1; // initializing cost is very obvious At most it would be better that it is restricted up to one-dimensional block initializing, same as StructInitializer. Kenji Hara
Jun 04 2013
On Monday, 3 June 2013 at 09:06:25 UTC, Don wrote:DMD has always accepted this initializer syntax for static arrays: float [50] x = 1.0;I would expect block initialization and have never considered first element initialization.
Jun 03 2013
Sometimes I'd like to write code like this: struct Foo { int x; } void main() { Foo[100] foos; foos[].x = 10; } Bye, bearophile
Jun 04 2013