December 11, 2019
On Wednesday, 11 December 2019 at 23:09:01 UTC, Bastiaan Veelo wrote:
> Isn’t https://forum.dlang.org/post/vxzqttydlvzngrwrvipa@forum.dlang.org better still? Streamlining template mixins could pay off in many more places, and is truly extendable and customisable.

Seems I’m mixing up template and string mixins.

December 11, 2019
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
> This is the feedback thread for the first round of Community Review for DIP 1027, "String Interpolation":
>
> https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
>

Questions for the rationale:

1. Why % as a format character?

I would guess "so that legacy strings won't accidentally
trigger interpolation", but since this proposal already
requires i"" syntax, legacy strings aren't a problem.

Or "wanting to specify the formatting, as with %{d}bananas,
meant I had to come up with something new anyway." But Nim,
Zig, and Python all do this (the first two as normal library
functionality rather than a language extension) with the {}
syntax.

  import strformat
  let num = 123
  echo fmt"{num}"    # output: 123
  echo fmt"{num:x}"  # output: 7b

Alternate syntax ({} interpolation):

  writefln(i"I ate {apples} and {bananas:d} totalling {apples + bananas} fruit.");

2. Why i"" syntax?

It (presumably, not necessarily) conflicts with user string
prefixes, and since this proposal already limits string
interpolation to printf-style uses, and since the use of %
format character already makes conflict with legacy strings
already very unlikely, why not use regular string syntax but
make writefln() and friends statically analyze the string
they're given to see if it's an interpolating one or not?

Alternate syntax (no i""; in(isTemplated!argstring)):

  writefln("I ate %apples and %{d}bananas totalling %(apples + bananas) fruit.");

3. Why rewrite to positional code?

I would guess "because I don't want to add new GC-reliant
features", but since this proposal already limits string
interpolation to printf-style uses, the function accepting the
string is an obvious owner.

The positional rewrite has other problems:

a. interpolated strings can't be mixed with conventional
elements, a common and unremarkable thing for interpolation in
other languages.

b. functions that accept an interpolated string have to know
that they do this, and have special handling for it, when in
other languages the choice to interpolate is purely a decision
of the caller's, and can be changed for readability or
efficiency or taste.

c. Speaking of efficiency: in other languages you can hoist a
repeated use of an interpolated string above some loops that
use it. With this proposal you'd have to rely on the optimizer
to deal with this.

4. Seriously, why rewrite to positional code?

This is going to function as something like an attractive
nuisance for people that learn D.

Newbie: "Hey, I want some interpolation here. Does D have that? Oh! It
does!"

Newbie: *uses interpolation, gets error*

Newbie: "what?"

Newbie: ... this D thing, it's filled with features with
strange limitations. Features that don't work naturally
together. Come on even a simple thing like string
interpolation! That's convenient in every language that has it!
Why is it so weird here? This is just like how the other day I
tried to rewrite a trivial benchmark in -betterC and kept
getting weird errors about TypeInfos. grumble grumble grumble.

*** meanwhile, in a world without interpolation ***

Newbie: "Hey, I want some interpolation here. Does D have that?
... looks like format() does what I want."

Newbie: *uses format(), it works as expected, life moves on*

--
Final "but since this proposal already" count: 3
December 11, 2019
On Wednesday, 11 December 2019 at 23:17:37 UTC, Bastiaan Veelo wrote:
> On Wednesday, 11 December 2019 at 20:57:35 UTC, Ola Fosheim Grøstad wrote:
>> immutable s = f!!"My name is {this.name}";
>
> I like this. A universal improvement that also happens to enable all kinds of string interpolation, including SQL.
Another option is to add unicode support:

    fmt«I am {name}!»

==>

    mixin(fmt!"I am {name}!")

(on my mac I get those symbols by hitting alt-shift-v and alt-shift-b)

