June 07
https://issues.dlang.org/show_bug.cgi?id=24587

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |razvan.nitu1305@gmail.com

--- Comment #1 from RazvanN <razvan.nitu1305@gmail.com> ---
I don't find this very useful. It seems that we are complicating the type system only to obtain something that is actually more confusing. cast() is used to drop all qualifiers whereas if you want to keep some of them you can just cast to the appropriate combination of qualifiers (i.e. cast(const shared)). That way you know exactly what the type is at the cast site, whereas introducing the possibility to negate a single qualifier makes it ambiguous with regards to what the type at the cast site is.

Also, can you provide a concrete code example where this is useful? It seems to me that this is a theoretical proposal without any actual practical usefulness.

--
June 17
https://issues.dlang.org/show_bug.cgi?id=24587

--- Comment #2 from Bolpat <qs.il.paperinik@gmail.com> ---
I just found out `cast(const)` not only adds `const` if it’s not present, it also removes any other qualifiers.

(In reply to RazvanN from comment #1)
> I don't find this very useful.

Not an argument.

> It seems that we are complicating the type
> system only to obtain something that is actually more confusing.

The type system remains unchanged. It only adds a concise syntax to cast away specific qualifiers without having to query the type.

You can argue the syntax is confusing. I don’t think it is.

> cast() is
> used to drop all qualifiers whereas if you want to keep some of them you can
> just cast to the appropriate combination of qualifiers (i.e. cast(const
> shared)).

Yes, but that’s not easy. One has to know which qualifiers are present. In a template-context, one has to tediously query them, and in a non-template context, one has to look them up and repeat them, and if they change, too bad, the cast now does something unintended.

> That way [with `cast(Quals)`] you know exactly what the type is at the cast site, whereas introducing the possibility to negate a single qualifier makes it ambiguous with regards to what the type at the cast site is.

When is that a use-case? When is “I don’t care what qualifiers a type has, make
it XYZ” a use case?
The only one I see is when you want to extract information of what template
instance or whatnot something is,
and qualifiers are in the way. I.e. in an unevaluated context.

Of course, if you have a `const shared LongAndComplicated!(Template!Instance)
x`,
it’s easy to write `cast(const)x`, but here I have to look up its type, see
that it’s `const` and repeat(!) that qualifier.
What I want is not repeat anything and express intent, i.e. the intent to
remove `shared`.

What did a `cast(const)` intend?
Add `const`?
Remove something else and retain `const`?
Who knows.

> Also, can you provide a concrete code example where this is useful?

I can’t because I don’t work professionally with D.
Any example I’d provide would be dismissed as “toy project example” anyways.

> It seems
> to me that this is a theoretical proposal without any actual practical
> usefulness.

Among the negated qualifier casts, most definitely `cast(!shared)` would be
useful. If you `cast()`, you might end up casting away `const` and mutate stuff
that you shouldn’t. For `cast(!shared)` on a `const shared` type object, I see
two uses:
1. You intend to read, then you lock a mutex, `cast(!shared)` and do the read
while being assured by the compiler you’re not mutating anything as `const` (or
anything else) goes nowhere. Also, `const` member functions are used instead of
non-`const` ones.
2. You intend to write, and because `cast(!shared)` leaves `const` intact,
you’ll get a compile-error instead of UB if you accidentally write to something
that’s `const`.

I don’t know where in run-time code you want to override all qualifiers. In general, I’d assume you always want to add or remove specific ones. E.g. template code can’t really use `cast(const)` not because it adds `const` (that’s obvious), but because it removes `shared` when it’s present and does so “silently”.

--