September 10, 2020
On 9/9/20 5:41 PM, Paul Backus wrote:
> On Tuesday, 8 September 2020 at 10:59:31 UTC, Mike Parker wrote:
>> This is the discussion thread for the first round of Community Review of DIP 1036, "Formatted String Tuple Literals":
> 
> As per the rules, I'm responding here to Steven's post from the Feedback thread.
> 
> Steven Schveighoffer wrote:
>> First, thanks for your opinion. We value all the opinions of people in the community, especially long-standing members with a lot of experience with D such as yourself.
>>
>> However, this entire post has no actionable or specific items, and really should have been added to the discussion thread instead. I'm responding to it here because in the past I have had cases where I posted feedback and got no response or changes, and it irked me.
> 
> Thanks for replying. The specific, actionable item in my post is: withdraw the DIP.
> 
> This kind of feedback ("related to the merits of the proposal rather than to the contents of the DIP") is explicitly permitted in Community Review by the Feedback thread rules, which is why I posted it there instead of in the Discussion thread.

I did not realize that was specifically in the rules! Sorry.

> The reason I gave that feedback, instead of more detailed feedback about the DIP's contents, is that I sincerely believe DIP 1036 cannot be salvaged. I have a lot of respect for you and Adam, and would hate to see you waste your time and effort on a proposal doomed to failure. I think you (or anyone else who wishes to take up the string-interpolation torch) would be much better off discarding DIP 1036 and starting a new proposal from scratch.

I disagree completely. This DIP is on the right track. And I'm happy to "waste time" if it means it gets a fair shake at inclusion. It costs me nothing to have it be judged.

> Regarding the specific points you replied to:
> 
>> The interface is actually simple to use. Without specific concerns, it's hard to address these comments further.
> 
> If the interface is simple to use, why does the DIP anticipate that new users will have so much trouble using it that they'll need "helpful hints" from the compiler, and possibly even a link to a web page (!), to get it right? I quote:

We do not anticipate much trouble at all for using the feature in the DIP. In fact, the opposite is true -- using the dip is really easy if you want a string, just append .idup. How is this difficult to understand or use?

However, we acknowledge that users who come from a non-D background and languages that do not have the vast compile-time introspection capabilities that D has (maybe the language they are used to only has string interpolation, and not formatted tuples), will try something that will not compile. Having the compiler teach them the correct way is not a bad thing, nor is it admitting an interface issue. It's an explanation of how to recreate the behavior they are used to in D.

It's no different from other suggestions that the compiler does (e.g. "writeln not found, perhaps try importing std.stdio").

> 
>> An i"" string is not likely to be compatible with existing D string functions and variables. The compiler SHOULD provide helpful hints in error messages to help new users understand how to properly use the new feature. This message MAY link to a web page to educate the user on resolving the error.
> 
> To me, this does not pass the laugh test. [1] If you anticipate this being hard enough to get right that new users cannot do it without extensive hand-holding, maybe the problem is not with the users, but with the proposal itself.

We don't. It will be easy to get right. If they get it wrong, they will be taught and then get it right. It's not that hard.

> 
>> This measure of "complexity" is arbitrary, and has no bearing on the validity of the DIP. in fact, many already-accepted DIPS have relatively similar ratios of description and rationale.
> 
> Again, I quote:
> 
>> ### Justifications
>>
>> The **complexity** of the format spec may seem superfluous, however it serves four key roles:
> 
> Emphasis added. If you want to nitpick the wording here, take it up with your co-author.

The DIP does not have high complexity. It's straightforward, and understandable.

The complexity you quote has nothing to do with the DIP, but is referring to how a custom type with more features is more complex than a simple string. Again, this is to compare with DIP1027, where a string was used as the format specifier. A custom type is obviously more complex than a string, and so the DIP explains why we did it.

> 
>> One thing to note is that this DIP has a prior very similar DIP, but just used a string for the formatting specification. The Justification section is ENTIRELY devoted to explaining why this DIP does not use that. In fact, we can remove the entire section, and it doesn't change anything about the DIPs features or benefits. But without a distinction between DIP1027 and this DIP, arguably it would be rejected on principle (why approve something that was just rejected).
> 
> I think members of this community sometimes give the language maintainers (currently Walter and Atila, previously Walter and Andrei) too little credit. They're not perfect, but generally speaking they are reasonable people with good judgment. Have there been any actual examples of a DIP being rejected on principle for being too similar to another previously-rejected DIP?