December 12, 2019
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
> This is the feedback thread for the first round of Community Review for DIP 1027, "String Interpolation":
>
> https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
>
> All review-related feedback on and discussion of the DIP should occur in this thread. The review period will end at 11:59 PM ET on December 25, or when I make a post declaring it complete.
>
> At the end of Round 1, if further review is deemed necessary, the DIP will be scheduled for another round of Community Review. Otherwise, it will be queued for the Final Review and Formal Assessment.
>
> Anyone intending to post feedback in this thread is expected to be familiar with the reviewer guidelines:
>
> https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md
>
> *Please stay on topic!*
>
> Thanks in advance to all who participate.

1. The DIP fails to mention why this has been chosen as better over the other alternatives out there.

2. Why %?
  a) it clashes with format specifiers, sounds like a bad idea.
  b) it's more common in text than other alternatives (e.g. $) which means it increases making the user escape text.

3. How does this work with normal strings? And token strings? One use-case I've been looking forward to is generative programming with token strings and interpolated strings. This doesn't seem to help there? If not, why a half solution? If it does, then maybe an example?

4. How is this handled?

auto d = 7;
writefln(i"I ate %apples and %{d}bananas totalling %(apples + bananas) fruit.");

// bug? silent failure? compiler error? Does it do what the user expects?

5. I believe you can do everything this DIP does with a better syntax -> "$itemPrice%.2f" where $ is the identifier and after the % is the formatting. And you don't have to deal with that * runtime error

6. What's the rationale behind allowing anything other than %s? The type of variable can be inferred?

Cheers,
- Ali



December 12, 2019
On Wednesday, 11 December 2019 at 19:34:01 UTC, Patrick Schluter wrote:
>
> So you complexified your code because of a restriction of the language.

Not at all, before I was trying to do to much.
With multiple format calls, I made the code boring
and easy to follow.
>
>>
>> Not being able to use * will stop me using this feature in many places.
>>
>>
>> The rationale about "missing arguments, wrong format specifier,... " Is a mute point IMO. format!"%d"(13.37) does
>
> MOOT not mute
>
>> the same thing already without any language change.
>> I thought the idea was not to introduce language changes if a library solution can do most of it already.
>> I find that the readability argument is highly subjective.
>
> It is but it is also true that from more than 4 parameters in a format string it gets more and more noisy.

True, so you would split up the code, right!?
If both format styles don't work with more than x arguments,
why do I need to styles to not get the work done.
One is enough to shoot myself in the foot, isn't it.

>
>> The first part of the rationale is, IHO,
>> already pointing to the solution. Short strings are easy to manage.
>> So let's promote short strings in
>> combination with format!"%s" and
>> output ranges.
>>
>> How will this feature work at CT.
>> Format doesn't even work completely at CT.
>
> It's a problem with format and is perpendicular to this DIP, i.e. if this DIP is adopted or not, it will not change anything to the issues of format.

Why do we need it then?

>
>>
>> I know this goes a bit off topic,
>> but IMO this is a feature that is wanted,
>> because other languages have it.
>> And we want to say we have it too.
>
> May be sometimes it is good to look why certain features are spreading like wildfire. C format specifiers were a regression compared to what was available at that time (in Pascal or even Cobol), but as C had so much other things to it, people tended to accept the strange and ugly printf formatting, but it's clear that i was universally loathed. That's why C++ tried this worse shift syntax and other languages tried other solutions.
> It is not because we in the end managed to get used to the outdated and dangerous printf format that it is good in the first place.
> This DIP is simple enough that it is a good candidate imho to be tried.
format!""() is not dangerous, if it is please show me why, I
use it all over the place.
I'm also not sure why it is outdated, format is very flexible
and powerful, i.e. array formatting is just awesome.



