Discussion Thread: DIP 1036--String Interpolation Tuple Literals--Community Review Round 2

Adam D. Ruppe destructionator at gmail.com
Thu Feb 4 13:44:48 UTC 2021


On Thursday, 4 February 2021 at 07:09:07 UTC, Daniel N wrote:
> With a plain tuple it is possible to create a wrapper which 
> generates DIP1036 style lowering (or simply work directly in 
> the template with the value params).

That forces CTFE evaluation of *everything* which is pretty 
useless.

int bar;
fun!(i"foo {$bar+5}"); // bar cannot be evaluated at compile time

Only the literals themselves should be in the compile time tuple, 
with the rest of them staying right where they are (which can be 
either side). It is impossible to express that in a library, 
since to call a library function/instantiate a library template, 
you must choose one or the other! (The exception being if the lib 
function works only in terms of strings, and you use mixin at the 
call site.)

That's really the reason why this is proposed a language feature 
in the first place. A library *can't* do it well.

> 3) Unavoidable Bloat <- Current DIP1036

There's a lot of FUD around the community about templates lately 
and while there's a kernel of truth to it, it is massively 
overblown.

The only part of the template that is kept at runtime at all is 
the toString method, and it is trivial - return string literal. 
At the usage point, it is inlined, so I guess it only keeps the 
function body in case someone takes an address of it. A higher 
quality implementation (perhaps an optimized build already does, 
i've only tested my poc on dmd w/o flags) could skip this too and 
the template itself is invisible in the binary.

Inside the compiler, this template instance does add a couple 
entries to the symbol table, but they tend to be very small 
(proportional to the size of the string literal fragment in the 
original code). Where huge symbols become problematic is when 
they are recursive or otherwise nested since that's non-linear 
generated growth. It is rarely, if ever, the result of linear 
growth in the actual written codebase. (Of course, you could 
write some ctfe function that mixes in a huge interpolated string 
that mixes in another huge interpolated string but you can 
deliberately sabotage ctfe in all kinds of other ways too.)

Now, there is something to be said about functions receiving it, 
since i"foo" and i"bar" are different types, so you'd have two 
expansions. Of course, that's also the case with anything else 
you spread too... send X and const X and you get to separate 
instances. D in general could use a "collapse these instances" 
feature.

But even with the status quo, if you just forward converted 
arguments to another function to do the bulk of the work, this 
can also be pretty easily optimized by existing compilers.

void writeln(T...)(T t) {
     foreach(arg; t)
        write(arg.toString);
     write("\n");
}

> Strings are ubiquitous, lowering to a plain tuple is the least 
> possible bloat and also most powerful (support for ref etc), 
> but with my proposed simplification you are now free to opt-in 
> to more advanced meta programming _when you need it_, pay as 
> you go!

Without the string in the compile time tuple from the language, 
you lost most the potential power.


More information about the Digitalmars-d mailing list