Tuples, CTFE, and Sliding Template Arguments
Timon Gehr
timon.gehr at gmx.ch
Fri Jan 12 23:04:58 UTC 2024
On 1/12/24 23:35, Walter Bright wrote:
> Given the interest in CTFE of istrings, I have been thinking about
> making a general use case out of it instead of one specific to istrings.
> ---------------------
>
> Sliding Template Arguments
>
> Consider the following template:
>
> ```
> void pluto(string s)()
> {
> pragma(msg, s);
> }
>
> void test()
> {
> pluto!"hello"();
> }
> ```
>
> This compiles because `s` is a compile time argument, and `pragma(msg, s)`
> expects s to be a compile time value.
>
> ```
> void pluto()(string s)
> {
> pragma(msg, s);
> }
>
> void test()
> {
> pluto("hello");
> }
> ```
>
> This fails to compile because `s` is a runtime argument that is not
> accessible
> at compile time, even if it is inlined. (Inlining doesn't help here
> because inlining is done after CTFE and semantic analysis.)
>
> Those examples illustrate the difference between a compile time and a
> runtime argument.
>
> For background, to generate a tuple of elements:
>
> ```
> alias AliasSeq(T...) = T;
> ```
> and a function argument list that accepts a tuple:
> ```
> void func(Args...)(Args args)
> {
> }
> ```
> But notice that `args` are runtime arguments. It turns out there is no way
> to use tuples to split an argument tuple into compile time and runtime
> tuples:
>
> ```
> void pluto(Args...)(Args args)
> {
> exec!(args[0])(args[1 .. args.length]);
> }
> ```
> This is the problem that DIP1036e ran into. It's clever solution is to
> have the compiler (because it cannot be done with metaprogramming) take
> the first argument, and use it as a compile time argument to a templated
> dummy value. Then, the type of that argument is a template with the
> value encoded into the type, which can be programmatically extracted and
> then processed at compile time.
>
> The awkwardness of this is it only happens with istrings, it is not a
> general purpose capability, plus the insertion of dummy arguments into
> the argument list just so their types can be extracted.
>
> Hence, the genesis of this proposal which describes a language
> capability to create a compile time parameter from a tuple of runtime
> expressions.
>
> For lack of a better term, I'll call it "Sliding Template Arguments".
>
> Consider a template function:
>
> ```
> void pluto(string s, Args...)(Args args)
> {
> pragma(msg, s);
> }
>
> void exec()
> {
> pluto!"hello"(1,2,3);
> }
> ```
> which works now. But this fails to compile:
> ```
> pluto("hello",1,2,3);
> ```
> because there is no argument for `s`.
>
> So, instead of issuing a compilation error, the compiler can "slide" the
> arguments to the left, so the first argument is moved into the compile
> time parameter list. Then, the call will compile.
>
> The rule would be something like:
>
> 1. the function is a template taking a variadic runtime argument list
> 2. the compile time parameters are a sequence of N value parameters,
> followed by
> the variadic type parameter.
> 3. the value parameters do not have default values
> 4. no compile time arguments are provided in the template invocation
> 5. the leftmost N runtime arguments are matched against the compile time
> parameters,
> and removed from the runtime argument list
> 6. if they match, then the template instantiation is rewritten to
> reflect this
> 7. compilation then proceeds normally
>
> Template Sliding thus becomes a general use facility. One interesting
> consequence of this is it opens up a whole new class of functions that
> can now do CTFE computations on the leftmost arguments.
Generally I think this is a good idea, but the proposed syntax is a bit
too specialized, arbitrarily restricted and the behavior may be
unexpected and should be opt-in instead.
Maybe we can do it like this instead:
```d
void pluto(string s, Args...)(enum string x = s, Args args){
}
```
I.e., you can use `enum` in a function argument list and you have to
default-initialize them. This means that this parameter always needs to
have exactly that value.
Then, the arguments matched to an `enum` parameter are evaluated at
compile time and matched against the initializer.
More information about the Digitalmars-d
mailing list