Thread overview
cast(function qualifier)
February 03
https://forum.dlang.org/post/v0urjh$58i$1@digitalmars.com

On Thursday, 2 May 2024 at 01:51:45 UTC, Timon Gehr wrote:
> The status quo is that it is annoying to type-pun function pointers to stronger function attributes as the entire type has to be specified:
>
> ```d
> (cast(int function(int)pure)&f)(2);
> ```
>
> This is also error prone as the return type and/or argument types could go out of sync with the actual type of `f`.
>
>
> `cast` could simply allow a list of function attributes and cast a function pointer or delegate to a type that additionally has those attributes:
>
> ```d
> (cast(pure)&f)(2);
> ```
>
> This simple syntactic sugar would make it a bit easier to work with attributes in `@system`/`@trusted` code. Of course, safety checks would still be performed, as for the more explicit cast syntax.

This looks nice.
February 05

On Monday, 3 February 2025 at 18:38:51 UTC, Atila Neves wrote:

>

https://forum.dlang.org/post/v0urjh$58i$1@digitalmars.com

On Thursday, 2 May 2024 at 01:51:45 UTC, Timon Gehr wrote:

>

The status quo is that it is annoying to type-pun function pointers to stronger function attributes as the entire type has to be specified:

(cast(int function(int)pure)&f)(2);

This is also error prone as the return type and/or argument types could go out of sync with the actual type of f.

cast could simply allow a list of function attributes and cast a function pointer or delegate to a type that additionally has those attributes:

(cast(pure)&f)(2);

This simple syntactic sugar would make it a bit easier to work with attributes in @system/@trusted code. Of course, safety checks would still be performed, as for the more explicit cast syntax.

This looks nice.

I addressed this enhancement with that.

I generally dislike the qualifier casts because they override all existing qualifiers.

  • cast(qualifiers) removes all qualifiers, then adds the given qualifiers (includes cast()).

It’s a blunt tool that makes making precise cuts hard. You locked a mutex and and now are good to go with casting away shared? Well, too bad, you did cast() and also removed a const, welcome to UB town. You made sure some C API doesn’t mutate your stuff and cast away const? Well, too bad, you also cast away shared and now you’re debugging race conditions.

My idea is to use ... to abbreviate the type of the operand within the cast; that would make cast(...) a no-op.
Qualifier manipulations go in front of ... and (member) function attribute manipulations trail behind. cast(const ... const) dg adds(!) const both as a qualifier and a member function attribute to the type of dg.

Before a single qualifier or attribute, there can be a - or !. Both remove the qualifier or attribute, but the - is a compile-error if the qualifier or attribute is not present, whereas ! removes if it is present, essentially just ensuring a qualifier or attribute isn’t present in the result.

IMO, there should be:

  • cast() removes all qualifiers.
  • cast(!qualifier ...) removes the given qualifier (only one)
  • cast(qualifiers ...) adds the given qualifiers (at least one must be given)
  • cast(... !attribute) removes the given (member) function attribute from a function / delegate type
  • cast(... attributes) adds the given (member) function attributes to a function / delegate type
shared inout void delegate() @safe const dg;

cast() dg; // void delegate() const @safe
cast(!shared ...) dg; // inout void delegate() const @safe
cast(-shared ...) dg; // inout void delegate() const @safe
cast(-const ...) dg; // error, `dg` isn’t const
cast(const ...) dg; // const inout shared void delegate() const @safe
cast(... !const) dg; // inout shared void delegate() @safe
cast(... !@safe) dg; // inout shared void delegate() const
cast(... !pure) dg; // inout shared void delegate() const @safe
cast(... -pure) dg; // error, `dg` isn’t pure
cast(... pure nothrow) dg; // const inout shared void delegate() const nothrow pure @safe
February 07

On Wednesday, 5 February 2025 at 11:22:59 UTC, Quirin Schroll wrote:

>

On Monday, 3 February 2025 at 18:38:51 UTC, Atila Neves wrote:

>

[...]

I addressed this enhancement with that.

[...]

This is complicated, but I understand why.

February 15

On Wednesday, 5 February 2025 at 11:22:59 UTC, Quirin Schroll wrote:

>

I generally dislike the qualifier casts because they override all existing qualifiers.

  • cast(qualifiers) removes all qualifiers, then adds the given qualifiers (includes cast()).

It’s a blunt tool that makes making precise cuts hard. You locked a mutex and and now are good to go with casting away shared? Well, too bad, you did cast() and also removed a const, welcome to UB town. You made sure some C API doesn’t mutate your stuff and cast away const? Well, too bad, you also cast away shared and now you’re debugging race conditions.

