Reducing variadic template combinatorics (C++ was onto something)
Steven Schveighoffer
schveiguy at gmail.com
Tue Oct 14 14:44:56 UTC 2025
On Tuesday, 14 October 2025 at 12:30:23 UTC, Dennis wrote:
> Very interesting thing you're bringing up, I'll share my
> thoughts.
>
> On Tuesday, 14 October 2025 at 04:30:49 UTC, Steven
> Schveighoffer wrote:
>> ```d
>> void writelines(T...)(T values)
>> {
>> import std.stdio;
>> static foreach(v; values)
>> writeln(v);
>> }
>> ```
>>
>> Every combination of every type creates a new template
>> instantiation. We only save on instantiations when 2 calls
>> happen to match all their types.
>
> True, but the instantiations are all very short, so they are
> cheap to process and get inlined in an optimized build. In
> theory, it's not much worse than writing the calls yourself
> like in your second example:
>
>> ```d
>> writeln(1); writeln(2); writeln(3); writeln(4);
>> ```
Yes, but it's not just runtime cost. There's cost to the compile
time.
What I'm exploring is that we *have* an unrolled loop -- the
parameter list. If somehow we can harness this into avoiding the
different processing per call to reach the same conclusion,
that's what I'm looking at. Whether this results in some kind of
"best practice" or some special handling the compiler can use to
save some compile time, I'm not sure. But I feel there is
definitely some benefit that can be seen here.
> Much more problematic is:
>
> ```D
> void writelines(T...)(T values)
> {
> static foreach(v; values)
> {
> // *hundreds of lines of implementation for writeln(v)*
> }
> }
> ```
>
> Because then you duplicate the implementation multiple times,
> even though it's probably 99% the same for `int, uint,
> const(int), immutable(uint)` etc. + every variadic combination
> of those. So it's best practice to reduce the number of
> possible template parameter values as early as possible before
> getting to an implementation. Don't instantiate `impl!T` for
> every integral type when `impl!(T.sizeof)` also works.
It's also the same implementation for `int, int, int, int`!
the *hundreds of lines of implementation* is not only repeated
for different types, it's also repeated for the *same* type with
different parameter configuration.
In other words, `writelines(1, 2)` and `writelines(1, 2, 3)`
creates 5 loop bodies, one for each parameter, whereas
`writelines2(1)(2)` and `writelines2(1)(2)(3)` creates one "body"
for int, and that's it.
The compiler compiles and processes all variations of function
calls independently, and sees no benefit from realizing all the
loop bodies are the same.
> Here's a real example of employing this technique:
> https://github.com/dlang/druntime/pull/3852
Nice, yes this is part of it.
>
>> How about we try an operator? (...)
>> And the usage is as you would expect:
>>
>> ```d
>> coutlines << 1 << 2 << 3 << 4;
>> ```
>
> The problem here is that << is meant to do arithmetic, not
> construct a list. In Java you can write `System.out.println(""
> + 1 + 2 + 3 + 4);`, which is better, but + is still also used
> for arithmetic so it's still confusing (as seen by the `"" +`
> required to string concatenate rather than add).
I did not properly convey that I *don't* want this solution. It's
just an exploration of what is possible with the current language.
I dislike C++ iostream operators, and prefer the parameter list
style for writeln. But I had never considered that there is a
*compile time* benefit to the way C++ is doing it.
>> But... I still want to write `writelines(1, 2, 3, 4)`. The
>> ergonomics there are nice! Is there some way we can capture
>> this same reduction in complexity while still keeping the nice
>> syntax?
>
> I'd say: just write a template helper that does nothing but
> forward each argument to another call. If that's somehow
> significantly worse than manually writing 4 function calls,
> investigate why that is and see if that can be fixed.
Right, if nothing else it is a "best practice" on how to avoid
template bloat. But if there is a way we can convey to the
compiler this pattern, it would be very nice!
-Steve
More information about the Digitalmars-d
mailing list