September 09, 2020
On Tuesday, 8 September 2020 at 10:59:58 UTC, Mike Parker wrote:
> This is the feedback thread for the first round of Community Review of DIP 1036, "Formatted String Tuple Literals".
>

The fear of the gc has negatively impact this DIP. Why does the average programmer have to call .idup when it comes frequent used feature in other languages? If speed is an issue then the solution is to optimized the gc, not avoid it entirely.

We shouldn't let c/c++ fear of the garbage collector  potential handicap new d features here.

-Alex
September 09, 2020
On Wednesday, 9 September 2020 at 18:39:59 UTC, 12345swordy wrote:
> The fear of the gc has negatively impact this DIP.

That decision wasn't made because of the GC. It is more due to working the the variety of use cases in D like ref params, types without toString, compile-time arguments, and more that are all well-defined for argument lists but not in other places.

Perhaps the text should call these out more explicitly.
September 09, 2020
On 9/9/20 12:43 PM, Seb wrote:
> Just to re-state my points:
> 
> 1) I strongly believe that printf shouldn't make up most of the design considerations and DIPs space. This is about a D feature, not C. Trying to bridge both worlds will please none.
> 
> 2) No C string magic: "spec will automatically convert to a compile-time NUL-terminated C string if spec.hasAllSpecs is true." is just a big NO.

It does not take up most of the design consideration, or the DIP's space.

It is a judgment call as to which is more useful. In our opinion, a C library is unlikely to provide bindings that work directly with parsed-out format specifiers, whereas a D function likely could provide those. It's much more likely that a D function would rather provide mechanisms to work directly with the actual spec type than have a conversion to a string happen.

This is basically a free feature on top of the existing implementation. It is not the main focus.

> 3) `${%d}bananas` is an awful syntax compromise as it will be very unintuitive to newcomers as it's not clear what the variable is.
> For example, `${bananas:2f}` would read much better. In general, I like the way Python handles the format specifiers:
> 
> https://www.python.org/dev/peps/pep-0498/#format-specifiers

That is syntactically a problem. Remember that any expression can be the Argument to the string interpolation parameter. A colon followed by 2f could be valid syntax at the end of an expression.

${cond ? 1f:2f}

If there are unambiguous alternatives that would be more acceptable to the language maintainers, we are fine with it, as long as the format string resolves in the way specified with the DIP. Note that this syntax comes directly from DIP1027.

> 4) Format specifiers need to be 100% customizable. The NodeJS community got this right and it lead to a few awesome libraries. One example that has been mentioned before is https://github.com/chalk/chalk

Format specifiers are 100% customizable. You specify whatever you want in the format specifier, or as part of the expression.

> 5) APIs will need to be written specifically to cater for _d_interpolated_strings if no implicit conversion is allowed anyhow, so the interpolated_string struct should always containing its arguments. This would allow for adding methods like `idup`, `toString` etc. directly inside the struct. I don't see the DIP explaining the advantage of doing rewrite magic to `writefln(<interpolationSpec>, apples, bananas, apples + bananas);` and this will only confuse people.
> More importantly, it severely restricts the freedom for function designers as they can not accept two interpolated strings nor argument afters the interpolated string.
> Note that this also removes most-of the problems with "wrong-use of functions".

The issue here is that enclosing the parameters into a single structure has issues with forwarding ref-ness, or binding to aliases or lazy parameters, etc.

> 6) "if a StringLiteral follows an InterpolatedString, it is appended to the InterpolatedString in the parsing pass (not the lexer pass)". Automatic string concatenation was deprecated for good reasons. This DIP does not provide a good motivation for this nor explains how all the risks learned from this are mitigated.

This was copy-pasted from DIP1027. We do not have strong preferences either way. However, forming interpolation string tuples using multiple lines or multiple types of strings should be supported. For sure, explicit concatenation does not work for this instance. Implicit concatenation solves the problem, but I'm open to other ideas.

> 
> 7) A main use-case for interpolated strings is D mixins. It doesn't address combineing it with token strings  to create D code, e.g. `qi{class D { auto $varName = 20; }`

mixin(i""q{class D { auto $varName = 20; });

> 8) A lot of people want `string k = i"foo $bar";` to work and the DIP should at least a very good explanation why the compiler shouldn't rewrite such assignments to `string k = i"foo $bar".idup;` as it's very clear what the user wants here and the @nogc argument applies to normal strings as well.
> In fact, the overload resolution could be changed, s.t. d_to_string struct overloads have a higher priority, but the `string` overloads are still being considered. The compiler would need to implement this logic anyhow to issue the mentioned: "Did you mean to use .idup?" messages.

