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