Bug 11346 – [2.064 beta] field initializing not allowed in loops or after labels

Status
RESOLVED
Resolution
INVALID
Severity
regression
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-10-24T14:00:00Z
Last change time
2013-10-25T02:08:16Z
Assigned to
nobody
Creator
rswhite4

Comments

Comment #0 by rswhite4 — 2013-10-24T14:00:25Z
Code: ---- import std.stdio; struct Test { public: const int[] test; this(int i) { for (size_t j = 0; j < 4; ++j) { this.test ~= i + j; } } } void main() { Test t = Test(42); } ---- Error: field test initializing not allowed in loops or after labels WTF?
Comment #1 by k.hara.pg — 2013-10-24T17:24:38Z
(In reply to comment #0) > Code: > ---- > import std.stdio; > > struct Test { > public: > const int[] test; > > this(int i) { > for (size_t j = 0; j < 4; ++j) { > this.test ~= i + j; > } > } > } > > void main() { > Test t = Test(42); > } > ---- > > Error: field test initializing not allowed in loops or after labels > > WTF? It's intended behavior change introduced by fixing bug 9665. Possible code fix is: this(int i) { int[] tmp; for (size_t j = 0; j < 4; ++j) { tmp ~= i + j; } this.test = tmp; // initialize non-mutable field only once }
Comment #2 by rswhite4 — 2013-10-24T23:54:24Z
That is so non intuitive. A good example how you can make simple code more complicated. I will wait for the threads in D.learn or possible bug reports for that...
Comment #3 by k.hara.pg — 2013-10-25T00:10:47Z
(In reply to comment #2) > That is so non intuitive. A good example how you can make simple code more > complicated. I will wait for the threads in D.learn or possible bug reports for > that... If multiple initialization for non-mutable field is allowed, it could break type system. For example: struct S { const int[] arr; this(immutable int[] a) { arr = a; // First initialization arr[0] = 1; // Second initialization - modify immutable data! } } Therefore, it's necessary limitation.
Comment #4 by rswhite4 — 2013-10-25T00:13:09Z
So it was a "bug" in 2.063.2 and will never change? It's a real _ugly _ restriction and I'm sure that many newbies don't understand that. But thanks for explanation.
Comment #5 by rswhite4 — 2013-10-25T00:41:49Z
BTW: Your example was an index assignment. Such things could be detected and therefore distinguished of "normal" assignments. Multiple assignments (as I showed in my two bug reports) for an array or an assocaitve array should be possible in the CTor.
Comment #6 by rswhite4 — 2013-10-25T00:50:39Z
To describe my viewpoint somewhat closer: ---- if (Primitive.Target.Vertex & trg) this._targetIds[Primitive.Target.Vertex] = ids++; [1] if (Primitive.Target.Color & trg) this._targetIds[Primitive.Target.Color] = ids++; [2] if (Primitive.Target.TexCoords & trg) this._targetIds[Primitive.Target.TexCoords] = ids++; [2] ---- [1] is allowed because the compiler things, that is the first assignment for _targetIds. But that is _no_ real assignment. A real assigment would be something like that: this._targetIds = ...; It is an index assignment, so the AA is probably not fully initialized. [2] and [3] are rejected, because the compiler thinks, that this are multiple assignments. But that is plain worng. That are also index assignments to initialize my AA. Same thing for normal arrays. A assignment would be arr = [1, 2, 3]; But the operator ~= is a concatenation to initialize my array. IMO we should distinguish this. That would retain your type safety and get rid of the annoying limitation.
Comment #7 by k.hara.pg — 2013-10-25T01:00:14Z
(In reply to comment #4) > So it was a "bug" in 2.063.2 and will never change? > It's a real _ugly _ restriction and I'm sure that many newbies don't understand > that. But thanks for explanation. Yes. Unfortunately that was a long-standing hole in the type system.
Comment #8 by k.hara.pg — 2013-10-25T01:29:24Z
(In reply to comment #6) > To describe my viewpoint somewhat closer: [snip] Unfortunately, AA indexing access and array concatenation also have the possibility of type system breaking. struct S { immutable int[] arr; this(immutable int[] a) { arr = a; assert(arr.capacity > 0); // emulate `arr ~= 10;` (* cast(int[]*) &arr) ~= 10; } } void main() { immutable int[] arr = [1,2,3]; immutable int[] a = arr[0..2]; assumeSafeAppend(a); assert(a.capacity > 0); auto s = S(a); import std.stdio; writeln(arr); // prints [1,2,10] } It's arbitrary example, but under the @system code, concatenation may break type system without explicit casting. The AA case is more easy. If you access the AA by the same key twice, you will mutate once initialized non-mutable data. struct S { immutable int[string] aa; this(int n) { aa["str"] = n; aa["str"] = n; // multiple initialization } } Compiler cannot detect above case without extra runtime cost. Keep the rule for "initialization inside constructor" simple, I think the current behavior is enough acceptable.
Comment #9 by rswhite4 — 2013-10-25T01:32:01Z
I still hate it, but ok, that means for me: no more const for arrays and AA's. Thanks for your time.
Comment #10 by k.hara.pg — 2013-10-25T02:08:16Z
(In reply to comment #9) > I still hate it, but ok, that means for me: no more const for arrays and AA's. > Thanks for your time. No problem.