The state of string interpolation

Neia Neutuladh neia at ikeran.org
Thu Dec 6 02:14:12 UTC 2018


On Thu, 06 Dec 2018 00:10:56 +0000, o wrote:
> And please don't mention Phobos' sorry excuse for string interpolation:
> "a is: %s, b is: %s, sum is %s.".format(a, b, a + b)
> Is no better than "a is: "~a.to!string~"b is: "~b.to!string~" and the
> sum is: "~(a+b).to!string~"."

I mean, let's not be hyperbolic. Or contemptuous. format() is a lot more 
readable than a bunch of concatenation for a lot of things. It gives you a 
coherent view of the structure of the string as a whole. As a tradeoff, 
it's harder to see the relationship between the format specifiers and the 
parameters.

String interpolation gets rid of that tradeoff.

However, that would also force druntime to include formatting code that it 
currently lacks. It's very likely that this would have some 
inconsistencies with std.conv. Like, the most straightforward way to make 
this work is to have a runtime function taking variadic arguments:

    string _d_stringinterpc(...);
    wstring _d_stringinterpw(...);
    dstring _d_stringinterpd(...);

That would allow a pluggable approach, which allows for the maximum amount 
of compatibility.

So you write:

    auto bar = "hello world".lazyReplace('l', 'p');
    writeln("foo ${bar}");

This compiles down to:

    writeln(_d_stringinterpc("foo ", bar));

And it prints:

    foo scratch.LazyReplacementRange!(immutable(char), 
string).LazyReplacementRange

lazyReplace returns a LazyReplacementRange, which doesn't define 
toString(). Its corresponding TypeInfo_Struct doesn't have a xtoString 
function pointer set, so we can't convert it to a string by 
calling .toString() on it (even indirectly through reflection). We can't 
list its properties and fields at runtime, so we can't iterate through it 
like std.format would. We can't even assemble a toString() that looks like 
the default for structs in std.conv.

The only thing we have available is the name of the type.

In 2007, this would have worked.

----

Okay, it's bad to use that sort of runtime function. What about putting a 
template inside object.d?

That would require us to put std.conv and std.format into object.d. It 
wouldn't be even remotely pluggable.

This isn't an issue in most languages. Most languages tie their standard 
libraries to their compilers. D maintains a greater separation than 
normal, in part because of the Tango / Phobos separation.


More information about the Digitalmars-d mailing list