Bug 10643 – Refused const array struct field initialized with void

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-07-14T14:35:41Z
Last change time
2017-08-25T10:07:54Z
Keywords
pull, rejects-valid
Assigned to
No Owner
Creator
bearophile_hugs
See also
https://d.puremagic.com/issues/show_bug.cgi?id=11739, https://issues.dlang.org/show_bug.cgi?id=11331

Comments

Comment #0 by bearophile_hugs — 2013-07-14T14:35:41Z
class Bar { const int[1000] x = void; this(int n) { x[] = n; } } void main() {} dmd 2.064alpha gives errors but I think the code is correct: test.d(2): Warning: const field with initializer should be static, __gshared, or an enum test.d(4): Error: slice x[] is not mutable There is also some discussion in this thread: http://forum.dlang.org/thread/[email protected]
Comment #1 by maxim — 2013-07-14T19:38:14Z
From http://dlang.org/changelog.html#staticfields : "Eventually, they will be deprecated, and then will trigger an error." The issue is that void initializer does not disable initialization but fills aggregate member with zero (it also fills data with zeros for types which .init property is not zero). If you replace void with some number, the code would not still compile, so this is not a specific to void. Also this fails in accordance with change-log. I think this can be change to request to make void behavior to what it does for local variables or request to update the spec, but in current circumstances this issue is resolved-invalid.
Comment #2 by monarchdodra — 2013-12-14T07:01:10Z
(In reply to comment #1) > The issue is that void initializer does not disable initialization but fills > aggregate member with zero (it also fills data with zeros for types which .init > property is not zero). Technically, void initialization implies *no* initialization whatsoever: //---- void main() { { int i = 5; } int i = void; assert(i == 5; } //---- When a *member* of a struct is declared void, it's value may be padded with anything the compiler wishes. Regardless of what the bits are, the value remains non-initialized. > If you replace void with some number, the code would not > still compile, so this is not a specific to void. Also this fails in accordance > with change-log. I don't understand this answer. "Non"-initialization is *still* initialization to T.init, yet that's allowed. > From http://dlang.org/changelog.html#staticfields : "Eventually, they will be > deprecated, and then will trigger an error." I don't understand why it is not legal to have a const member with an initializer. So now it is impossible to do this? struct S { const(int) i = 5; //default const value this(int n) { i = n; //Override default } } void main() { S s; assert(s.i == 5); }
Comment #3 by maxim — 2013-12-14T07:21:23Z
(In reply to comment #2) > (In reply to comment #1) > > The issue is that void initializer does not disable initialization but fills > > aggregate member with zero (it also fills data with zeros for types which .init > > property is not zero). > > Technically, void initialization implies *no* initialization whatsoever: > > //---- > void main() > { > { > int i = 5; > } > int i = void; > assert(i == 5; > } > //---- Actually there is difference between void initialization of variable and member field. In first case it is as you say, but in second case void initialization means filling data with zero bytes. You may argue that it is incorrect, but untill the behavior is changed, you are stuck with it. Anyway, void is irrelevant to the issue, because judjing by issue 11739, you have something different in mind. > When a *member* of a struct is declared void, it's value may be padded with > anything the compiler wishes. Regardless of what the bits are, the value > remains non-initialized. > > > If you replace void with some number, the code would not > > still compile, so this is not a specific to void. Also this fails in accordance > > with change-log. > > I don't understand this answer. "Non"-initialization is *still* initialization > to T.init, yet that's allowed. Yes, but this is third case. Why is it relevant here? I think you are just confuse the discussion. > > From http://dlang.org/changelog.html#staticfields : "Eventually, they will be > > deprecated, and then will trigger an error." > > I don't understand why it is not legal to have a const member with an > initializer. So now it is impossible to do this? > > struct S > { > const(int) i = 5; //default const value > this(int n) > { > i = n; //Override default > } > } > > void main() > { > S s; > assert(s.i == 5); > } Ok, here is what you really mean (i think). Note, that the code fails with any initializer (void or some value), so void is irrelevant. Default initialization is also irrelevant because you have initializer. So, the issue of interest is: struct S { const(int) i = void; // or any other initializer this(int j) { i = j; } } From changelog: Eventually, they will be deprecated, and then will trigger an error. Such fields should now be changed to enum or static. Making a field implicitly static based on whether it is const/immutable and has an initializer leads to confusion. The static keyword can be used to explicitly make any field static. That is why the code is rejected. I would add into rationale additional point: having initializer and overwriting field is useless because you either know in beforehand value of a member (and use initializer), or you do not (and set value in RT).
Comment #4 by monarchdodra — 2013-12-14T09:05:49Z
(In reply to comment #3) > Ok, here is what you really mean (i think). Note, that the code fails with any > initializer (void or some value), so void is irrelevant. Default initialization > is also irrelevant because you have initializer. So, the issue of interest is: > > struct S > { > const(int) i = void; // or any other initializer > this(int j) > { > i = j; > } > } > > From changelog: Eventually, they will be deprecated, and then will trigger an > error. Such fields should now be changed to enum or static. Making a field > implicitly static based on whether it is const/immutable and has an initializer > leads to confusion. The static keyword can be used to explicitly make any field > static. > > That is why the code is rejected. I understand the changelog, and why the code is rejected, but I disagree with the rationale: The change is due to the fact that const members were static by default. We are changing this, however, to make sure people are correctly impacted, we are making the old semantic explicitly illegal. *BUT*, if I want to declare an actual struct with a const field (eg: it can't be changed, but each struct has its own value). I'd want that field's default value to be "5", but for that value to *possibly* be chosen differently at declaration. I see no problem with doing this. However, it seems that even though we have deprecated the "semantic", we still have the wrong behavior: > I would add into rationale additional point: > having initializer and overwriting field is useless because you either know in > beforehand value of a member (and use initializer), or you do not (and set > value in RT). Or... you want to have a default value (5) which is implementation defined, which the user may or may not decide to not use: //---- struct S { const(int) i = 5; } void main() { S s1; //*Should* be 5 S s2 = S(6); //*Should* be 6 (doesn't work) } //---- If we'd just change right now (still hasn't been done) so that non-statics are actually... non-static, we wouldn't have this problem.
Comment #5 by jakobovrum — 2013-12-14T11:06:09Z
*** Issue 11741 has been marked as a duplicate of this issue. ***
Comment #6 by k.hara.pg — 2013-12-14T11:12:44Z
(In reply to comment #0) > class Bar { > const int[1000] x = void; > this(int n) { > x[] = n; > } > } > void main() {} http://dlang.org/changelog.html#staticfields In 2.063, just only warning was added for implicitly static aggregate members. So currently, Bar.x is still made static implicitly. And, you cannot initialize static variable inside instance constructor. Therefore, essentially current behavior is not a bug. ...But, fortunately(?), void initialized variable is currently not initializable inside static constructor. class Bar { const int x = void; static this() { x = 1; } // NG! } const int x = void; static this() { x = 10; } // NG! This is another compiler bug (I filed it in bug 11742). But for the reason we can fix this issue without breaking any existing code.
Comment #7 by k.hara.pg — 2013-12-14T11:14:53Z
*** Issue 11739 has been marked as a duplicate of this issue. ***
Comment #8 by k.hara.pg — 2013-12-14T21:28:00Z
Comment #9 by github-bugzilla — 2013-12-25T14:30:33Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/d74fc8040d91e1436bdd155130e2afb316381c9f fix Issue 10643 - Refused const array struct field initialized with void Void initialized non-mutable aggregate members should become instance fields. https://github.com/D-Programming-Language/dmd/commit/c4fbc2435cd2cbc1535764c839e66bd7567b4d3b Merge pull request #2964 from 9rnsr/fix10643 Issue 10643 - Refused const array struct field initialized with void