digitalmars.D.learn - Cast converts AA to rvalue?
- Johan (17/17) Aug 09 2022 Testcase:
- Steven Schveighoffer (9/23) Aug 09 2022 So what is happening is you are casting away shared on the expression
- Johan (14/26) Aug 10 2022 I think old compilers parsed it as `(cast()aa)[1]`, which works
Testcase: ``` shared int[int] aa; void main () { cast()aa[1] = 1; } ``` Up to dlang 2.097, this program runs and works fine. Since dlang 2.098, the program errors with: `core.exception.RangeError /app/example.d(3): Range violation` I think the 2.098+ behavior is correct, but I cannot find anything about the change of this language behavior in the release notes. Please enlighten me, Johan related discussion: https://forum.dlang.org/post/etxuhqzlkofitxswsxel forum.dlang.org
Aug 09 2022
On 8/9/22 7:02 PM, Johan wrote:Testcase: ``` shared int[int] aa; void main () { cast()aa[1] = 1; } ``` Up to dlang 2.097, this program runs and works fine. Since dlang 2.098, the program errors with: `core.exception.RangeError /app/example.d(3): Range violation` I think the 2.098+ behavior is correct, but I cannot find anything about the change of this language behavior in the release notes.So what is happening is you are casting away shared on the expression `aa[1]`. This expression by itself is an *access* of a value, not an *assignment*. This is consistent for structs defining both opIndex and opIndexAssign (the expression calls `opIndex`, not `opIndexAssign`), as far back as I can test. If you use `cast()(aa[1]) = 1`, it has a range error even on older versions. That it ever worked is puzzling. -Steve
Aug 09 2022
On Wednesday, 10 August 2022 at 00:28:53 UTC, Steven Schveighoffer wrote:On 8/9/22 7:02 PM, Johan wrote:I think old compilers parsed it as `(cast()aa)[1]`, which works on newer compilers too without range error. In my case, `aa` is also `immutable`. The only way I know how to make it work is now pretty ugly (casting away immutable should be ugly, so perhaps it's OK...): ``` shared immutable int[int] aa; void main () { // (cast()aa)[1] = 1; // works without immutable (*cast(int[int]*)(&aa))[1] = 1; } ```Testcase: ``` shared int[int] aa; void main () { cast()aa[1] = 1; } ```If you use `cast()(aa[1]) = 1`, it has a range error even on older versions. That it ever worked is puzzling.
Aug 10 2022
On 10.08.22 10:20, Johan wrote:``` shared immutable int[int] aa; void main () { // (cast()aa)[1] = 1; // works without immutable (*cast(int[int]*)(&aa))[1] = 1; } ```We have shared static constructors for that: shared static this() { aa[1] = 1; /* no cast needed */ }
Aug 10 2022
On Wednesday, 10 August 2022 at 09:52:10 UTC, ag0aep6g wrote:On 10.08.22 10:20, Johan wrote:But our code is not a toy example ;-) (sorry for unnecessary snarky remark) ``` void f() { aa[1] = 1; // error } shared static this() { f(); } ``` I had considered it, but discarded it... `f` is also a template in our code. Your remark made me check again, and the call chain is short, perhaps I'll convert `f` to a template mixin... Unfortunately doesn't work: "immutable variable `aa` initialization is not allowed in nested function `f`". -Johan``` shared immutable int[int] aa; void main () { // (cast()aa)[1] = 1; // works without immutable (*cast(int[int]*)(&aa))[1] = 1; } ```We have shared static constructors for that: shared static this() { aa[1] = 1; /* no cast needed */ }
Aug 10 2022
On Wednesday, 10 August 2022 at 17:14:08 UTC, Johan wrote:``` void f() { aa[1] = 1; // error } shared static this() { f(); } ``` I had considered it, but discarded it... `f` is also a template in our code. Your remark made me check again, and the call chain is short, perhaps I'll convert `f` to a template mixin... Unfortunately doesn't work: "immutable variable `aa` initialization is not allowed in nested function `f`".If you can build a mutable version of the array in a `pure` function, you can do it like this: ```d int[int] make_aa() pure { int[int] maa; maa[1] = 1; /* or function calls, or whatever */ return maa; } immutable int[int] aa; shared static this() { aa = make_aa(); } ``` If you can't do it in a `pure` function, you can do it with a cast: `aa = cast(immutable) make_aa();`. Casting from mutable to immutable is better, because it does not have undefined behavior (as long as you don't use a mutable reference later). Your casting away immutable and then mutating does have undefined behavior.
Aug 10 2022