Bug 24197 – Allow typeof(return) in template constraints

Status
NEW
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-10-24T15:32:43Z
Last change time
2024-12-13T19:31:17Z
Assigned to
No Owner
Creator
Bolpat
See also
https://issues.dlang.org/show_bug.cgi?id=20595
Moved to GitHub: dmd#18192 →

Comments

Comment #0 by qs.il.paperinik — 2023-10-24T15:32:43Z
This is from the first question of [DConf '23 Day 2 Keynote](https://youtu.be/3iWn4S8JV8g?t=2323): How do I communicate to the user of a function template that the return type is a range? The compiler has all it needs to check it (per template instance). We just cannot express it with D’s syntax. I see two solutions: SOLUTION 1: Make template `if` constraints work with `typeof(return)` even if it’s inferred by deferring the constraint check. SOLUTION 2: Introduce a new kind of template constraint that’s checked after instantiation, a template `assert`. I’d guess that Solution 2 is easier to implement and communicates better. I like both solutions, tho. ## Solution 1 I have no idea how templates are compiled and how their constraints are checked, but I’ll assume the constraints are checked before the body is instantiated. Of course if `typeof(return)` targets an inferred return type, it cannot be checked before instantiating the template. Because a template constraint is a logical expression tree composed of `&&`s, `||`s and `!`s and other expressions as leafs, I’d imagine it like this: 1. Leaves that contain `typeof(return)` are pretended to be `true` if the leaf is under an even number of negations, otherwise `false`. (They’re essentially skipped.) 2. Then the template is instantiated. If there were `typeof(return)` in step 1, errors are throttled. 3. If the template has constraints with `typeof(return)` (that were skipped), now that the return type is known, the constraints are checked again. (Constraints without `typeof(return)` could be pretended `true` or `false` as above.) If the constraint evaluates to `true`, there were `typeof(return)` in step 1, and throttled errors in step 2, then report the errors of step 2. For the most part, constraints will look like this: ```d auto someAlgo(R)(R range) if (isInputRange!R && isInputRange!(typeof(return))) { … } ``` ## Solution 2 An alternative would be a new construct next to template constraints. I suggest `assert`; while constraints are checked as one of the first steps of template instantiation, template `assert`s would be checked as one of the last steps (at a point the return type is successfully inferred). ```d auto someAlgo(R)(R range) if (isInputRange!R) assert (isInputRange!(typeof(return))) { … } ``` The template `assert` would be essentially a `static assert` the same way a template `if` constraint essentially is a `static if`. Template `if` and template `assert` are the compile-time/static analogue of runtime `in` and `out` function contracts.
Comment #1 by qs.il.paperinik — 2023-10-24T15:44:02Z
This can be done (in a limited extent) in C++20: ```cpp #include <concepts> template<std::integral T> std::integral auto f(T t) { return t + 1; } ```
Comment #2 by b2.temp — 2023-10-24T16:56:45Z
You'll find an alternative syntax idea in https://issues.dlang.org/show_bug.cgi?id=20595. For the functionality in itself, comment #1 suggested to use a static assert in an `out` contract.
Comment #3 by robert.schadek — 2024-12-13T19:31:17Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18192 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB