DIP 1027---String Interpolation---Format Assessment

Petar Petar
Thu Feb 27 14:32:29 UTC 2020


On Thursday, 27 February 2020 at 09:30:30 UTC, Walter Bright 
wrote:
> On 2/27/2020 12:27 AM, Petar Kirov [ZombineDev] wrote:
>> I'm well aware that allocation is inevitable if we want this 
>> behavior. My argument is that this behavior is so ubiquitous 
>> that not following it would be surprising to much more people, 
>> than if D didn't follow C's Usual Arithmetic Conversions 
>> rules. For example, Rust not following those conversion rules 
>> is considered a good thing,
>
> Rust does not follow C syntax at all, so nobody will reasonably 
> expect it to have C semantics. D does follow it, it's a 
> feature, so people will have expectations.

I'm not sure where exactly you draw the line, but I would say 
that C# follows C's syntax about as much as D does. Yet it 
doesn't import some of the broken C semantics like implicit 
narrowing conversions (luckily, neither does D) and allowing 
mixed sign comparisons (the oldest open D issue :( [0]).

My point is that if D didn't follow the usual arithmetic 
conversions, much fewer newcomers would even notice compared to 
extremely large backlash that we may get if go with the string 
interpolation -> raw tuple approach.

[0]: https://issues.dlang.org/show_bug.cgi?id=259

>> while if D decided to be different than all other languages 
>> w.r.t. string interpolation,
>
> You can make it behave like all those other languages simply 
> with:
>
>     f(format("hello $a"));
>
> and there it is. But having it generate a GC allocated string 
> is not so easy to unwind, i.e. it'll be useless with printf and 
> generate unacceptable garbage with writefln. The extra string 
> will always make it slow. Essentially, it'll be crippled. 
> Making D behave like a scripting language will yield scripting 
> performance.

I know, I know. Though I think you misunderstood. There several 
ways to make printf work with zero allocations. For example:

1. Have a simple pragma(inline, true) wrapper function that will 
convert the distinct type to printf-style args. This wrapper 
function can even be named printf as it would work by virtue of 
function overloading. This is O(1) additional code that once 
written no one will need to bother with.

2. Have the new type implicitly convert to printf-style args. I 
think this is what Adam is proposing. While nice to have, I don't 
think it's necessary.

As for std.stdio.write(f)(ln), there's no reason why any garbage 
would need to be created, as again, a simple overload that 
accepts the distinct type will be able to handle it just like it 
would (performance-wise) with DIP1027. However, with DIP1027, 
only writef and writefln can be used, while write and writeln 
will produce wrong results (wrong according to people that have 
used string interpolation in other languages).

> D is a language built up from simple, orthogonal parts (or at 
> least that is a goal). A language built from larger indivisible 
> parts is much, much less user-adaptable.

I appreciate the sentiment. Having orthogonal features in D is 
important to me as well. However, I think DIP1027 falls short 
here because it produces a single format string and that way 
loses all of the structure. This is ok for printf, but not for 
third-party libraries and even our own std.format, as with a 
distinct type we won't need to parse the whole format string at 
all, just the individual format specifiers. In other words, a 
distinct type would make nothrow std.format a much more tractable 
problem (at least for some cases).

> An example of this is the built-in associative array, which has 
> a series of
> fairly intractable problems as a result. Another example is the 
> built-in
> complex type in D, which turned out to be a bad idea - a much 
> better one is
> building it as a library type.

AFAIR, most of the problems with D's built-in AAs are that they 
have an extern (C) interface that relies on typeinfo. If they are 
fully converted to templated library types, the situation would 
be much better. IIRC, one of the blocking issues was that D 
didn't have autovivification [1] operators, so a library type 
wouldn't be a complete replacement without additional help from 
the compiler.

So in conclusion, having a distinct library-defined type (in 
druntime) seems the best way to go to me, as it's more flexible 
than raw tuples, could allow easy GC-backed conversion to string 
for script-like code and would offer a superset of the 
functionality that DIP1027 would offer, while still allowing easy 
(although not 100% direct) calls to printf.

[1]: https://en.wikipedia.org/wiki/Autovivification


More information about the Digitalmars-d-announce mailing list