My idea is to use ... to abbreviate the type of the operand within the cast; that would make cast(...) a no-op.
Qualifier manipulations go in front of ... and (member) function attribute manipulations trail behind. cast(const ... const) dg adds(!) const both as a qualifier and a member function attribute to the type of dg.

[...]

>
shared inout void delegate() @safe const dg;

cast() dg; // void delegate() const @safe
cast(!shared ...) dg; // inout void delegate() const @safe
cast(-shared ...) dg; // inout void delegate() const @safe
cast(-const ...) dg; // error, `dg` isn’t const
cast(const ...) dg; // const inout shared void delegate() const @safe
cast(... !const) dg; // inout shared void delegate() @safe
cast(... !@safe) dg; // inout shared void delegate() const
cast(... !pure) dg; // inout shared void delegate() const @safe
cast(... -pure) dg; // error, `dg` isn’t pure
cast(... pure nothrow) dg; // const inout shared void delegate() const nothrow pure @safe

I understand where you're coming from but unfortunately the result looks like line noise.

Even if it's more verbose, I would much rather read code like the following:

alias Dg = typeof(dg);
cast(Unshared!Dg) dg; // inout void delegate() const @safe
cast(UnconstContext!Dg) dg; // inout shared void delegate() @safe
cast(Unsafe!Dg) dg; // inout shared void delegate() const
cast(Impure!Dg) dg; // inout shared void delegate() const @safe
cast(Pure!(Nothrow!Dg)) dg; // const inout shared void delegate() const nothrow pure @safe
February 17

On Saturday, 15 February 2025 at 13:28:38 UTC, Paul Backus wrote:

>

On Wednesday, 5 February 2025 at 11:22:59 UTC, Quirin Schroll wrote:

>

I generally dislike the qualifier casts because they override all existing qualifiers.

  • cast(qualifiers) removes all qualifiers, then adds the given qualifiers (includes cast()).

It’s a blunt tool that makes making precise cuts hard. You locked a mutex and and now are good to go with casting away shared? Well, too bad, you did cast() and also removed a const, welcome to UB town. You made sure some C API doesn’t mutate your stuff and cast away const? Well, too bad, you also cast away shared and now you’re debugging race conditions.

My idea is to use ... to abbreviate the type of the operand within the cast; that would make cast(...) a no-op.
Qualifier manipulations go in front of ... and (member) function attribute manipulations trail behind. cast(const ... const) dg adds(!) const both as a qualifier and a member function attribute to the type of dg.

[...]

>
shared inout void delegate() @safe const dg;

cast() dg; // void delegate() const @safe
cast(!shared ...) dg; // inout void delegate() const @safe
cast(-shared ...) dg; // inout void delegate() const @safe
cast(-const ...) dg; // error, `dg` isn’t const
cast(const ...) dg; // const inout shared void delegate() const @safe
cast(... !const) dg; // inout shared void delegate() @safe
cast(... !@safe) dg; // inout shared void delegate() const
cast(... !pure) dg; // inout shared void delegate() const @safe
cast(... -pure) dg; // error, `dg` isn’t pure
cast(... pure nothrow) dg; // const inout shared void delegate() const nothrow pure @safe

I understand where you're coming from but unfortunately the result looks like line noise.

Remember that you generally won’t do this too often anyway.

>

Even if it's more verbose, I would much rather read code like the following:

alias Dg = typeof(dg);
cast(Unshared!Dg) dg; // inout void delegate() const @safe
cast(UnconstContext!Dg) dg; // inout shared void delegate() @safe
cast(Unsafe!Dg) dg; // inout shared void delegate() const
cast(Impure!Dg) dg; // inout shared void delegate() const @safe
cast(Pure!(Nothrow!Dg)) dg; // const inout shared void delegate() const nothrow pure @safe

This is template instantiation hell.

February 17

On Monday, 17 February 2025 at 11:26:59 UTC, Quirin Schroll wrote:

>

On Saturday, 15 February 2025 at 13:28:38 UTC, Paul Backus wrote:

>

I understand where you're coming from but unfortunately the result looks like line noise.

Remember that you generally won’t do this too often anyway.

The problem isn't that it's annoying to type, it's that it makes the resulting code unreadable. Every single time I run into this reading code, I'm going to have to pull up the relevant part of the language spec to figure out what the hell it's doing.

> >
alias Dg = typeof(dg);
cast(Unshared!Dg) dg; // inout void delegate() const @safe
cast(UnconstContext!Dg) dg; // inout shared void delegate() @safe
cast(Unsafe!Dg) dg; // inout shared void delegate() const
cast(Impure!Dg) dg; // inout shared void delegate() const @safe
cast(Pure!(Nothrow!Dg)) dg; // const inout shared void delegate() const nothrow pure @safe

This is template instantiation hell.

This is a non-argument. What specifically is the negative consequence of template instantiation in this context?