How to cast `shared` away reliably
Arafel
er.krali at gmail.com
Thu Feb 12 01:14:30 UTC 2026
On 2/11/26 22:12, Nick Treleaven wrote:
> On Wednesday, 11 February 2026 at 16:49:19 UTC, Arafel wrote:
>> On 2/11/26 16:02, Paul Backus wrote:
>> Also, it wasn't clear to me what classes and structs would do it (they
>> don't, either).
>
> They do:
> ```d
> struct S
> {
> int i;
> }
> shared S s;
> pragma(msg, typeof(s.i)); // shared int
> ```
>
But:
```d
struct S {
int i;
int* p;
}
shared S s;
static assert(is(typeof( (cast() s).i) == int));
static assert(is(typeof( (cast() s).p) == int*));
```
So with a struct or class you can cast away `shared` to access their
members, but with a built-in array or AA you can't.
As an example of why this can become confusing, consider the different
behaviour that `Array` (or any container type that has opIndex) has:
```d
import std;
alias AI = Array!int;
shared AI ai;
static assert(is(typeof((cast () ai)[0]) == int)); // PASSES
alias AI2 = int[];
shared AI2 ai2;
static assert(is(typeof((cast () ai2)[0]) == int)); // FAILS
```
My purpose here, as in the previous example, was to show how
user-defined types and built-in types behave differently, even when they
look similar, and how that can easily become confusing.
>> So, I'm not saying that it's not according to spec, or that it's
>> wrong, but it really _looks like_ the unintended result of applying
>> rules meant for other situations rather than a fully thought-out feature.
>
> I don't think the type qualifiers are at fault, its more how casting and
> `alias this` interact with them.
>
After spending so much time, I more or less understand now how it works,
and why some tests pass, and some don't.
I just think it's too inconsistent, confusing, and ultimately unnecessary.
These rules make sense (perhaps) for `const`, but certainly not for
`shared` that it _expected_ to be removed. If the language _forces_ me
to cast away shared (and, for the record, I agree with that), it should
be easy and straightforward.
There should be a clear way to say: "Hey, all locks in place, now it's
safe. Give me my variable back exactly as it was, so I can actually do
some work."
This just forces one to go through (even more) hoops and loops to be
able to use a `shared` variable, especially in generic code. And, in
fact, it's even messier if you add complex types, like `shared
(RefCounted!S[string])` and / or `shared(RefCounted!S[])`.
More information about the Digitalmars-d
mailing list