Bug 23666 – Recognize template opApply pattern

Status
NEW
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-02-02T17:15:13Z
Last change time
2024-12-13T19:27:04Z
Keywords
pull
Assigned to
No Owner
Creator
Bolpat
Moved to GitHub: dmd#20224 →

Comments

Comment #0 by qs.il.paperinik — 2023-02-02T17:15:13Z
Normally, when `opApply` is a template, `foreach` variable types cannot be inferred and must be stated explicitly. I propose an exception to this rule to make implementing `opApply` with respect to attributes (safe, nogc, pure, nothrow) easier[1, 2]. Basic idea: Make `opApply` a template to infer attributes based on the delegate argument’s type. If `opApply` is a template with a single template type parameter that is used as the type of the single function parameter and is additioanlly constrained to a delegate type, we can use that type to infer `foreach` variable types. A minimal example: ```d struct S { int opApply(DG : int delegate(int))(DG dg) { return 0; } } void main() @safe { foreach (x; S()) // infer `int` for x { } } ``` Details: When all `opApply` function templates in an aggregate have as their first template parameter a type parameter that is “aptly” constrained[5] (“aptly” defined blow), the respective instantiations with the constraint type are valid (i.e. instantiate `opApply(DG : Constraint)` as `opApply!Constraint`), and the resulting template instance (a member function) can be called with 1 argument of the type of the constraint (i.e. `opApply!Constraint(Constraint.init)` compiles), these member function templates are added to non-template `opApply` member functions used to determine `foreach` types. To be “aptly constrained” means that the constraint is a type of the following form: ```d int delegate ParameterList MemberFunctionAttributes` ``` where `ParameterList` and `MemberFunctionAttributes` [3, 4] are defined in the D grammar. The parameters of the `ParameterList` in an “apt” constraint are considered together with `ParameterList`s of non-template `opApply(int delegate ParameterList MemberFunctionAttributes)` (if any) to find the best match in terms of number and `ref`-ness. If the best match for a given `foreach` statement is such a template instance, it is instantiated again with the type of the `foreach` lambda, where the types of the `foreach` body lambda’s parameters are set to the types determied by the constraint in the `opApply` template. A template `opApply` may have more than one template parameter and more than one function parameter when the additional parameters have defaults. [1] Relevant thread: https://forum.dlang.org/thread/[email protected] [2] Relevant post: https://forum.dlang.org/post/[email protected] [3] https://dlang.org/spec/function.html#Parameters [4] https://dlang.org/spec/function.html#MemberFunctionAttributes [5] https://dlang.org/spec/template.html#Constraint
Comment #1 by qs.il.paperinik — 2023-02-06T18:30:37Z
Generalization: To be “aptly constrained” means that the constraint is a type of the following form: ```d Int delegate ParameterList MemberFunctionAttributes` ``` where `ParameterList` and `MemberFunctionAttributes` [3, 4] are defined in the D grammar, and Int is `int` with any type constructors (`const`, `inout`, `shared`) applied to it (they don’t matter anyways), but it shouldn’t fail because some type inference made it e.g. `const`.
Comment #2 by nick — 2023-12-12T17:41:14Z
You can use `auto opApply` to infer attributes instead of a template.
Comment #3 by qs.il.paperinik — 2024-05-29T10:15:49Z
(In reply to Nick Treleaven from comment #2) > You can use `auto opApply` to infer attributes instead of a template. ```d struct S { auto opApply(int delegate(ref int) callback) { int x; return callback(x); } } void main() @safe { foreach (ref x; S()) {} // Error: `@safe` function `D main` cannot call `@system` function `S.opApply` } ``` However, this does (for reasons beyond my understanding): ```d struct S { int opApplyImpl(DG : int delegate(ref int))(scope DG callback) { int x; return callback(x); } alias opApply = opApplyImpl!(int delegate(ref int)); } void main() @safe { foreach (ref x; S()) {} } ```
Comment #4 by nick — 2024-05-31T09:56:45Z
Sorry, yes. This proposal seems workable.
Comment #5 by dlang-bot — 2024-06-26T16:49:29Z
@Bolpat created dlang/dlang.org pull request #3859 "Specify `opApply` as an alias to a function template instance" fixing this issue: - Fix Bugzilla Issues 23666, 17953, 23116, and 24633 https://github.com/dlang/dlang.org/pull/3859
Comment #6 by robert.schadek — 2024-12-13T19:27:04Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/20224 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB