www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Cast converts AA to rvalue?

reply Johan <j j.nl> writes:
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
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
parent reply Johan <j j.nl> writes:
On Wednesday, 10 August 2022 at 00:28:53 UTC, Steven 
Schveighoffer wrote:
 On 8/9/22 7:02 PM, Johan wrote:
 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.
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; } ```
Aug 10 2022
parent reply ag0aep6g <anonymous example.com> writes:
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
parent reply Johan <j j.nl> writes:
On Wednesday, 10 August 2022 at 09:52:10 UTC, ag0aep6g wrote:
 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 */ }
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
Aug 10 2022
parent ag0aep6g <anonymous example.com> writes:
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