December 12, 2019
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
> This is the feedback thread for the first round of Community Review for DIP 1027, "String Interpolation":
>
> https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
>
> All review-related feedback on and discussion of the DIP should occur in this thread. The review period will end at 11:59 PM ET on December 25, or when I make a post declaring it complete.
>
> At the end of Round 1, if further review is deemed necessary, the DIP will be scheduled for another round of Community Review. Otherwise, it will be queued for the Final Review and Formal Assessment.
>
> Anyone intending to post feedback in this thread is expected to be familiar with the reviewer guidelines:
>
> https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md
>
> *Please stay on topic!*
>
> Thanks in advance to all who participate.

Lowering interpolated strings to a format string and a tuple of values rather than just a tuple is less versatile than other solutions that have previously been proposed.  This DIP pigeon-holes interpolated strings for one use case.  Interpolated strings can be used for more than just creating strings.  They are just a pretty syntax to interleave string literals and expressions. This solution is assuming the user will only use this for string formatting, but that's not necessarily the case.

My original proposal lowered it directly to a tuple of string literals and expressions (https://github.com/dlang/dmd/pull/7988) and Adam Ruppe's proposal (http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html) lowered it to a custom type where the same tuple could be accessed via a field.  These solutions provide more versatility and are just as easy to print and format into strings with a single function call. Adam Ruppe's proposal was more complex than my own but improved versatility (i.e. added a method to convert it to a string without importing a module, allowed functions to overload on interpoated strings, provided access to the original raw un-interpolated string, etc).  The problem with this DIP is that it's both more complex than my original proposal and less versatile.

The other problem with this DIP is how it handles consecutive interpolated strings.  Consider a case where you'd like to write a message with consecutive interpolated strings (see real life example here https://github.com/dlang/dmd/pull/7988/files#diff-685230fdddcb87fcbb4a344b264a2fb6L736):

// using this DIP
writefln(i" ... %a ... ", i" ... %b ... ");
// becomes
writefln(" ... %s ... ", a, " ... %s ... ", b);
// that doesn't work, so you'd have to do this
writeln(i" ... $(a) ... ".format, i" ... $(b) ... ".format);

// by lowering to a tuple, you would get this
writeln(i" ... %a ... ", i" ... %b ... ");
// becomes
writeln(" ... ", a, " ... ", " ... ", b, " .. ");

I also don't see any mention of my proposal in the DIP in "Prior Work" or how this DIP compares to my proposal or Adam's.

December 12, 2019
On Wednesday, 11 December 2019 at 20:46:03 UTC, Meta wrote:
> On Wednesday, 11 December 2019 at 20:28:21 UTC, Ola Fosheim Grøstad wrote:
>> [...]
>
> Yeah, I think if it comes down to adding a new language feature to the compiler, or changing how mixins behave in such a way that may be cause for security concerns, it's less costly to add the language feature.
>
> Really, though, all that's needed is to allow mixin templates to be mixed in without using the `mixin` keyword (I say "all", but that's quite a large language change):
>
> string interp(string s)()
> {
>     ....
> }
>
> mixin template i(string s)
> {
>     enum i = mixin(interp!s);
> }
>
> auto n = 2, m = 5;
> auto s = i!"The product of ${n} and ${m} is ${n * m}";
> writefln(s);

This would be really cool
December 12, 2019
On Wednesday, 11 December 2019 at 17:49:45 UTC, Meta wrote:
> On Wednesday, 11 December 2019 at 15:55:35 UTC, Patrick Schluter wrote:
>> On Wednesday, 11 December 2019 at 12:50:34 UTC, Ernesto Castellotti wrote:
>>> On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
>>>> [...]
>>>
>>> From the dip it seems that it is only valid for writefln & co
>>> So a code like:
>>>    auto myText = i"I ate% apples"
>>> would not be valid.
>>
>> It is allowed everywhere where a tuple expression is allowed
>>
>> auto myText = "I ate%s", apples
>>
>> doesn't make sense
>
> It works already (un?)fortunately:
>
>     auto test = AliasSeq!("The product of %s and %s is %s", 2, 5, 10);
>     writeln(test);  //Prints "The product of %s and %s is %s2510"
>     writefln(test); //Print   "The product of 2 and 5 is 10"
>
> This DIP is just taking that 1 extra small step to allow i"" strings to be lowered to tuple literals.

