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