How to cast `shared` away reliably

Arafel er.krali at gmail.com
Wed Feb 11 16:49:19 UTC 2026


On 2/11/26 16:02, Paul Backus wrote:
> All type qualifiers in D (`const`, `immutable`, `shared`) are 
> transitive, which means that a type qualifier applied to the "top level" 
> of a type will also be applied recursively to each part of the type. So, 
> a `const(int[])` is the same as a `const(const(int)[])`, and likewise 
> for `shared`, `immutable`, or any combination thereof.
> 
> This is documented in the language spec's page on type qualifiers:
> 
>> Type qualifiers modify a type by applying a _TypeCtor_. _TypeCtors_ 
>> are: `const`, `immutable`, `shared`, and `inout`. Each applies 
>> transitively to all subtypes.
> 
> Source: https://dlang.org/spec/const3.html

Quite helpful even if still somewhat confusing.

I think it would still make sense to define what a "subtype" is. It 
might feel "intuitive", but the closest I can find is this:

https://dlang.org/spec/type.html#derived-data-types

However, of the items listed there, pointers are indeed showing this 
behaviour, but functions and delegates aren't.

Also, it wasn't clear to me what classes and structs would do it (they 
don't, either).

So, all in all, this becomes one of the most unintuitive parts of the 
language. Consider:

```d
struct Pointer(T) {
     T* t;
     alias this=t;
}
void main() {
     shared(Pointer!int) foo;
     shared(int *) bar;
     int i;
     foo = &i; // FAILS
     bar = &i; // FAILS
     cast() foo = &i; // WORKS!!
     cast() bar = &i; // FAILS
}
```

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 can _now_ understand what is happening, and more or less why. But when 
you have a shared variable and just want to remove `shared` after having 
made sure you've got whatever locks you need, you need to dig really 
deep into the obscure corner cases of the language, especially if you're 
using it in generic code.

So my suggestion would be to have some `unshare` helper in phobos, with 
lowercase "u", and potentially `unconst`, etc. These functions would get 
you back your variable cast back as `T` when you pass in a `shared(T)` 
one. Assuming, of course, that the current behaviour isn't going to 
change anytime soon.


More information about the Digitalmars-d mailing list