February 27, 2020
On Thursday, 27 February 2020 at 00:21:36 UTC, Walter Bright wrote:
> So would DIP1027.

We know. It is *almost* there, the format string idea is a good one. But DIP1027 had a fatal flaw: it made type safety impossible.

One small change - wrapping the format string in a new type while keeping the rest of the tuple exactly the same - fixes that fatal flaw. And as a cool bonus, the simple fact that there's a type around it - with no special rules; it is just a struct to identify that it is a format string - unlocks more potential with it too.

I tried to put it as a dip back on Feb 4 (and it is now on github: https://github.com/dlang/DIPs/pull/186 ) but I don't know how to word this in spec language. I'm a D programmer, not a spec author :(
February 26, 2020
On 2/26/2020 4:46 PM, Adam D. Ruppe wrote:
> But DIP1027 had a fatal flaw: it made type safety impossible.

I don't see how that is true.
February 27, 2020
On Thursday, 27 February 2020 at 03:50:35 UTC, Walter Bright wrote:
> On 2/26/2020 4:46 PM, Adam D. Ruppe wrote:
>> But DIP1027 had a fatal flaw: it made type safety impossible.
>
> I don't see how that is true.

Because it turned a format string into a list of built-in types indistinguishable from a set of manual parameters. You cannot in principle tell the difference between "test $i" and ("test %s", i) - you cannot write a function that takes a string and then *any other type* and is also protected from being accidentally called with a format string.

Features should be as simple as they can be, but no simpler. - The point of simplicity is predictability. DIP1027 is so simple that it crosses back into surprising.
February 27, 2020
On Thursday, 27 February 2020 at 00:20:27 UTC, Walter Bright wrote:
> On 2/26/2020 3:13 AM, Petar Kirov [ZombineDev] wrote:
>> In all other languages with string interpolation that I'm familiar with, `a` is not passed to the `i` parameter.
>
> All rely on a garbage collected string being generated as an intermediate variable.

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, while if D decided to be different than all other languages w.r.t. string interpolation, most newcomers would consider this a bad thing and not elegant and innovative as we are aiming for.

I agree with Adam, Steven and others that string interpolation expression should yield a distinct type and not a tuple. By doing this we would be able to overload functions so they could accept both strings (which would cause GC allocation when the argument is a interpolated string), and the new distinct type, in which case the allocation could be avoided.
February 27, 2020
On 2/26/2020 10:38 PM, FeepingCreature wrote:
> On Thursday, 27 February 2020 at 03:50:35 UTC, Walter Bright wrote:
>> On 2/26/2020 4:46 PM, Adam D. Ruppe wrote:
>>> But DIP1027 had a fatal flaw: it made type safety impossible.
>>
>> I don't see how that is true.
> 
> Because it turned a format string into a list of built-in types indistinguishable from a set of manual parameters. You cannot in principle tell the difference between "test $i" and ("test %s", i) - you cannot write a function that takes a string and then *any other type* and is also protected from being accidentally called with a format string.

That isn't a type safety error.
February 27, 2020
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.

> 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.

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. 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.
February 27, 2020
On 2/26/2020 7:41 AM, Arine wrote:
> Yah, what's unwanted about that?

1. unwanted extra string allocation
2. poor performance
3. doesn't work with printf
4. doesn't work with writef
5. non-default formats require extra temp strings to be generated
February 27, 2020

On 27/02/2020 01:20, Walter Bright wrote:
> On 2/26/2020 3:13 AM, Petar Kirov [ZombineDev] wrote:
>> In all other languages with string interpolation that I'm familiar with, `a` is not passed to the `i` parameter.
> 
> All rely on a garbage collected string being generated as an intermediate variable.

The string buffer could also be stack allocated or manually managed with malloc/free by the string interpolation type.
February 27, 2020
On Thursday, 27 February 2020 at 09:45:06 UTC, Rainer Schuetze wrote:
> On 27/02/2020 01:20, Walter Bright wrote:
>> On 2/26/2020 3:13 AM, Petar Kirov [ZombineDev] wrote:
>>> In all other languages with string interpolation that I'm familiar with, `a` is not passed to the `i` parameter.
>> 
>> All rely on a garbage collected string being generated as an intermediate variable.
>
> The string buffer could also be stack allocated or manually managed with malloc/free by the string interpolation type.

Don't forget LDC does GC to stack optimisations. There ought to be no need to do anything manually if you care about perf.
February 27, 2020
On Thursday, 27 February 2020 at 09:34:23 UTC, Walter Bright wrote:
> On 2/26/2020 7:41 AM, Arine wrote:
>> Yah, what's unwanted about that?
>
> 1. unwanted extra string allocation
> 2. poor performance
> 3. doesn't work with printf
> 4. doesn't work with writef
> 5. non-default formats require extra temp strings to be generated

Pretty sure he meant that this call:

int a;
CreateWindow(i"Title $a");

Would call CreateWindow like:

CreateWindow("Title %s", a);

Which is what is unwanted.

Btw: with the adam-steve-twist you fix everything that is unwanted, including enforcing explicitness when someone wants it to act as a string, without the danger of mistakenly calling the wrong overloads of functions because of switching to string interpolation.

And it seems to me there's precedent in typeid

i.e. typeid is an construct in D that lowers to a TypeInfo type, which is defined somewhere (is that object.d?) Anyway. The same would happen with the interpolated string.

Btw: Swift does this for string interpolation and it works very well -> https://www.hackingwithswift.com/articles/178/super-powered-string-interpolation-in-swift-5-0