The idup is a convenience feature that can be used on top of the proposal. The DIP as proposed could still be valid without idup, and I do not want to tie acceptance or rejection based on the presence of the idup function. That being said, if the language maintainers wish to add more compiler magic to this in order to accept, it is not something that we would be against.

What we are against is the format spec ALONE implicitly converting to a string.

> 9) The DIP does not mention operator overloading, e.g.
> 
> string s = "foo";
> ....
> s ~= i"foo $bar";
> 
> IMHO this is unambiguous and would reduce the need to call `.idup`.

This specific usage is not possible, without more compiler magic. There is no opOpAssignRight (or whatever you would call it) that would make this possible, even if the interpolation string was a struct that did have access to the parameters.

However, for a custom type for s, this would work exactly as intended with your code:

void opOpAssign(string op: "~", S, Args...)(S spec, Args args) if (isInterpolationSpec!S)
{
    myOutputRange.formattedWrite(spec.toFormatString!"%s", args);
}

-Steve
September 09, 2020
On 9/9/20 3:48 PM, Steven Schveighoffer wrote:
> mixin(i""q{class D { auto $varName = 20; });

Oops, this should be:

mixin(i""q{class D { auto $varName = 20; }.idup);

-Steve
September 11, 2020
On Tuesday, 8 September 2020 at 10:59:58 UTC, Mike Parker wrote:
> This is the feedback thread for the first round of Community Review of DIP 1036, "Formatted String Tuple Literals".
>
> ===================================
> **THIS IS NOT A DISCUSSION THREAD**
>
> Posts in this thread must adhere to the feedback thread rules outlined in the Reviewer Guidelines (and listed at the bottom of this post).
>
> https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md
>
> That document also provides guidelines on contributing feedback to a DIP review. Please read it before posting here. If you would like to discuss this DIP, please do so in the discussion thread:
>
> https://forum.dlang.org/post/vwrbvacnuerasbphgtjy@forum.dlang.org
> ==================================
>
> You can find DIP 1036 here:
>
> https://github.com/dlang/DIPs/blob/15537f9b36afa48f1c1cd57468e8c77f8f2499dd/DIPs/DIP1036.md
>
> The review period will end at 11:59 PM ET on September 22, or when I make a post declaring it complete. Feedback posted to this thread after that point may be ignored.
>
> At the end of this review round, the DIP will be moved into the Post-Community Round 1 state. Significant revisions resulting from this review round may cause the DIP manager to require another round of Community Review, otherwise the DIP will be queued for the Final Review.
>
> ==================================
> Posts in this thread that do not adhere to the following rules will be deleted at the DIP author's discretion:
>
> * All posts must be a direct reply to the DIP manager's initial post, with only two exceptions:
>
>     - Any commenter may reply to their own posts to retract feedback contained in the original post
>
>     - The DIP author may (and is encouraged to) reply to any feedback solely to acknowledge the feedback with agreement or disagreement (preferably with supporting reasons in the latter case)
>
> * Feedback must be actionable, i.e., there must be some action the DIP author can choose to take in response to the feedback, such as changing details, adding new information, or even retracting the proposal.
>
> * Feedback related to the merits of the proposal rather than to the contents of the DIP (e.g., "I'm against this DIP.") is allowed in Community Review (not Final Review), but must be backed by supporting arguments (e.g., "I'm against this DIP because..."). The supporting arguments must be reasonable. Obviously frivolous arguments waste everyone's time.
>
> * Feedback should be clear and concise, preferably listed as bullet points (those who take the time to do an in-depth review and provide feedback in the form of answers to the questions in this document will receive much gratitude). Information irrelevant to the DIP or is not provided in service of clarifying the feedback is unwelcome.

I think that, in principle, the way that is described by the DIP is the best way for i"" strings to work. However, I still have some points:

* The DIP says the name of the interpolation spec template defined in DRuntime is unspecified, but then does specify a name for `isInterpolationSpec`. Is this even necessary? I think that name should remain unspecified as well.

* The DIP tries to explain the implementation of `toFormatString` and `hasAllSpecs` in great depth. But is this even necessary? It seems to me that this should actually be an optional mechanic (like `idup`) that is implemented by DRuntime as a convenience function, and those sections can be removed entirely, which will also simplify the DIP, or can be moved to an "optional mechanics" section.

* The addition of an optional `alias this` implicit conversion only if all the format specifiers are defined seems way too complicated for me. My preference would be to add an implementation-defined function (just like `idup` now) to the template, so users of `printf` can just write:
```d
printf(i"${%d}a + ${%d}b = ${%d}(a + b)".toFormatz());
```
or something. Alternatively, it's not that hard to write a wrapper around `printf` which overloads for interpolated strings, but an implicit conversion tailored for immutable(char)* seems excessive.

* The grammar changes have some issues: "Expression" is defined, but this name already exists at https://dlang.org/spec/grammar.html#expressions. So, it should be given its own name.

* I feel like interpolated strings should work out of the box together with `mixin` without requiring a DRuntime CTFE `.idup` call.

* As a personal matter, the i"" q{$a + $b} implicit concatenation magic seems weird. My advice would be to just add `iq{$a + $b}`.

(* As a minor point, some code blocks don't have the language set to D, which would improve readability.)

September 12, 2020
Under "Wrong-use in unrelated function" it says:

--------
    Window createWindow(string title, int width = 0, int height = 0);

A user has some code that calls it like so:

    import std.conv;
    auto window = createWindow("Process debugger " ~ to!string(pid));

A new version of the compiler is released and the user, eager to try D's new string interpolation feature, rewrites that code as would be common in many other languages:

    auto window = createWindow(i"Process debugger $pid");

This would compile without error, but would not do what the user intended.
----------

This is indeed correct, but I take issue with "as would be common in many other languages". Because of D's close relationship with C, it would be a fair statement to compare with C. But C doesn't have string interpolation. It is impossible to constrain D based on what people expect from "many other languages".

D should do what is best for D, not what is best for C#, Forth, or Haskell. It is not unreasonable to expect people to at least glance at the instructions before assuming D is just like Language X. If they don't (and we're all guilty of that) then they get to debug it, like first noticing that the window title reads "Process debugger %s", which is not disastrous.

#DIP1038 needs a much better rationale as to why it should be preferred over #DIP1027.

(On a related note, I propose that default arguments are an overused feature, and should raise an eyebrow when used. There are many other inadvertent problems one can run into with careless use of it.)
September 13, 2020
On Wednesday, 9 September 2020 at 18:39:59 UTC, 12345swordy wrote:
> On Tuesday, 8 September 2020 at 10:59:58 UTC, Mike Parker wrote:
>> This is the feedback thread for the first round of Community Review of DIP 1036, "Formatted String Tuple Literals".
>>
>
> The fear of the gc has negatively impact this DIP. Why does the average programmer have to call .idup when it comes frequent used feature in other languages? If speed is an issue then the solution is to optimized the gc, not avoid it entirely.
>
> We shouldn't let c/c++ fear of the garbage collector  potential handicap new d features here.
>
> -Alex

I forgot the mention, that this dip doesn't explore how other languages implement string interpolation.

-Alex
September 15, 2020
On 9/11/20 1:13 PM, burt wrote:
> I think that, in principle, the way that is described by the DIP is the best way for i"" strings to work. However, I still have some points:

Thanks. We are most certainly evolving on what we think is best, based on feedback here and internal discussions. I hate to leave this feedback hanging, even though likely the DIP as is will be moot once we update. However I will respond to the points you made in the context of the current DIP text.

> 
> * The DIP says the name of the interpolation spec template defined in DRuntime is unspecified, but then does specify a name for `isInterpolationSpec`. Is this even necessary? I think that name should remain unspecified as well.

As a function which accepts parameters, you need some way to determine whether you have an interpolation spec. If we don't name the type or template, you can't specify the type to accept. So you need some way to determine that you got one. Doing it this way leaves more discretion to the implementation.

> * The DIP tries to explain the implementation of `toFormatString` and `hasAllSpecs` in great depth. But is this even necessary? It seems to me that this should actually be an optional mechanic (like `idup`) that is implemented by DRuntime as a convenience function, and those sections can be removed entirely, which will also simplify the DIP, or can be moved to an "optional mechanics" section.

In the current DIP text, toFormatString is the only official way to fetch the spec text.

hasAllSpecs is really just a mechanism to enable the implicit conversion to const char *. I'm not sure we had to allow access to it.

> 
> * The addition of an optional `alias this` implicit conversion only if all the format specifiers are defined seems way too complicated for me. My preference would be to add an implementation-defined function (just like `idup` now) to the template, so users of `printf` can just write:
> ```d
> printf(i"${%d}a + ${%d}b = ${%d}(a + b)".toFormatz());
> ```
> or something.

This won't work, because you need to translate just the format specifier, and your proposed form must pass through all the parameters. This *might* work, if you use a template, but it's getting to the point where it's really not worth it.

> Alternatively, it's not that hard to write a wrapper around `printf` which overloads for interpolated strings, but an implicit conversion tailored for immutable(char)* seems excessive.

The goal was to keep the ability from DIP 1027 to be able to call printf (and other C format + varargs functions) without modifications. However, we agree with you (and most other commenters here) that this requirement does not hold its own weight, and too much complexity was added for this one possibility.

> 
> * The grammar changes have some issues: "Expression" is defined, but this name already exists at https://dlang.org/spec/grammar.html#expressions. So, it should be given its own name.

There are more than just this one problem in the grammar (I have found another which nobody has pointed out yet). Admittedly, both Adam and I are not grammar experts, and we basically copied what Walter had written in DIP1027.

> 
> * I feel like interpolated strings should work out of the box together with `mixin` without requiring a DRuntime CTFE `.idup` call.

It would be nice (along with any other usage that binds directly to a string). We think we have this issue solved with the next DIP iteration.

> 
> * As a personal matter, the i"" q{$a + $b} implicit concatenation magic seems weird. My advice would be to just add `iq{$a + $b}`.

We also agree with this. Again, the next version should help here. This also was a holdover from DIP1027.

> (* As a minor point, some code blocks don't have the language set to D, which would improve readability.)
> 

Thanks, I will make sure the code blocks are properly annotated (Mike actually did a lot of them as an editing review).

-Steve
September 15, 2020
On 9/12/20 11:23 PM, Walter Bright wrote:
> Under "Wrong-use in unrelated function" it says:
> 
> --------
>      Window createWindow(string title, int width = 0, int height = 0);
> 
> A user has some code that calls it like so:
> 
>      import std.conv;
>      auto window = createWindow("Process debugger " ~ to!string(pid));
> 
> A new version of the compiler is released and the user, eager to try D's new string interpolation feature, rewrites that code as would be common in many other languages:
> 
>      auto window = createWindow(i"Process debugger $pid");
> 
> This would compile without error, but would not do what the user intended.
> ----------
> 
> This is indeed correct, but I take issue with "as would be common in many other languages". Because of D's close relationship with C, it would be a fair statement to compare with C. But C doesn't have string interpolation. It is impossible to constrain D based on what people expect from "many other languages".

We meant what many other languages do for string interpolation specifically (there are quite a few users of Python that find a good home with D, I don't think we should ignore them because they didn't come from C). But let's put this on the back burner for a bit, the next version of the DIP I think will solve this problem in a cleaner way.

> 
> D should do what is best for D, not what is best for C#, Forth, or Haskell. It is not unreasonable to expect people to at least glance at the instructions before assuming D is just like Language X.

We agree with this, as I think actually there aren't really any other languages that have done string interpolation in this exact way. D has a chance here to really shine with its introspection capabilities and focus on lowering.

However, it's also good to look at what works in other languages, and to frame the expectations of cross-language developers. If we can make it work like they expect AND cater to D's tremendous introspection capabilities, we have a very big win.

> If they don't (and we're all guilty of that) then they get to debug it, like first noticing that the window title reads "Process debugger %s", which is not disastrous.

I have been thinking a lot about "incorrect usage" and this DIP.

How many of us have done:

writeln("Name: %s, age: %d", name, age);

And are surprised when you get unexpected output. I do it all the time. And it's not terrible, I just fix it and move on.

Perhaps we put too much emphasis on the dangers of misuse. But I think a more reasonable pushback on the "surprise" factor here is that if call DOES happen to bind to an existing function not designed to take string interpolation tuples, the parameter ordering is much different than expected (Andrei pointed this out, and it's a very good point).

To be fair though, the biggest problem with the createWindow accidental match isn't necessarily the title, but the window width might be 20, or 65000. Honestly, you might not even notice the title when your window appears to open with random sizes.

> #DIP1038 needs a much better rationale as to why it should be preferred over #DIP1027.

Our next revision will be vastly different from DIP1027. So this is kind of a moot point.

> (On a related note, I propose that default arguments are an overused feature, and should raise an eyebrow when used. There are many other inadvertent problems one can run into with careless use of it.)

default parameters are a nice way to avoid having to write simple overloads which just call the other overloads. I wouldn't say this example is *completely* careless, but if I were to design it with this in mind, I probably would have provided a Size struct as the second parameter (and make it a default parameter).

The truth is, we don't always get to design the APIs we use, and if we can keep intact the expectations that the original designers had when designing them, the DIP is in a better place.

-Steve
September 23, 2020
On Tuesday, 8 September 2020 at 10:59:58 UTC, Mike Parker wrote:

>
> The review period will end at 11:59 PM ET on September 22, or when I make a post declaring it complete. Feedback posted to this thread after that point may be ignored.
>

Thanks to everyone who provided feedback!
1 2
Next ›   Last »