www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - cast(function qualifier)

reply Atila Neves <atila.neves gmail.com> writes:
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
parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
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:

 ```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.
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 ```
Feb 05
next sibling parent Atila Neves <atila.neves gmail.com> writes:
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](https://github.com/dlang/dmd/issues/19596) with that. [...]
This is complicated, but I understand why.
Feb 07
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
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
parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
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`.
[...]
 ```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.
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:

 ```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
parent Paul Backus <snarwin gmail.com> writes:
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.
 ```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.
This is a non-argument. What *specifically* is the negative consequence of template instantiation in this context?
Feb 17