Yes this is the purpose of the dip, but it is not what I expect for the string interpolation.
This would require explicitly calling the functions of a library to convert the tuple into a string, I would like it to be done
literals implicitly.

December 12, 2019
On Thursday, 12 December 2019 at 06:47:28 UTC, Ernesto Castellotti wrote:
> On Wednesday, 11 December 2019 at 20:46:03 UTC, Meta wrote:
>> Really, though, all that's needed is to allow mixin templates to be mixed in without using the `mixin` keyword (I say "all", but that's quite a large language change):
>>
>> string interp(string s)()
>> {
>>     ....
>> }
>>
>> mixin template i(string s)
>> {
>>     enum i = mixin(interp!s);
>> }
>>
>> auto n = 2, m = 5;
>> auto s = i!"The product of ${n} and ${m} is ${n * m}";
>> writefln(s);
>
> This would be really cool

One idea I've seen floated in a previous thread is to introduce a new unary operator that could take the place of the "mixin" keyword. So instead of

    auto s = mixin(interp!"My ${vehicle} is full of ${creature}s!");

you could instead write something like this:

    auto s = @interp!"My ${vehicle} is full of ${creature}s!";
December 12, 2019
On Wednesday, 11 December 2019 at 23:33:20 UTC, mipri wrote:
> This is going to function as something like an attractive
> nuisance for people that learn D.
>
> Newbie: "Hey, I want some interpolation here. Does D have that?
> Oh! It
> does!"
>
> Newbie: *uses interpolation, gets error*

I think there's a general rule here:

A DIP that adds an innovative feature, or which enters
poorly-explored design space, can be a conservative "80%
solution" that has some caveats and limitations on its use,
that people learning the language will need to learn to
properly use the feature.

But a DIP that adds a very well explored feature should provide
a 100% solution that adds exactly what people will expect from
"<feature name> in <any language>". It should do this
precisely because people are so well-prepared in their
expectations for any such feature.

Suppose that D didn't have floating point numbers, and a DIP
were released today to add them to the language, but instead of
IEEE floating point, it implemented some novel thing. The
details of the novel thing don't matter: it's not 100% what
people want from "floating point", so it's an embarrassment.

Think of how the documentation would have to read. dlang.org's
own docs, to be useful, would have to explain the feature in
terms of how it fails to meet the expectations of other
languages.

In code, this must all work:

  auto s1 = i"I ate %apples and %{d}bananas.";
  enum pears = "two";
  enum s2 = i"I ate %pears.";
  immutable string s3 = i"%s1";

  void takes_a_normal_string(string s) { }

  takes_a_normal_string(i"%one + %two = %(one + two).");

  // not an error: writefln sees %d in the post-interpolation
  // string and works normally
  writefln(i"making %bread using %%d ingredients", 6);

  string x = qi"SPAM
  Hello %firstname %lastname!
  ...
  SPAM";

Although if i"" is definitely the syntax used, then the
rest of the syntax is free to be something familiar like

  // resembles 14 languages from wikipedia examples
  i"$one + $two = ${one + two}"

or

  // resembles 4 languages
  i"{one} + {two} = {one + two}"

Finally, look at Swift's syntax:

  let apples = 4
  print("I have \(apples) apples")

How about that? Undefined escape sequences are an error, so
new ones can be added without breaking the language or changing
the meaning of old code. And this no longer requires an ugly
'i' prefix.

If the "lower to printf-style arguments" is really what's
wanted, then it could be an *option* with an alternate escape
like \[apples], so people's expectations about string
interpolation would still be met. A 100% solution + some extra
features is a much easier sell.