I might reject a DIP that had a minor change from a previously rejected one, without any good explanation as to why. Framing it as us somehow thinking poorly of the language maintainers is somewhat insulting. I can't imagine anyone putting up a DIP without context of why the DIP is designed how it is.

90% of the DIP is actually exactly the same as DIP1027. It's just the format spec type which is different. If we do not explain the design change, we risk someone filling in the holes with their own idea of why we designed it this way (you seem to have no problem incorrectly describing our motivation).

> 
>> This assessment is incorrect. There is an implicit conversion of the format specification to immutable char * in the circumstance that you have specified all format information. This makes it compatible with printf.
> 
> "X is true in the circumstance that Y" is not the same thing as "X is true." :)

I admit that in the case where your call to printf would crash your program, we disallow compilation.

> 
> Also, the fact that i"${%s}(foo)" and i"$(foo)" are equivalent when you pass them to `writefln` but not when you pass them to `printf` is another thing that doesn't pass the laugh test. You're not making it easy for me to tell my friends about D.

printf is a C function. It does not have introspection capabilities, and so your format specifiers have to be exact. This is not hard to explain, especially to people with a C background (they have certainly dealt with mismatched format specifiers).

How would your friends understand why you can do writefln("%s", 1) and not printf("%s", 1)?

> 
>> Implicitly converting the format spec to string would result in undoubtedly incorrect function calls, and we address the concerns quite thoroughly. Even if it is a desired thing, it's not something we should provide. This is not the same as trying and failing. We intend misuse of string conversion to not compile.
> 
> I understand perfectly. My criticism of DIP 1036 is not that you have failed at what you set out to do, but that you have set out to do the wrong thing to begin with.

How about you tell me what the right thing is?

> 
> By the way, there's another part of that Scott Meyers talk that addresses the problem of accidentally passing arguments to the wrong parameters. The solution he shows there would also work for the example in the DIP, without requiring any of the elaborate machinery the DIP proposes.

I watched and enjoyed the whole talk. The entire time I thought "yes, this is why we designed the DIP to be easy to use correctly, and hard to use incorrectly". I have no idea how you come away with the opposite conclusion.

The format spec could be a simple wrapper for a string. But we then lose all the nice compile-time capabilities such as validating formats at compile-time, or generating the correct format string at compile time without depending on the compiler to know what that means.

> 
>> I would characterize the DIP as not only trying to address these issues, but succeeding. printf is supported for valid cases. writefln will be supported as expected. Conversion to string or immutable char * is possible with a library call which should be provided. There are no flaws I can see.
> 
> Adding dedicated overloads of writefln, idup, etc. to deal with interpolated strings might sound like a good solution, but it doesn't scale. The *best-case* scenario is that DIP 1036 creates a bunch of meaningless busywork for library maintainers; the more realistic scenario is that most libraries never get updated at all, and users have to either check every individual function they use for interpolated-string compatibility, or defensively spam .idup everywhere (at which point, you might as well just make interpolated strings use the GC to start with).

How many functions do you suppose could use formatted string tuples? In Phobos, which I'd consider a large complex library, I bet there are somewhere on the order of 5-10. You think this doesn't scale? You think an afternoon of updates ONCE ever, is too much work? Those that just accept a string do not need adjustment. One just adds .idup with the call and it's done.

Your characterization of defensive programming is incorrect. A defensive programmer would explicitly do something because they were afraid the compiler would COMPILE their code incorrectly. In this case, the incorrect code DOESN'T compile, and the compiler tells them how it can be updated. No defensiveness or spamming in sight.

One possible improvement is to follow Sebastian Wilzbach's suggestion to try .idup if the call doesn't succeed. This might solve a lot of the concerns here, but I don't think it's required for the DIP proposal to stand. Having to add .idup to the end of an interpolation isn't difficult, and most people will learn it quickly.

> DIP 1027 had its issues, but at least it was simple to explain, simple to use, and didn't require the library and runtime to bend over backwards to support it. DIP 1036, by contrast, is hard to explain, fiddly to use, and requires extensive coordination between the compiler, runtime, and library to implement. In short, it's a step in the wrong direction.

This is ironically the exact opposite. It's easy to use DIP1027 incorrectly -- printf(i"age : $age") or createWindow(i"Pid is $pid"); and hard to use it correctly --  mysqlQuery(i"select * from sometable where author = ${?}author and date < ${?}publishedBefore and ... ${?}x .. ${?}y .. ${?}z ... ${?}why .. ${?}all ... ${?}these .. ${?}questionmarks");

Our DIP does not have these problems, and is pretty easy to explain.

