digitalmars.dip.ideas - cast(function qualifier)
- Atila Neves (3/21) Feb 03 This looks nice.
- Quirin Schroll (48/75) Feb 05 I addressed [this
- Atila Neves (3/9) Feb 07 This is complicated, but I understand why.
- Paul Backus (16/48) Feb 15 [...]
- Quirin Schroll (3/57) Feb 17 This is template instantiation hell.
- Paul Backus (7/23) Feb 17 The problem isn't that it's annoying to type, it's that it makes
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.
Feb 03
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:I addressed [this enhancement](https://github.com/dlang/dmd/issues/19596) 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 ```d 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 ```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.
Feb 05
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:This is complicated, but I understand why.[...]I addressed [this enhancement](https://github.com/dlang/dmd/issues/19596) with that. [...]
Feb 07
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`.[...]```d 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: ```d 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 ```
Feb 15
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:Remember that you generally won’t do this too often anyway.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`.[...]```d 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: ```d 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.
Feb 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: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.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.This is a non-argument. What *specifically* is the negative consequence of template instantiation in this context?```d 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.
Feb 17