-Steve
September 10, 2020
On 9/10/20 2:30 PM, zoujiaqing wrote:
> Please support like this:
> 
> int i = 10;
> 
> string b = "test " ~ i;
> 
> writeln(b); // test 10

string b = i"test $i".idup;

-Steve
September 10, 2020
On Thursday, 10 September 2020 at 18:40:03 UTC, Matheus wrote:
> On Thursday, 10 September 2020 at 18:30:26 UTC, zoujiaqing wrote:
>>
>> Please support like this:
>>
>> int i = 10;
>>
>> string b = "test " ~ i;
>>
>> writeln(b); // test 10
>
> Shouldn't a type like "i" in this example be automatically converted to string in cases like this?
>
> Matheus.

Forget... I just remembered that there was a thread about this, and in this case could be a concatenation between "string" and a "char".

Matheus.
September 10, 2020
On 9/9/20 5:41 PM, Paul Backus wrote:
> On Tuesday, 8 September 2020 at 10:59:31 UTC, Mike Parker wrote:
>> This is the discussion thread for the first round of Community Review of DIP 1036, "Formatted String Tuple Literals":
> 
> As per the rules, I'm responding here to Steven's post from the Feedback thread.
> 
> Steven Schveighoffer wrote:
>> First, thanks for your opinion. We value all the opinions of people in the community, especially long-standing members with a lot of experience with D such as yourself.
>>
>> However, this entire post has no actionable or specific items, and really should have been added to the discussion thread instead. I'm responding to it here because in the past I have had cases where I posted feedback and got no response or changes, and it irked me.
> 
> Thanks for replying. The specific, actionable item in my post is: withdraw the DIP.
> 
> This kind of feedback ("related to the merits of the proposal rather than to the contents of the DIP") is explicitly permitted in Community Review by the Feedback thread rules, which is why I posted it there instead of in the Discussion thread.
> 
> The reason I gave that feedback, instead of more detailed feedback about the DIP's contents, is that I sincerely believe DIP 1036 cannot be salvaged. I have a lot of respect for you and Adam, and would hate to see you waste your time and effort on a proposal doomed to failure. I think you (or anyone else who wishes to take up the string-interpolation torch) would be much better off discarding DIP 1036 and starting a new proposal from scratch.
> 
> Regarding the specific points you replied to:
> 
>> The interface is actually simple to use. Without specific concerns, it's hard to address these comments further.
> 
> If the interface is simple to use, why does the DIP anticipate that new users will have so much trouble using it that they'll need "helpful hints" from the compiler, and possibly even a link to a web page (!), to get it right? I quote:
> 
>> An i"" string is not likely to be compatible with existing D string functions and variables. The compiler SHOULD provide helpful hints in error messages to help new users understand how to properly use the new feature. This message MAY link to a web page to educate the user on resolving the error.
> 
> To me, this does not pass the laugh test. [1] If you anticipate this being hard enough to get right that new users cannot do it without extensive hand-holding, maybe the problem is not with the users, but with the proposal itself.
> 
>> This measure of "complexity" is arbitrary, and has no bearing on the validity of the DIP. in fact, many already-accepted DIPS have relatively similar ratios of description and rationale.
> 
> Again, I quote:
> 
>> ### Justifications
>>
>> The **complexity** of the format spec may seem superfluous, however it serves four key roles:
> 
> Emphasis added. If you want to nitpick the wording here, take it up with your co-author.
> 
>> One thing to note is that this DIP has a prior very similar DIP, but just used a string for the formatting specification. The Justification section is ENTIRELY devoted to explaining why this DIP does not use that. In fact, we can remove the entire section, and it doesn't change anything about the DIPs features or benefits. But without a distinction between DIP1027 and this DIP, arguably it would be rejected on principle (why approve something that was just rejected).
> 
> I think members of this community sometimes give the language maintainers (currently Walter and Atila, previously Walter and Andrei) too little credit. They're not perfect, but generally speaking they are reasonable people with good judgment. Have there been any actual examples of a DIP being rejected on principle for being too similar to another previously-rejected DIP?
> 
>> This assessment is incorrect. There is an implicit conversion of the format specification to immutable char * in the circumstance that you have specified all format information. This makes it compatible with printf.
> 
> "X is true in the circumstance that Y" is not the same thing as "X is true." :)
> 
> Also, the fact that i"${%s}(foo)" and i"$(foo)" are equivalent when you pass them to `writefln` but not when you pass them to `printf` is another thing that doesn't pass the laugh test. You're not making it easy for me to tell my friends about D.
> 
>> Implicitly converting the format spec to string would result in undoubtedly incorrect function calls, and we address the concerns quite thoroughly. Even if it is a desired thing, it's not something we should provide. This is not the same as trying and failing. We intend misuse of string conversion to not compile.
> 
> I understand perfectly. My criticism of DIP 1036 is not that you have failed at what you set out to do, but that you have set out to do the wrong thing to begin with.
> 
> By the way, there's another part of that Scott Meyers talk that addresses the problem of accidentally passing arguments to the wrong parameters. The solution he shows there would also work for the example in the DIP, without requiring any of the elaborate machinery the DIP proposes.
> 
>> I would characterize the DIP as not only trying to address these issues, but succeeding. printf is supported for valid cases. writefln will be supported as expected. Conversion to string or immutable char * is possible with a library call which should be provided. There are no flaws I can see.
> 
> Adding dedicated overloads of writefln, idup, etc. to deal with interpolated strings might sound like a good solution, but it doesn't scale. The *best-case* scenario is that DIP 1036 creates a bunch of meaningless busywork for library maintainers; the more realistic scenario is that most libraries never get updated at all, and users have to either check every individual function they use for interpolated-string compatibility, or defensively spam .idup everywhere (at which point, you might as well just make interpolated strings use the GC to start with).
> 
> In other words, DIP 1036 is exactly the kind of thing Andrei is describing when he talks about Good Work [3]:
> 
>> Good Work begets more Good Work. Typically Good Work produces context, opportunity, and precedent for more of the same. The same reviewer who rubber stamped a piece of Good Work will have an idea how to produce more Good Work derived from it. The kind of environment where Good Work is revered encourages its creation, in a cycle that creates the illusion of progress. Because Good Work is complex, it produces "bug ripples" whereby increasingly complex Good Work fixes one bug but is liable to introduce others.
> 
> DIP 1027 had its issues, but at least it was simple to explain, simple to use, and didn't require the library and runtime to bend over backwards to support it. DIP 1036, by contrast, is hard to explain, fiddly to use, and requires extensive coordination between the compiler, runtime, and library to implement. In short, it's a step in the wrong direction.
> 
> [1] "Can I explain this to my friend, who doesn't know D, with a straight face?"
> [2] https://www.youtube.com/watch?v=5tg1ONG18H8&t=46m14s
> [3] https://forum.dlang.org/thread/q6plhj$1l9$1@digitalmars.com?page=15

I quoted this in its entirety because I agree with it in its entirety. It says what I wanted to say, in a much better form.

"Principle of Least Astonishment" (https://wiki.c2.com/?PrincipleOfLeastAstonishment) also comes to mind (incidentally I've first heard of it from Scott Meyers, too, but it probably predates him). I found some design choices surprising: We care about printf and its style of formatting. But we don't care for POSIX positional parameters. Yet we should design functions especially for interpolated strings. We move arguments to the end of the format string. The format string is actually not a string - per the infamous error message with a web link to educate the user. All of these are surprising.

These high-level decisions require a series of technical solutions that come in the form of a runaway train of engineering.
September 10, 2020
On Thursday, 10 September 2020 at 18:45:02 UTC, Steven Schveighoffer wrote:
>
> I disagree completely. This DIP is on the right track. And I'm happy to "waste time" if it means it gets a fair shake at inclusion. It costs me nothing to have it be judged.

Fair enough--that's your judgement call to make.

>> I understand perfectly. My criticism of DIP 1036 is not that you have failed at what you set out to do, but that you have set out to do the wrong thing to begin with.
>
> How about you tell me what the right thing is?

Sure. Here's the one-minute version of my personal vision for how string interpolation should work in D:

1. `writeln(i"Hello $name!")` lowers to `writeln("Hello ", name, "!")`.
2. `printf(f"Hello ${%s}name!")` lowers to `printf("Hello %s!", name)`
3. `f"Hello $name!"` and `i"Hello ${%s}name"` are parse-time errors.

The key idea is that rather than trying to find one magical solution that works for both writeln-style functions and printf-style functions, we have a dedicated syntax for each.

This won't stop people from calling functions with the wrong arguments, but I don't think it needs to--that should be each function's responsibility, not the language's (see: Scott Meyers' Year/Month/Day example). And if we do decide to make it the language's responsibility, we should do it in a way that solves the problem in the general case, like pragma(printf).
September 11, 2020
On Thursday, 10 September 2020 at 20:50:24 UTC, Paul Backus wrote:
> On Thursday, 10 September 2020 at 18:45:02 UTC, Steven Schveighoffer wrote:
>>
>> I disagree completely. This DIP is on the right track. And I'm happy to "waste time" if it means it gets a fair shake at inclusion. It costs me nothing to have it be judged.
>
> Fair enough--that's your judgement call to make.
>
>>> I understand perfectly. My criticism of DIP 1036 is not that you have failed at what you set out to do, but that you have set out to do the wrong thing to begin with.
>>
>> How about you tell me what the right thing is?
>
> Sure. Here's the one-minute version of my personal vision for how string interpolation should work in D:
>
> 1. `writeln(i"Hello $name!")` lowers to `writeln("Hello ", name, "!")`.
> 2. `printf(f"Hello ${%s}name!")` lowers to `printf("Hello %s!", name)`
> 3. `f"Hello $name!"` and `i"Hello ${%s}name"` are parse-time errors.
>
> The key idea is that rather than trying to find one magical solution that works for both writeln-style functions and printf-style functions, we have a dedicated syntax for each.
>
> This won't stop people from calling functions with the wrong arguments, but I don't think it needs to--that should be each function's responsibility, not the language's (see: Scott Meyers' Year/Month/Day example). And if we do decide to make it the language's responsibility, we should do it in a way that solves the problem in the general case, like pragma(printf).

How about using Atila's nogc code [0] and just having `i"Hello $name!" lower to `text("Hello ", name, "!")`

Works with both writeln, printf, and string assignment.

I think this whole business of making it work with format strings is a different feature. Especially if it is to work with sql and printf style formats?

[0]: https://github.com/atilaneves/nogc/blob/master/source/nogc/conv.d
September 11, 2020
On Friday, 11 September 2020 at 09:01:31 UTC, aliak wrote:
> How about using Atila's nogc code [0] and just having `i"Hello $name!" lower to `text("Hello ", name, "!")`
>
> Works with both writeln, printf, and string assignment.

The short answer is, I want to be able to write `mixin(i"...")` and have it work in BetterC. The long answer is something about design elegance, separation of concerns, etc.

Anyway, I don't expect my idea to satisfy everyone equally. That's why it's my "personal vision," and not my "perfect solution to everyone's problems." :)
September 11, 2020
On Thursday, 10 September 2020 at 20:50:24 UTC, Paul Backus wrote:

> This won't stop people from calling functions with the wrong arguments, but I don't think it needs to--that should be each function's responsibility, not the language's (see: Scott Meyers' Year/Month/Day example).

That issue that I have with your stance, is that we are dealing with c/c++ bindings here. How is c/c++ responsible in this case? You are asking the binder maintainer to create a wrapper to prevent accident function call.

The previous DIP is bad, because it is easy to accidentally call the wrong function. Which it is not ideal. You are asking the library maintainers to modify the library to prevent the users from shooting themselves in the foot by accident which is not ideal.

Alex
September 11, 2020
On Friday, 11 September 2020 at 13:19:37 UTC, 12345swordy wrote:
> On Thursday, 10 September 2020 at 20:50:24 UTC, Paul Backus wrote:
>
>> This won't stop people from calling functions with the wrong arguments, but I don't think it needs to--that should be each function's responsibility, not the language's (see: Scott Meyers' Year/Month/Day example).
>
> That issue that I have with your stance, is that we are dealing with c/c++ bindings here. How is c/c++ responsible in this case? You are asking the binder maintainer to create a wrapper to prevent accident function call.

Yes, that's exactly what I'm asking. Note that this is something D *already* does when it provides wrappers like `writefln` as alternatives to C functions like `printf`, so in practice, it should not require any new work to be done.

Keep in mind that any argument list you could generate using my or DIP 1027's interpolated strings is also an argument list you could have written by hand. So if a function is error-prone to call with string interpolation, chances are it's also error-prone to call without it.
September 11, 2020
On Friday, 11 September 2020 at 13:46:52 UTC, Paul Backus wrote:
> On Friday, 11 September 2020 at 13:19:37 UTC, 12345swordy wrote:
>> On Thursday, 10 September 2020 at 20:50:24 UTC, Paul Backus wrote:
>>
>>> [...]
>>
>> That issue that I have with your stance, is that we are dealing with c/c++ bindings here. How is c/c++ responsible in this case? You are asking the binder maintainer to create a wrapper to prevent accident function call.
>
> Yes, that's exactly what I'm asking. Note that this is something D *already* does when it provides wrappers like `writefln` as alternatives to C functions like `printf`, so in practice, it should not require any new work to be done.

You conflicting standard library feature with built in language feature here, they are not the same.