www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Discussion Thread: DIP 1036--Formatted String Tuple

reply Mike Parker <aldacron gmail.com> writes:
This is the discussion thread for the first round of Community 
Review of DIP 1036, "Formatted String Tuple Literals":

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. Discussion in this 
thread may continue beyond that point.

Here in the discussion thread, you are free to discuss anything 
and everything related to the DIP. Express your support or 
opposition, debate alternatives, argue the merits, etc.

However, if you have any specific feedback on how to improve the 
proposal itself, then please post it in the feedback thread. The 
feedback thread will be the source for the review summary that I 
will write at the end of this review round. I will post a link to 
that thread immediately following this post. Just be sure to read 
and understand the Reviewer Guidelines before posting there:

https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md

And my blog post on the difference between the Discussion and 
Feedback threads:

https://dlang.org/blog/2020/01/26/dip-reviews-discussion-vs-feedback/

Please stay on topic here. I will delete posts that are 
completely off-topic.
Sep 08 2020
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Tuesday, 8 September 2020 at 10:59:31 UTC, Mike Parker wrote:

 However, if you have any specific feedback on how to improve 
 the proposal itself, then please post it in the feedback 
 thread. The feedback thread will be the source for the review 
 summary that I will write at the end of this review round. I 
 will post a link to that thread immediately following this post.
The feedback thread is here: https://forum.dlang.org/post/vpgemqdqgorsuzqbxazw forum.dlang.org
Sep 08 2020
prev sibling next sibling parent reply Avrina <avrina12309412342 gmail.com> writes:
What's the purpose of toFormatString with a default spec? Why 
would you ever want to have a default??? That's just some hacky 
workaround from the previous DIP to circumvent some arbitrary 
rule. Why wouldn't you have some sort of type map instead that 
maps a format string to a type? All of that information is 
available.

The way 'hasAllSpec' seems to be intended to use just seems 
terrible. What happened to having an overload for printf() to 
handle the case of an interpolated string. Is that overload not 
happening? Implicitly converting to char* on a condition like 
'hasAllSpec' is just asking for trouble. This special case isn't 
required, it will only introduce bugs; just add an overload to 
printf. It also requires the user to specify all the formatting 
themselves when all that information is already there for it to 
know what formatting specifier to use. That wouldn't fly in a 
intrrolated string library implementation and it definitely 
shouldn't fly as a language feature.

The 'toFormatStringImpl' and friends implementations should just 
be removed. Its simple enough that anyone can implement it, 
not.like there is a performance benefit anyways as it is just 
going to be using CTFE, like a library implementation. It is also 
too specific, something like an sql query would just put a number 
depending on the order of the parameters. So in that case it isnt 
really a specifier for the argument some much as which argument 
should go where. I can only imagine how confusing and error prone 
that is going to be, especially since you have to specify every 
single argument if you dont implement your own wrapper or 
overload to fix this.
Sep 08 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/8/20 8:10 AM, Avrina wrote:
 What's the purpose of toFormatString with a default spec? Why would you 
 ever want to have a default??? That's just some hacky workaround from 
 the previous DIP to circumvent some arbitrary rule. Why wouldn't you 
 have some sort of type map instead that maps a format string to a type? 
 All of that information is available.
Because the default spec should not be constrained by the language (e.g. always "%s" as DIP1027 specified). See for instance mysql prepared statements, where the spec is "?". This way the callee can decide what to put for default specs.
 
 The way 'hasAllSpec' seems to be intended to use just seems terrible. 
 What happened to having an overload for printf() to handle the case of 
 an interpolated string. Is that overload not happening?
We could potentially handle it that way. But the idea of not having to handle it that way for this case is appealing. It means we don't have to write an overload for it unless you want to. There are potentially quite a few C libraries that use the format + parameters mechanism, and this allows a way to call those without having to write a wrapper for it.
 Implicitly 
 converting to char* on a condition like 'hasAllSpec' is just asking for 
 trouble. This special case isn't required, it will only introduce bugs; 
All vague statements, do you know of any specific trouble or bugs?
 just add an overload to printf. It also requires the user to specify all 
 the formatting themselves when all that information is already there for 
 it to know what formatting specifier to use. That wouldn't fly in a 
 intrrolated string library implementation and it definitely shouldn't 
 fly as a language feature.
This DIP doesn't provide for matching of parameters to their respective formats. It is one step above DIP1027, in that it allows a callee to specify the default format, and the format is available at compile-time. The main benefit is simply the fact that you CAN overload based on the fact that you received an interpolated string.
 
 The 'toFormatStringImpl' and friends implementations should just be 
 removed. Its simple enough that anyone can implement it, not.like there 
 is a performance benefit anyways as it is just going to be using CTFE, 
 like a library implementation. It is also too specific, something like 
 an sql query would just put a number depending on the order of the 
 parameters. So in that case it isnt really a specifier for the argument 
 some much as which argument should go where. I can only imagine how 
 confusing and error prone that is going to be, especially since you have 
 to specify every single argument if you dont implement your own wrapper 
 or overload to fix this.
These are implementation details, and not necessarily the final implementation. The real API is specified in the description. The numbered SQL problem is definitely one that is troubling -- you have to put in a placeholder for the number, and then replace it with the correct value, which means 2 passes of compile-time string generation. However, this is something that could be improved upon if the type provides access to the raw spec sequence, or allows a different way to build the format string (I have some ideas). Note that we are trying to prevent people from abusing the implementation to achieve "AST Macros" as Walter likes to put it. If we can provide a better way to generate the formatting, and still keep this property, it has a better chance of being accepted. -Steve
Sep 08 2020
parent reply Avrina <avrina12309412342 gmail.com> writes:
On Tuesday, 8 September 2020 at 13:32:10 UTC, Steven 
Schveighoffer wrote:
 On 9/8/20 8:10 AM, Avrina wrote:
 What's the purpose of toFormatString with a default spec? Why 
 would you ever want to have a default??? That's just some 
 hacky workaround from the previous DIP to circumvent some 
 arbitrary rule. Why wouldn't you have some sort of type map 
 instead that maps a format string to a type? All of that 
 information is available.
Because the default spec should not be constrained by the language (e.g. always "%s" as DIP1027 specified). See for instance mysql prepared statements, where the spec is "?". This way the callee can decide what to put for default specs.
That doesn't answer the question. A type map to specifier would do the same thing, just better; actually doing the work for the user.
 The way 'hasAllSpec' seems to be intended to use just seems 
 terrible. What happened to having an overload for printf() to 
 handle the case of an interpolated string. Is that overload 
 not happening?
We could potentially handle it that way. But the idea of not having to handle it that way for this case is appealing. It means we don't have to write an overload for it unless you want to. There are potentially quite a few C libraries that use the format + parameters mechanism, and this allows a way to call those without having to write a wrapper for it.
The way you have to pass the interpolated string for it to work makes it almost completely useless. Requiring all format specifiers to be defined by the user is counter intuitive compared to using an overload. There are many C libraries, they require you to write bindings in D anyways, it would not be that difficult to add an overload for interpolated strings.
 Implicitly converting to char* on a condition like 
 'hasAllSpec' is just asking for trouble. This special case 
 isn't required, it will only introduce bugs;
All vague statements, do you know of any specific trouble or bugs?
The DIP lists one? The CreateWindow example, if the specifier is given, you can call a function with the wrong arguments that weren't intended. The only way to avoid this is if you specifically create an overload to avoid the implicit conversion. This should not be the default. If there is any implicit conversion happening for an I telrpolated string, the only valid case would be one where it is converted to the finalized string. Which isn't possible the way this is being implemented.
 just add an overload to printf. It also requires the user to 
 specify all the formatting themselves when all that 
 information is already there for it to know what formatting 
 specifier to use. That wouldn't fly in a intrrolated string 
 library implementation and it definitely shouldn't fly as a 
 language feature.
This DIP doesn't provide for matching of parameters to their respective formats. It is one step above DIP1027, in that it allows a callee to specify the default format, and the format is available at compile-time. The main benefit is simply the fact that you CAN overload based on the fact that you received an interpolated string.
Not sure what you are getting at here. You seemed to have taken a paragraph out of context on which it was written. It shouldn't provide any formatting at all. See the below statement you cut off.
 The 'toFormatStringImpl' and friends implementations should 
 just be removed. Its simple enough that anyone can implement 
 it, not.like there is a performance benefit anyways as it is 
 just going to be using CTFE, like a library implementation. It 
 is also too specific, something like an sql query would just 
 put a number depending on the order of the parameters. So in 
 that case it isnt really a specifier for the argument some 
 much as which argument should go where. I can only imagine how 
 confusing and error prone that is going to be, especially 
 since you have to specify every single argument if you dont 
 implement your own wrapper or overload to fix this.
These are implementation details, and not necessarily the final implementation. The real API is specified in the description.
Yes, and the features they provide is what should be removed. There's no point to being able to call a C function with an interpolated string without an overload, see above.
 The numbered SQL problem is definitely one that is troubling -- 
 you have to put in a placeholder for the number, and then 
 replace it with the correct value, which means 2 passes of 
 compile-time string generation. However, this is something that 
 could be improved upon if the type provides access to the raw 
 spec sequence, or allows a different way to build the format 
 string (I have some ideas).
The sequence is accessible publically, at least with the given implementation as it is just a template. If that is not currently intended then the DIP implementation should be fixed, and that makes the situation with the 'toFormatString' default specifer much much worse. The user is forced to use it and can't implement their own type map to specifier to make interpolated strings function without having to have the user forcibly put specifiers in their interpolated strings for types that don't match the default.
 Note that we are trying to prevent people from abusing the 
 implementation to achieve "AST Macros" as Walter likes to put 
 it. If we can provide a better way to generate the formatting, 
 and still keep this property, it has a better chance of being 
 accepted.

 -Steve
It'd be better if this wasn't accepted then, rather than adding a crippled feature that's counter intuitive for a user to use. The discussion of the feature proposed was promising in the other DIP threads. What this ended up being isn't all that different than the other DIP.
Sep 08 2020
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 9 September 2020 at 01:32:58 UTC, Avrina wrote:
 A type map to specifier would do the same thing, just better; 
 actually doing the work for the user.
What would this look like?
Sep 08 2020
parent Avrina <avrina12309412342 gmail.com> writes:
On Wednesday, 9 September 2020 at 02:21:30 UTC, Adam D. Ruppe 
wrote:
 On Wednesday, 9 September 2020 at 01:32:58 UTC, Avrina wrote:
 A type map to specifier would do the same thing, just better; 
 actually doing the work for the user.
What would this look like?
Don't have access to a computer ATM, not writing on a phone. I'll write it up when I can.
Sep 09 2020
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/8/20 9:32 PM, Avrina wrote:
 On Tuesday, 8 September 2020 at 13:32:10 UTC, Steven Schveighoffer wrote:
 On 9/8/20 8:10 AM, Avrina wrote:
 What's the purpose of toFormatString with a default spec? Why would 
 you ever want to have a default??? That's just some hacky workaround 
 from the previous DIP to circumvent some arbitrary rule. Why wouldn't 
 you have some sort of type map instead that maps a format string to a 
 type? All of that information is available.
Because the default spec should not be constrained by the language (e.g. always "%s" as DIP1027 specified). See for instance mysql prepared statements, where the spec is "?". This way the callee can decide what to put for default specs.
That doesn't answer the question. A type map to specifier would do the same thing, just better; actually doing the work for the user.
Sorry, I didn't read the full question. So yes, a type map would work. But I think actually, if we give people access to the format tuple list (as I have brought up in the other subthread), a specific mechanism inside druntime is not necessary. I still want to allow the implicit cast to const char* to allow one to use C functions without having to wrap them. And in that case, you need a mechanism to generate the format string anyway. And there's no reason not to expose it for other users (I'm thinking of mysql-native, which uses a single specifier for all parameters, '?'). We can handle the easiest case, and leave the more complex ones to the user.
 The way you have to pass the interpolated string for it to work makes it 
 almost completely useless. Requiring all format specifiers to be defined 
 by the user is counter intuitive compared to using an overload. There 
 are many C libraries, they require you to write bindings in D anyways, 
 it would not be that difficult to add an overload for interpolated strings.
The DIP does not prevent someone overloading printf to deal with it in your specified manner. BUT if you don't want to do it, there is no harm in allowing the call to proceed. Now, printf could be overloaded, yes. We could make it work. It's not part of the DIP though. The point about writefln is salient because it will not work without an overload, and people will definitely expect writefln to work with interpolated strings.
 
 Implicitly converting to char* on a condition like 'hasAllSpec' is 
 just asking for trouble. This special case isn't required, it will 
 only introduce bugs;
All vague statements, do you know of any specific trouble or bugs?
The DIP lists one? The CreateWindow example, if the specifier is given, you can call a function with the wrong arguments that weren't intended. The only way to avoid this is if you specifically create an overload to avoid the implicit conversion. This should not be the default.
The key phrase in that is "if the specifier is given". Why would you add a specifier if you didn't understand what you are doing? The point of that is for cases like i"my name is $name", which will NOT convert implicitly to a const char *. The thought process goes: 1. I've used interpolated strings in (Python | Javascript | ...). 2. Oooh! D has interpolated strings, let me just do that. 3. Compiler says "no, use .idup". But if you are aware of the mechanisms of the interpolation spec, and you want to specify the formatting fields (e.g. if you are doing this in printf, you are already used to doing it), then it just works.
 If there is any implicit conversion happening for an I telrpolated 
 string, the only valid case would be one where it is converted to the 
 finalized string. Which isn't possible the way this is being implemented.
It is true this is not possible.
 The 'toFormatStringImpl' and friends implementations should just be 
 removed. Its simple enough that anyone can implement it, not.like 
 there is a performance benefit anyways as it is just going to be 
 using CTFE, like a library implementation. It is also too specific, 
 something like an sql query would just put a number depending on the 
 order of the parameters. So in that case it isnt really a specifier 
 for the argument some much as which argument should go where. I can 
 only imagine how confusing and error prone that is going to be, 
 especially since you have to specify every single argument if you 
 dont implement your own wrapper or overload to fix this.
These are implementation details, and not necessarily the final implementation. The real API is specified in the description.
Yes, and the features they provide is what should be removed. There's no point to being able to call a C function with an interpolated string without an overload, see above.
Programmers are lazy. If I can do: import core.stdc.stdio : printf; printf(i"hello ${%d}name"); That might be enough. It might bug me that I have to always specify formatting specs, and then I'm motivated to write an overload. But it's not necessary for the purposes of this language change.
 The numbered SQL problem is definitely one that is troubling -- you 
 have to put in a placeholder for the number, and then replace it with 
 the correct value, which means 2 passes of compile-time string 
 generation. However, this is something that could be improved upon if 
 the type provides access to the raw spec sequence, or allows a 
 different way to build the format string (I have some ideas).
The sequence is accessible publically, at least with the given implementation as it is just a template. If that is not currently intended then the DIP implementation should be fixed, and that makes the situation with the 'toFormatString' default specifer much much worse. The user is forced to use it and can't implement their own type map to specifier to make interpolated strings function without having to have the user forcibly put specifiers in their  interpolated strings for types that don't match the default.
The DIP implementation is an example, and while usable, was not intended as a defining part of the spec. In fact, I have conceived of a different mechanism that would break anything that depended on having that specific implementation, but would still satisfy the DIP requirements. I have since changed my view that the template parameters should be visible. They are visible anyway by introspection, and as you and others have pointed out, the way you would have to use the intended interface to process formatted items with the format string means 2 passes over the format string at compile-time. In other words, the compiler would (in this implementation) separate out the data for us in a nice way, but the only way to access it is to generate a string, and then have to split apart that string again to process it a different way. There's no need for that.
 Note that we are trying to prevent people from abusing the 
 implementation to achieve "AST Macros" as Walter likes to put it. If 
 we can provide a better way to generate the formatting, and still keep 
 this property, it has a better chance of being accepted.
It'd be better if this wasn't accepted then, rather than adding a crippled feature that's counter intuitive for a user to use.
I agree. We will have to be convincing that allowing access to the format specifiers and string data separately does not equate to AST macros. -Steve
Sep 09 2020
prev sibling next sibling parent reply James Blachly <james.blachly gmail.com> writes:
On 9/8/20 6:59 AM, Mike Parker wrote:
 This is the discussion thread for the first round of Community Review of 
 DIP 1036, "Formatted String Tuple Literals":
 
 https://github.com/dlang/DIPs/blob/15537f9b36afa48f1c1cd57468e8c77f8f24
9dd/DIPs/DIP1036.md 
I am really, really happy to see string interpolation coming to D, but I have a concern with the implementation as described in the DIP. Viz:
 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.
When I am writing Javascript or Python, I use string interpolation quite a bit (even nicer now that Python3 has f-strings), and in my estimate the proportion of uses with print() (or other language equivalent) versus other uses is at most 50/50. i.e., string interpolation is OFTEN used in many contexts beyond simply printing a message to the user. I read the sections "Usage in existing string-accepting functions" and understand `isInterpolationSpec`, and subsections "Wrong-use in unrelated function" and "On implicit conversions." The authors argue:
 To avoid unintentional bugs in libraries that don't anticipate interpolated
strings, this DIP does not recommend implicit conversion of the interpolation
spec structure to string, ... The logic behind this decision is that, when
making the additional effort to explicitly write format specifiers for all
interpolated values, the user will have demonstrated significant understanding
of how the feature works both in general and for a specific use case. In that
scenario, we can allow implicit conversion so the interpolated string can be
used by existing functions.
They then provide an example using printf. Ignoring for a moment C functions, what is the anticipated issue "with existing functions [and] the safety of accidentally calling existing functions inappropriately" ? Thanks again to the authors. I really truly think this is important work and thank them, but if the barrier to entry for a SEEMINGLY "simple" feature is too high, this makes D much less approachable for new users, about which I believe we should be very concerned. Kind regards
Sep 08 2020
next sibling parent James Blachly <james.blachly gmail.com> writes:
On 9/8/20 2:50 PM, James Blachly wrote:

As a tacky self-followup, I would add that I am not against the 
`interpolationSpec` specifically, but just arguing for more liberal 
approach to implicit conversion to D string, i.e., idup.

Normally I would suggest that implicit .idup should be accompanied by a 
compiler warning (instead of error, suggesting adding .idup), but I know 
how Walter feels about warnings.
Sep 08 2020
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/8/20 2:50 PM, James Blachly wrote:
 On 9/8/20 6:59 AM, Mike Parker wrote:
 This is the discussion thread for the first round of Community Review 
 of DIP 1036, "Formatted String Tuple Literals":

 https://github.com/dlang/DIPs/blob/15537f9b36afa48f1c1cd57468e8c77f8f24
9dd/DIPs/DIP1036.md 
I am really, really happy to see string interpolation coming to D, but I have a concern with the implementation as described in the DIP. Viz:
 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.
When I am writing Javascript or Python, I use string interpolation quite a bit (even nicer now that Python3 has f-strings), and in my estimate the proportion of uses with print() (or other language equivalent) versus other uses is at most 50/50. i.e., string interpolation is OFTEN used in many contexts beyond simply printing a message to the user. I read the sections "Usage in existing string-accepting functions" and understand `isInterpolationSpec`, and subsections "Wrong-use in unrelated function" and "On implicit conversions."
One thing to note here is that i"..." results not in a single thing, but a list of things. So it's not really possible to provide the mechanism we are providing AND have the whole thing implicitly convert to a single string. Much of the arguments about "wrong-use" are aimed at the previous DIP and why we feel this mechanism for the format string is better. Another previous suggestion (by Adam actually) is to wrap the entire thing into a single type, and encapsulate the list of parameters inside that. If we did it that way, then you could potentially automatically convert the whole thing to a string implicitly using existing facilities. But, you do lose some important capabilities. For instance, you would now be passing a copy of each item, instead of the item itself. This has issues that are not easily solved (for example forwarding refness, or binding to an alias). To me it's a choice between not having to specify .idup when you want a string (which necessarily has to allocate, even if it's implicitly done) vs. compile time goodies that come from expanding a thing into a compile-time list. Not only that, but there are already functions which use this mechanism of format + args, and attaching this feature to those functions is going to be much smoother if the parameters are parameters and not stuffed into a struct. This is why we went with the .idup route -- it's simple, easy to write, and already has a well-defined meaning. On top of that, it is a known signal that GC allocations are happening.
 
 The authors argue:
 To avoid unintentional bugs in libraries that don't anticipate 
 interpolated strings, this DIP does not recommend implicit conversion 
 of the interpolation spec structure to string, ... The logic behind 
 this decision is that, when making the additional effort to explicitly 
 write format specifiers for all interpolated values, the user will 
 have demonstrated significant understanding of how the feature works 
 both in general and for a specific use case. In that scenario, we can 
 allow implicit conversion so the interpolated string can be used by 
 existing functions.
They then provide an example using printf. Ignoring for a moment C functions, what is the anticipated issue "with existing functions [and] the safety of accidentally calling existing functions inappropriately" ?
This is the part that's aimed at DIP1027, and why we felt you should be able to overload based on the format string type, and that it should not automatically work for things like the createWindow example. Specifically for people who are used to Javascript or Python (or others), and expect the function to work as a string generator. We hope that the implementation in the compiler is smart enough to suggest the correct usage when the argument type mismatch is detected.
 Thanks again to the authors.  I really truly think this is important 
 work and thank them, but if the barrier to entry for a SEEMINGLY 
 "simple" feature is too high, this makes D much less approachable for 
 new users, about which I believe we should be very concerned.
It's a valid point. The full explanation of why we wrote the DIP this way is not essential to explaining the feature. In documentation, it might be good for ddoc to have a special notation for functions that accept formatted string tuple literals (i.e. collapse the interpolation string format and varargs that follow into one parameter). Then usage is simple, but one still has to understand the mechanisms to provide functions that accept such parameters. Though a simple tutorial and examples will go a long way. BUT, one still has to be wary of how the first argument, if it is an interpolation literal, may consume multiple parameters for the function. For functions that are defined without varargs, it's going to be highly confusing. I would be very surprised if any interpolation string tuple accepting function is not a template varargs one. -Steve
Sep 08 2020
prev sibling next sibling parent Paul Backus <snarwin gmail.com> writes:
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":

 https://github.com/dlang/DIPs/blob/15537f9b36afa48f1c1cd57468e8c77f8f2499dd/DIPs/DIP1036.md
When a DIP has to devote an equal amount of space to justifying the caveats and limitations of its proposal as it does to explaining the proposal in the first place (~1,500 words each), I think that is probably a sign that the proposal is not a very good one. Maybe the authors can try getting it into C++23 instead. :^)
Sep 08 2020
prev sibling next sibling parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 8 September 2020 at 10:59:31 UTC, Mike Parker wrote:
 [...]
I think it's a little bit awkward and risky that things like foo(Args...)(string a, Args args) or I suppose also foo(string a, int b) will get more than one parameter with a call like foo(i"hello $i"); which is very counter-intuitive to all existing concepts (this is a case that would pass multiple arguments from something which looks just like one single string) For example the SQL example shows very nicely why doing this without the library author allowing it is a bad idea. You argue that an attribute for the entire interpolated type is a bad idea and I agree with that, however an attribute just for allowing the compiler to expand interpolated strings to multiple arguments like this would be a great way to avoid unintended potentially dangerous usage. I really like the idea of the special _d_interpolated_string type containing all the parts as that will make usage very flexible. However I really dislike the intended API usage with `toFormatString` and `hasAllSpecs`. To me it seems very specialized just for the printf function and not really designed to be usable for functions performing simple concatenation like text(), which I think are a more common use. It looks like directly accessing "Parts" was not intended, but direct access would be the only way to reasonably and efficiently implement string interpolation as a user (without doing error-prone string replace operations which would break as soon as a user manually types in a % character) Instead of forcing the % syntax onto users using toFormatString, can we specify a proper API that could be implemented without it breaking with a simple i"You scored 100% with $points!".idup ?
Sep 09 2020
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 9 September 2020 at 08:12:05 UTC, WebFreak001 wrote:
 I think it's a little bit awkward and risky that things like

 foo(Args...)(string a, Args args)
 or I suppose also
 foo(string a, int b)

 will get more than one parameter with a call like

 foo(i"hello $i");
That would be a type mismatch error since i"..."'s first argument is an "interpolated tuple spec", NOT a string. The compiler's error message would probably suggest you try ".idup" to convert it to a plain string. If you did that, it would just be a single argument. The implicit conversion hasAllSpecs allows *only* happens if 1) the user provides a {} component for every interpolated item and 2) even so, it converts to `immutable(char)*` rather than `string`.
Sep 09 2020
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/9/20 4:12 AM, WebFreak001 wrote:
 On Tuesday, 8 September 2020 at 10:59:31 UTC, Mike Parker wrote:
 [...]
I think it's a little bit awkward and risky that things like foo(Args...)(string a, Args args) or I suppose also foo(string a, int b) will get more than one parameter with a call like foo(i"hello $i");
That won't compile. The interpolation spec type will not implicitly convert to string.
 
 which is very counter-intuitive to all existing concepts (this is a case 
 that would pass multiple arguments from something which looks just like 
 one single string)
 
 For example the SQL example shows very nicely why doing this without the 
 library author allowing it is a bad idea. You argue that an attribute 
 for the entire interpolated type is a bad idea and I agree with that, 
 however an attribute just for allowing the compiler to expand 
 interpolated strings to multiple arguments like this would be a great 
 way to avoid unintended potentially dangerous usage.
The intention is that you have to opt-in by specifying a template parameter that accepts the spec. An attribute is not necessary.
 
 I really like the idea of the special _d_interpolated_string type 
 containing all the parts as that will make usage very flexible. However 
 I really dislike the intended API usage with `toFormatString` and 
 `hasAllSpecs`. To me it seems very specialized just for the printf 
 function and not really designed to be usable for functions performing 
 simple concatenation like text(), which I think are a more common use. 
 It looks like directly accessing "Parts" was not intended, but direct 
 access would be the only way to reasonably and efficiently implement 
 string interpolation as a user (without doing error-prone string replace 
 operations which would break as soon as a user manually types in a % 
 character)
 
 Instead of forcing the % syntax onto users using toFormatString, can we 
 specify a proper API that could be implemented without it breaking with 
 a simple
 
 i"You scored 100% with $points!".idup
You are right in all of this. I think we probably need to allow access to the parts, and this solves a lot of issues. We can leave everything else, including printf compatibility. One of the goals of this mechanism is to start simple and expand if necessary. But it's going to be impossible to prevent people from introspecting the template parameters anyway. Just providing an alias to the parts is a simple thing, and allows much better code. One thing that I cringe on is the SQL example, where each parameter needs a number. With access to the parts, this is a single pass. With only toFormatString to get the format string, you have to put in a searchable placeholder in the format string, and then replace that on a second pass. I will talk with Adam and Mike and see how to proceed, as this requires a bit more work. -Steve
Sep 09 2020
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
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:


 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
Sep 09 2020
next sibling parent reply James Blachly <james.blachly gmail.com> writes:
On 9/9/20 5:41 PM, Paul Backus wrote:
 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).
This (and the related points about complexity and surprise especially of new users made by Paul but also by myself and others) make me tend to believe that we should just add GC-only, implicit automatic conversion to Dstring, and be done with it. Are there contemporary examples of other languages whose string interpolation is as complex as this proposals? I am really only most familiar with Javascript and Python, both of which use automatic memory management and the *string is a string is a string*. James
Sep 09 2020
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 9 September 2020 at 23:04:37 UTC, James Blachly 
wrote:
 Are there contemporary examples of other languages whose string 
 interpolation is as complex as this proposals? I am really only 
 most familiar with Javascript and Python, both of which use 
 automatic memory management and the *string is a string is a 
 string*.
Javascript is actually *very* similar to this dip, with the key difference that in D, we reuse existing normal function call syntax whereas Javascript invented a new magic function call syntax just for this feature. See the "Tagged templates" section here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals Notice that they call it a "template literal" rather than an interpolated string since it is so much more than a string. If you write foo`${5}, ${23}` in Javascript, it actually will rewrite that into a function call: foo([ "", ", ", ", ", "" ], 5, 23); I realize that's hard to read with all the quotes and commas... but it is essentially a dynamically-typed equivalent to what this DIP is talking about. The first argument to foo is a string spec. In D, we represent it as a templated struct. Javascript instead represents that as an array of strings. But it is fundamentally the same idea: it gives the string pieces from around the placeholders and an entry representing the inserted item. Then, the interpolated items are passed as separate arguments after the spec - just like we propose for D. The example on MDN for this uses JS' `...values` syntax to put it into an array, in D, we'd call that same thing `(Values...)(Values values)`, but again it is the same thing, just JS uses their dynamic typing whereas D uses a template. Now, the obvious difference with Javascript is they have a default function. Above, I wrote foo`...`. Leave the foo part off and it uses the default function instead - which is identical to our proposed idup. JS can do this because they introduced a new function call syntax to the language. And they can do that because JS only has one kind of function call to begin with: obj.foo(x) (where obj is optional and will default to null). D, by contrast, has several kinds of function calls: traditional foo(x), UFCS x.foo, and template foo!(x). Instead of inventing three new kinds of magic function call syntax, we just reuse what we already have. But, of course, that does have one small downside: there's no way to insert a default function like Javascript does without either more compiler magic or limiting it to just one case and forgetting about the others. Instead we simply ask you to explicitly call the function you want in all cases. I doubt most users will even find this particular controversial after they try it in reality.
Sep 09 2020
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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:


 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
Sep 10 2020
parent reply Paul Backus <snarwin gmail.com> writes:
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).
Sep 10 2020
next sibling parent reply aliak <something something.com> writes:
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
Sep 11 2020
parent reply Paul Backus <snarwin gmail.com> writes:
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." :)
Sep 11 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 September 2020 at 10:43:54 UTC, Paul Backus wrote:
 Anyway, I don't expect my idea to satisfy everyone equally.
This right here is why the idup mechanism is how it is. There's ten cases we identified from various people to try to hit: 1. string s = i""; should work. 2. nogc use of i"" should be possible. 3. foo(i""); should work where it is foo(string) {} 4. for createWindow(string s, int width = 0, int height = 0), calling createWindow(i"Connected $id") should NOT result in createWindow("Connected %s", id). It should either error, or convert the entire expression to a string. 5. db.query(i""); should be possibly to do safely 6. int x; verbose_debug!(i"$x assertion failed"); should be possible 7. readf(i"$foo"); should be possible as well as other ref, scope, etc. types 8. compile-time checking of format strings should be possible 9. mixin(i"T $name;"); should work 10. printf(i""); should work Hitting all ten is impossible; some of them are directly contradictory. But if we loosen some of those "should work" things to "works with .idup", then we actually can do them all. possibly do numbers 6, 7. Putting the arguments in an object forces evaluation, which would trigger CTFE errors on 6 and discards the ref storage class in case 7. (now I'm kinda of the opinion that case 7 is silly and not worth fussing over. But the general problem with it is once you put it in an object, parts are lost. I know a lot of people feel the whole concept of D's storage classes were a mistake, but it is what it is. If we go up one level and just present the parameter list, then you could still send it to an object, but you're no longer forced to, so all that data is still available. Jonathan Marler's original PR did what you proposed for `i""`. Walter Bright's did.... almost... what you proposed for `f""`. But better than any of them is Javascript's system, like I wrote about in a previous message, adapted to D. (and I know some of this should be in the DIP, to be honest, I've just written it up a couple times and over the delay to formalize the process, I just plain forgot what I said where. I *very* much simply prefer working with code and casual conversation than with this passive voice hyperformal waterfall spec speak. The dip text itself got weakened too by the focus on specifying ToFormatSpec instead of the actual structure implementation. It is the same code... just rewriting it in formal spec-talk instead of straightforward code is painful. I dropped out of college!)
Sep 11 2020
next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 11 September 2020 at 16:32:28 UTC, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 10:43:54 UTC, Paul Backus wrote:
 [...]
This right here is why the idup mechanism is how it is. There's ten cases we identified from various people to try to hit: [...]
You have a pull request that implement this then?
Sep 11 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 September 2020 at 17:46:22 UTC, 12345swordy wrote:
 You have a pull request that implement this then?
No, but you can copy/paste the example implementation in the dip and translate it by hand to get an idea of how it works.
Sep 11 2020
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 11 September 2020 at 18:03:24 UTC, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 17:46:22 UTC, 12345swordy wrote:
 You have a pull request that implement this then?
No, but you can copy/paste the example implementation in the dip and translate it by hand to get an idea of how it works.
I think you have a better case if you have an PR showing what you have in mind, if formal spec is not your strong suit.
Sep 11 2020
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 11 September 2020 at 16:32:28 UTC, Adam D. Ruppe wrote:
 Hitting all ten is impossible; some of them are directly 
 contradictory. But if we loosen some of those "should work" 
 things to "works with .idup", then we actually can do them all.
If that's your acceptance criterion, it seems to me like my, Walter's, and Jonathan's proposals are all just as good, since you can achieve the same result by appending `.text` and/or `.format`. In fact, I'd argue that they're even better than DIP 1036, because they work with the existing `text` and `format` functions rather that requiring new a tailor-made overload of `idup` to be added to druntime.
 If we go up one level and just present the parameter list, then 
 you could still send it to an object, but you're no longer 
 forced to, so all that data is still available. Jonathan 
 Marler's original PR did what you proposed for `i""`. Walter 
 Bright's did.... almost... what you proposed for `f""`. But 
 better than any of them is Javascript's system, like I wrote 
 about in a previous message, adapted to D.
The main difference is that the Javascript system uses a regular-old Javascript list for its "spec object", rather than an opaque runtime-defined type. That's the real sticking point for me. Especially since the only features it actually buys you that you can't get easily with any of the naked-argument-list proposals are: - Implicit conversion to const(char)* - Ability to write custom overloads that supply a default format specifier I don't think those two features alone are important enough to justify adding a bunch of extra cruft to Phobos and druntime--not to mention giving up compatibility with third-party libraries that *don't* add custom interpolation-spec overloads.
Sep 11 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 September 2020 at 18:16:10 UTC, Paul Backus wrote:
 The main difference is that the Javascript system uses a 
 regular-old Javascript list for its "spec object", rather than 
 an opaque runtime-defined type.
Frankly, I hate the opaque thing too and it is going to change. In my mind, it *must* be introspectable to be useful (without The sample implementation in the DIP its all these points, but the spec text doesn't. We had a hard time figuring out how to word it in spec-ese and kinda gave up, but it is obvious that giving up on that was a major mistake that we're going to go back and correct after this feedback round.
Sep 11 2020
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 11 September 2020 at 18:24:25 UTC, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 18:16:10 UTC, Paul Backus wrote:
 The main difference is that the Javascript system uses a 
 regular-old Javascript list for its "spec object", rather than 
 an opaque runtime-defined type.
Frankly, I hate the opaque thing too and it is going to change. In my mind, it *must* be introspectable to be useful (without The sample implementation in the DIP its all these points, but the spec text doesn't. We had a hard time figuring out how to word it in spec-ese and kinda gave up, but it is obvious that giving up on that was a major mistake that we're going to go back and correct after this feedback round.
Okay, here's my follow-up question: D already has two widely-used conventions for passing "string data with other stuff in the middle" to a function. The first is to use a format string as the first argument, followed by all the other bits of "stuff" as the rest of the argument list. The second is to break the string into pieces, and insert the other bits of "stuff" into the argument list between those string pieces. What do we gain by adopting a *third* convention from Javascript? Aren't the two we have already enough?
Sep 11 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 September 2020 at 18:32:05 UTC, Paul Backus wrote:
 What do we gain by adopting a *third* convention from 
 Javascript?
The complexity of the format spec may seem superfluous, however it serves four key roles: 1. It divorces the compiler entirely from details of generated format strings. For example, different functions that accept format strings might use different default format specifiers. 2. It allows overloading existing string-accepting functions to prevent accidental usage that happens to fit the parameter list (see example below). 3. It provides necessary error checking capabilities. 4. It provides an additional API for user functions to introspect the string, building on D's existing compile-time capabilities.
Sep 11 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 11 September 2020 at 19:04:23 UTC, Adam D. Ruppe wrote:
 The complexity of the format spec may seem superfluous, however 
 it serves four key roles:

     1. It divorces the compiler entirely from details of 
 generated format strings. For example, different functions that 
 accept format strings might use different default format 
 specifiers.
A much easier way to do this is to simply have no default format specifier in the first place. This is how f"..." strings would work in my proposal. (Though I agree this was an issue with DIP 1027.)
     2. It allows overloading existing string-accepting 
 functions to prevent accidental usage that happens to fit the 
 parameter list (see example below).
If a function is prone to accidental usage with string interpolation, it's probably also prone to accidental usage without string interpolation. The solution is to use the type system. Again, I refer you to Scott Meyers for a more detailed explanation: https://www.youtube.com/watch?v=5tg1ONG18H8&t=47m15s
     3. It provides necessary error checking capabilities.
Not sure what you mean by this. The Phobos functions that use the existing argument-list conventions already do error checking; is there something they're currently missing?
     4. It provides an additional API for user functions to 
 introspect the string, building on D's existing compile-time 
 capabilities.
We can already do this with existing D features. See for example `std.format.format`, which has an overload that introspects the format string at compile time.
Sep 11 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 September 2020 at 19:31:33 UTC, Paul Backus wrote:
 The solution is to use the type system.
This is exactly what the DIP does! Something serious must have gotten lost between my brain and the text.
 Not sure what you mean by this. The Phobos functions that use 
 the existing argument-list conventions already do error 
 checking; is there something they're currently missing?
This is kinda a rephrasing of the other three items (though, of course, introspection can do a lot more than just error checking, like I imagine a world where we gather translation strings like gnu gettext but 100% with a stock D compiler, no need for add-on tools) - by providing a new type, you can not only catch it at function overload / template constraint level, but you can also catch errors inside the format string itself. You said:
 We can already do this with existing D features. See for 
 example `std.format.format`, which has an overload that 
 introspects the format string at compile time.
Indeed, and the DIP text has this example: https://github.com/dlang/DIPs/blob/15537f9b36afa48f1c1cd57468e8c77f8f2499dd/DIPs/DIP1036.md#usage-in-existing-string-accepting-functions <quote> auto writefln(Fmt, Args...)(Fmt fmt, Args args) if (isInterpolationSpec!Fmt) return std.stdio.writefln!(fmt.toFormatString!"%s", Args)(args); } These ensure that interpolated strings just work for their most likely target functions while also providing a new benefit: the format string, including user additions via ${}, will be checked at compile time, even when passed as a run-time argument. </quote> Look very carefully at what it is doing there... it does a compile time check of a runtime argument through its type, actually ignoring the runtime pointer to it. Since a different type `Fmt` is generated for each unique i"" instance, you can do the same compile time optimizations format does *without* the explicit overload. It is valid to pass that format string as a template argument since it is generated from the *static data*, encoded in the type, not from the runtime string. This is also the reason why "All format specifiers must be known at compile time" is listed under Limitations. So let's say I call string world = "lol"; func(i"hello ${%d}world"); func's implementation is free to inspect that format string at compile time! It might forward to the `writefln!fmt(args)` in which case it actually gets to leverage existing language features in a new way to check that %d/string mismatch and report it in a way that is impossible with normal writefln today (you must use the explicit template arg overload version at the call site). This DIP builds on D's unique strengths, enhancing existing opportunities. None of the others come close, they're just syntax sugar.
Sep 11 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 11 September 2020 at 19:59:35 UTC, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 19:31:33 UTC, Paul Backus wrote:
 The solution is to use the type system.
This is exactly what the DIP does! Something serious must have gotten lost between my brain and the text.
I guess you didn't have time to check out the video. What I mean is, the solution is to change the signature of "createWindow": alias Width = Typedef!(int, int.init, "Width"); alias Height = Typedef!(int, int.init, "Height"); void createWindow(string title, Width width, Height height); This solves the issue of accidentally passing the wrong thing with i"Window $id", and also prevents non-interpolation-related accidental usage, like mixing up the width and height.
 This DIP builds on D's unique strengths, enhancing existing 
 opportunities. None of the others come close, they're just 
 syntax sugar.
I agree with this 100%, except I think it's a point against DIP 1036 and in favor of the other proposals. :) We already have ways to put stuff in the middle of strings. The reason we want string interpolation is to make the syntax for it less ugly. So, it *should* be "just syntax sugar." Anything beyond that is bloat.
Sep 11 2020
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote:
 This solves the issue of accidentally passing the wrong thing 
 with i"Window $id", and also prevents non-interpolation-related 
 accidental usage, like mixing up the width and height.
yeah that's legit. So what we're considering is simplifying it a bit and dropping the embeddable format strings. Also Steven is seeing if he can make auto-conversion work and I'm mulling over your idea of two different prefixes. t"..." yields the tuple, i"..." automatically calls idup (or whatever). t is the building block, i is the "just give me a string" shortcut built on top of t. So in my next draft, processing a t"" yourself looks like: auto foo(InterpList, Args...)(InterpList interp, Args args) { string ret; foreach(idx, arg; args) { ret ~= interp.strings[idx]; ret ~= to!string(arg); } ret ~= interp.strings[args.length]; return ret; } And processing an i"" is trivial; it is just either a string or a subclass of string (aka a struct with alias toString this) and you'd just use it like that. The t"" is more composable; it is the superior language feature. But I can live with a convenience compromise. So we'll see.
Sep 11 2020
next sibling parent reply claptrap <clap trap.com> writes:
On Saturday, 12 September 2020 at 02:48:38 UTC, Adam D. Ruppe 
wrote:
 On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote:
 This solves the issue of accidentally passing the wrong thing
And processing an i"" is trivial; it is just either a string or a subclass of string (aka a struct with alias toString this) and you'd just use it like that. The t"" is more composable; it is the superior language feature. But I can live with a convenience compromise. So we'll see.
Thats a step in the right direction IMO.
Sep 12 2020
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/12/20 5:27 AM, claptrap wrote:
 On Saturday, 12 September 2020 at 02:48:38 UTC, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote:
 This solves the issue of accidentally passing the wrong thing
And processing an i"" is trivial; it is just either a string or a subclass of string (aka a struct with alias toString this) and you'd just use it like that. The t"" is more composable; it is the superior language feature. But I can live with a convenience compromise. So we'll see.
Thats a step in the right direction IMO.
To me it seems akin to that moment you realize the practical joke has gone too far. Flight attendant: "More of anything?" Seinfeld: "More of everything!" So now we're talking about not one, but two interpolated strings. Deus Ex Machina and all that. (For fun and giggles: Good Work six months from now will make their semantics juuuuust slightly different.) How is this great design? There is so much to be said about sense and sensibility; living under one's means; economy of mechanism; creating a part of a whole; and such. I really feel we miss a different mind on the team. Someone who just thinks differently. Like an architect. Or a novelist. One possibility - which sadly comes from my limited engineering mind - is to create and observe budgets for metrics that are proxies to complexity. * 1000 words in the DIP * 1000 words complete documentation * 1000 words tutorial * 1000 lines in total implementation (compiler + library) * 30 seconds explanation that doesn't omit any dangerous subtleties
Sep 12 2020
parent reply claptrap <clap trap.com> writes:
On Saturday, 12 September 2020 at 13:06:01 UTC, Andrei 
Alexandrescu wrote:
 On 9/12/20 5:27 AM, claptrap wrote:
 On Saturday, 12 September 2020 at 02:48:38 UTC, Adam D. Ruppe 
 wrote:
 On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus 
 wrote:
 This solves the issue of accidentally passing the wrong thing
And processing an i"" is trivial; it is just either a string or a subclass of string (aka a struct with alias toString this) and you'd just use it like that. The t"" is more composable; it is the superior language feature. But I can live with a convenience compromise. So we'll see.
Thats a step in the right direction IMO.
To me it seems akin to that moment you realize the practical joke has gone too far. Flight attendant: "More of anything?" Seinfeld: "More of everything!" So now we're talking about not one, but two interpolated strings. Deus Ex Machina and all that. (For fun and giggles: Good Work six months from now will make their semantics juuuuust slightly different.) How is this great design? There is so much to be said about sense and sensibility; living under one's means; economy of mechanism; creating a part of a whole; and such. I really feel we miss a different mind on the team. Someone who just thinks differently. Like an architect. Or a novelist.
One more interpolated string ... one more brain ... more of everything ;) Maybe the problem isnot enough exploratory work is done up front? It's like evolutionary optimisation, if the initial set of solutions are not spread wide enough over the problem space you will inevitably converge on a local minimum instead of the global one. I mean this DIP is a variation on Walters, Walters is an variation in writeln. They arnt really looking outside already established ideas for inspiration. Its the convergent vs divergent thinking problem. And maybe programmers are very convergent in general, because you pretty constantly need to be evaluating what your doing as a programmer. So it's switch out of that way of thinking and just shoot ideas off with no criticism. IE. Maybe have 4 or 5 people come up with as many solutions as possible, literally just write down ideas as they come to you. And then bring them all together and evaluate them. It's usually the outlier ideas that can spur people to "think differently" about the problem even if those outliers dont end up going anywhere.
 One possibility - which sadly comes from my limited engineering 
 mind - is to create and observe budgets for metrics that are 
 proxies to complexity.

 * 1000 words in the DIP
 * 1000 words complete documentation
 * 1000 words tutorial
 * 1000 lines in total implementation (compiler + library)
 * 30 seconds explanation that doesn't omit any dangerous 
 subtleties
Im only going on what I see in the newsgroup but it often seems like everyone has their own set of goals by which to judge the DIP, instead of there being a document saying the DIP should meet these goals, specifying if a goal is an absolute or very desirable, or just nice to have. I it seems there's a jump straight from "we want string interpolation" to "heres a solution" and completely skip "what do we really want from string interpolation".
Sep 13 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 13 September 2020 at 09:40:34 UTC, claptrap wrote:
 Maybe the problem isnot enough exploratory work is done up 
 front?
Various forms of this have come up over the years. A PR in 2017 offered just the basics done automatically: https://github.com/dlang/dmd/pull/6703 This kind of thing is perhaps the most obvious - just have the compiler rewrite it for you. Very limited, though, it only really works for the one use case. Been discussed several times before this too, but never went anywhere. This one in 2018 though opened up some new ideas, from Jonathan Marler: https://github.com/dlang/dmd/pull/7988 The key innovation there was instead of calling a function, it just built an argument list. This is when these proposals actually started getting interesting to me: it makes it usable in a lot more cases, though the cost is it isn't as convenient. It is very simple though. As you can see though, it got a great many comments and even a DIP draft <https://github.com/dlang/DIPs/pull/140/files>. In 2019, Walter started thinking in terms of printf, and this eventually led to his DIP 1027, which had the compiler build a string and reorder the arguments for you. It is still a parameter list you just pass to another function, but it is partially cooked. This adds to the complexity but opened up more possibilities. That's an interesting innovation too, but his DIP had a number of flaws and missed potential which this new DIP aims to patch. The major innovation here is adding a new type to the tuple. Over the last couple days, we've had some new ideas came up and I considered what we could do with them. and Javascript both have quite interesting offerings, if you haven't looked at them, you should. The links are in the OP's references. Anyway, meanwhile, Steven went back to the old ideas. So instead of adding new stuff, he shattered it and picked up just the pieces that survived. And what we're looking at now just takes the best one feature from each generation and puts it together. Convenience of gen one, flexibility of gen two, power of gen three. Without the rest of the accumulated cruft. At first, I pushed back at him saying various use cases wouldn't work... but turns out they do. Much of the other stuff genuinely wasn't necessary. So we wrote the first several drafts and now are in the editing process to pare it back down.
 IE. Maybe have 4 or 5 people come up with as many solutions as 
 possible, literally just write down ideas as they come to you. 
 And then bring them all together and evaluate them. It's 
 usually the outlier ideas that can spur people to "think 
 differently" about the problem even if those outliers dont end 
 up going anywhere.
Indeed, I often "think out loud" in these thread. Most of it goes nowhere... but every so often some piece of it endures. If we just instantly shot everything down instantly, we'd flush the gold with the dirt.
Sep 13 2020
parent reply claptrap <clap trap.com> writes:
On Monday, 14 September 2020 at 02:54:35 UTC, Adam D. Ruppe wrote:
 On Sunday, 13 September 2020 at 09:40:34 UTC, claptrap wrote:
 IE. Maybe have 4 or 5 people come up with as many solutions as 
 possible, literally just write down ideas as they come to you. 
 And then bring them all together and evaluate them. It's 
 usually the outlier ideas that can spur people to "think 
 differently" about the problem even if those outliers dont end 
 up going anywhere.
Indeed, I often "think out loud" in these thread. Most of it goes nowhere... but every so often some piece of it endures. If we just instantly shot everything down instantly, we'd flush the gold with the dirt.
That's still not the same thing. These threads are full of assessment and evaluation. The first reply to one of your ideas will be someone evaluating it. That's not good for spurring more ideas. Think like improv comedy, if after each time someone said something there was a pause for evaluation of how funny it was, it would kill the momentum. To really broaden the idea search space there needs to be no evaluation while you're generating ideas. If that was done up front, you might have skipped 2 years of DIPs that went nowhere? I dont know maybe there are constraints on language design that means theres not a large space to explore.
Sep 15 2020
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 15 September 2020 at 09:30:37 UTC, claptrap wrote:
 These threads are full of assessment and evaluation.
Yeah, it kinda sucks.
 If that was done up front, you might have skipped 2 years of 
 DIPs that went nowhere?
There's only actually been two formal DIPs: Walter's and this one, which is just a tweak to Walter's (though the next version after this round is a full rewrite). The rest of it has been sample implementations or just informal talk. Just it is worth noting this conversion has been going on for a while including a lot more people than are present in this thread.
Sep 15 2020
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/11/20 10:48 PM, Adam D. Ruppe wrote:
 Also Steven is seeing if he can make auto-conversion work and I'm 
 mulling over your idea of two different prefixes. t"..." yields the 
 tuple, i"..." automatically calls idup (or whatever).
I am legitimately scared at this point.
Sep 12 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 12 September 2020 at 12:40:21 UTC, Andrei 
Alexandrescu wrote:
 I am legitimately scared at this point.
Posts like this add nothing of value to the conversation. You should at least say why. But you have to understand there is literally no winning. Provide a convenience feature and people complain it is not composable. Provide a composable feature and people complain it is not convenient. Provide both and get this. At a certain point, we'll have to tell one group (or more) "sorry, you lose". Personally, I say we should make it composable and tell everyone else to suck it up and call a function on the result. But I'm trying to be a team player here and at least explore the options before dismissing them.
Sep 12 2020
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/12/20 9:11 AM, Adam D. Ruppe wrote:
 On Saturday, 12 September 2020 at 12:40:21 UTC, Andrei Alexandrescu wrote:
 I am legitimately scared at this point.
Posts like this add nothing of value to the conversation. You should at least say why.
The "why" is in subtext. Apologies if not obvious. It was along the lines of: "Great, so this language feature already wants to serve too many masters. Now we have it spawning Sorcerer-Apprentice style. The ultimate Deus Ex Machina of language design ever: yet another syntactical addition. A tool to be reached for with the highest trepidation, now mentioned glibly. I am afraid. I am very afraid."
 But you have to understand there is literally no winning. Provide a 
 convenience feature and people complain it is not composable. Provide a 
 composable feature and people complain it is not convenient. Provide 
 both and get this.
At this point I think a win would be to reject this DIP. I'd rather have no interpolation than live with this little monster.
 At a certain point, we'll have to tell one group (or more) "sorry, you 
 lose". Personally, I say we should make it composable and tell everyone 
 else to suck it up and call a function on the result. But I'm trying to 
 be a team player here and at least explore the options before dismissing 
 them.
There may be the opposite view, in which the community tells you to give up on this or that or the other facility. It seems to me that that's the best mental frame for a DIP writer. There is also a matter of being able to disagree strongly on something without that spilling into the personal. (Something my wife and I very much want to do in our own disagreements, with limited but notable success.) You and I work together. Steve and I are neighbors of sorts. I should be able to look you two in the eye and tell you, "this design sucks". And you should be able to tell me (hopefully not in retaliation), "autodecoding sucks". And we should all enjoy a drink of our choice together same as before.
Sep 12 2020
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/12/2020 8:04 AM, Andrei Alexandrescu wrote:
 There is also a matter of being able to disagree strongly on something without 
 that spilling into the personal. (Something my wife and I very much want to do 
 in our own disagreements, with limited but notable success.) You and I work 
 together. Steve and I are neighbors of sorts. I should be able to look you two 
 in the eye and tell you, "this design sucks". And you should be able to tell
me 
 (hopefully not in retaliation), "autodecoding sucks". And we should all enjoy
a 
 drink of our choice together same as before.
I'll "heft a pint" to that!
Sep 12 2020
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/12/20 10:48 PM, Walter Bright wrote:
 On 9/12/2020 8:04 AM, Andrei Alexandrescu wrote:
 There is also a matter of being able to disagree strongly on something 
 without that spilling into the personal. (Something my wife and I very 
 much want to do in our own disagreements, with limited but notable 
 success.) You and I work together. Steve and I are neighbors of sorts. 
 I should be able to look you two in the eye and tell you, "this design 
 sucks". And you should be able to tell me (hopefully not in 
 retaliation), "autodecoding sucks". And we should all enjoy a drink of 
 our choice together same as before.
I'll "heft a pint" to that!
I suspect we shall be doing that in 2 weeks while discussing this DIP (hopefully updated)! #beerconfsept -Steve
Sep 13 2020
prev sibling parent reply James Lu <jamtlu gmail.com> writes:
On Saturday, 12 September 2020 at 02:48:38 UTC, Adam D. Ruppe 
wrote:
 On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote:
 This solves the issue of accidentally passing the wrong thing 
 with i"Window $id", and also prevents 
 non-interpolation-related accidental usage, like mixing up the 
 width and height.
yeah that's legit. So what we're considering is simplifying it a bit and dropping the embeddable format strings. Also Steven is seeing if he can make auto-conversion work and I'm mulling over your idea of two different prefixes. t"..." yields the tuple, i"..." automatically calls idup (or whatever). t is the building block, i is the "just give me a string" shortcut built on top of t. So in my next draft, processing a t"" yourself looks like: auto foo(InterpList, Args...)(InterpList interp, Args args) { string ret; foreach(idx, arg; args) { ret ~= interp.strings[idx]; ret ~= to!string(arg); } ret ~= interp.strings[args.length]; return ret; } And processing an i"" is trivial; it is just either a string or a subclass of string (aka a struct with alias toString this) and you'd just use it like that. The t"" is more composable; it is the superior language feature. But I can live with a convenience compromise. So we'll see.
Too many features, too much syntax, increases mental overhead. Instead of adding syntax, you can use an existing language feature to do it. For example, t"" could be the default, and it can use alias this to do an automatic conversion of t"" to i"": struct Tuple { private string toString(); alias toString this; }; I don't know how using alias this in this way would change compilation time to relatively efficient (=efficient enough to test with) machine code.
Sep 12 2020
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/12/20 10:37 AM, James Lu wrote:
 On Saturday, 12 September 2020 at 02:48:38 UTC, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote:
 This solves the issue of accidentally passing the wrong thing with 
 i"Window $id", and also prevents non-interpolation-related accidental 
 usage, like mixing up the width and height.
yeah that's legit. So what we're considering is simplifying it a bit and dropping the embeddable format strings. Also Steven is seeing if he can make auto-conversion work and I'm mulling over your idea of two different prefixes. t"..." yields the tuple, i"..." automatically calls idup (or whatever). t is the building block, i is the "just give me a string" shortcut built on top of t. So in my next draft, processing a t"" yourself looks like: auto foo(InterpList, Args...)(InterpList interp, Args args) {     string ret;     foreach(idx, arg; args) {         ret ~= interp.strings[idx];         ret ~= to!string(arg);     }     ret ~= interp.strings[args.length];     return ret; } And processing an i"" is trivial; it is just either a string or a subclass of string (aka a struct with alias toString this) and you'd just use it like that. The t"" is more composable; it is the superior language feature. But I can live with a convenience compromise. So we'll see.
Too many features, too much syntax, increases mental overhead. Instead of adding syntax, you can use an existing language feature to do it. For example, t"" could be the default, and it can use alias this to do an automatic conversion of t"" to i"": struct Tuple {     private string toString();     alias toString this; }; I don't know how using alias this in this way would change compilation time to  relatively efficient (=efficient enough to test with) machine code.
I think it's telling that now it's not only about adding two new tokens to the language, but about a synthetic subtyping relationship between them. How can this pass the laughing test?
Sep 12 2020
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 12 September 2020 at 14:37:45 UTC, James Lu wrote:
 Instead of adding syntax, you can use an existing language 
 feature to do it.
That is good if we just doing simple values, but it fails for D's unique compile-time things and is iffy with ref and non-copyable types. I wrote about it in more detail in my blog last year: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html#hybrid-library-solutions In short, things like `ref`, `enum`, and `alias`-ness of data are lost through that layer. So good, but not great because it doesn't build on D's other existing strengths. Me and Steven continue to argue in a chat btw, we're whittling each other's ideas down and we're coming to something you all will prolly like... so stay tuned.
Sep 12 2020
parent James Lu <jamtlu gmail.com> writes:
On Saturday, 12 September 2020 at 14:53:48 UTC, Adam D. Ruppe 
wrote:
 On Saturday, 12 September 2020 at 14:37:45 UTC, James Lu wrote:
 [...]
That is good if we just doing simple values, but it fails for D's unique compile-time things and is iffy with ref and non-copyable types. I wrote about it in more detail in my blog last year: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html#hybrid-library-solutions In short, things like `ref`, `enum`, and `alias`-ness of data are lost through that layer. So good, but not great because it doesn't build on D's other existing strengths. Me and Steven continue to argue in a chat btw, we're whittling each other's ideas down and we're coming to something you all will prolly like... so stay tuned.
I have participated in Python language design discussions.
Sep 13 2020
prev sibling parent reply Aliak <something something.com> writes:
On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote:
 On Friday, 11 September 2020 at 19:59:35 UTC, Adam D. Ruppe 
 wrote:
 On Friday, 11 September 2020 at 19:31:33 UTC, Paul Backus 
 wrote:
 The solution is to use the type system.
This is exactly what the DIP does! Something serious must have gotten lost between my brain and the text.
I guess you didn't have time to check out the video. What I mean is, the solution is to change the signature of "createWindow": alias Width = Typedef!(int, int.init, "Width"); alias Height = Typedef!(int, int.init, "Height"); void createWindow(string title, Width width, Height height);
Requiring to retype int semantically for every function that has a string followed by an int to avoid “non-obvious” affects of a language feature seems seems a bit overkill. Pretty sure there was something in Scott meyers talks about APIs that work how you’d expect them to as well.
 This solves the issue of accidentally passing the wrong thing 
 with i"Window $id", and also prevents non-interpolation-related 
 accidental usage, like mixing up the width and height.

 This DIP builds on D's unique strengths, enhancing existing 
 opportunities. None of the others come close, they're just 
 syntax sugar.
I agree with this 100%, except I think it's a point against DIP 1036 and in favor of the other proposals. :) We already have ways to put stuff in the middle of strings. The reason we want string interpolation is to make the syntax for it less ugly. So, it *should* be "just syntax sugar." Anything beyond that is bloat.
Sep 12 2020
parent Paul Backus <snarwin gmail.com> writes:
On Saturday, 12 September 2020 at 07:49:49 UTC, Aliak wrote:
 Requiring to retype int semantically for every function that 
 has a string followed by an int to avoid “non-obvious” affects 
 of a language feature seems seems a bit overkill.
Nobody is required to do anything. My point is, this kind of function is prone to accidental usage *with or without* string interpolation, and making the argument list more strongly typed is an effective technique for fixing that. Of course, you can also decide that the consequences of accidental usage are not a big deal, and that you're willing to live with them for the sake of convenience. I think that's a totally reasonable decision to make, especially for safe functions. Adding additional complexity to string interpolation to compensate for deficiencies in library interfaces is not good design. Problems should be addressed at their source.
Sep 12 2020
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.com> writes:
On 9/11/20 2:24 PM, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 18:16:10 UTC, Paul Backus wrote:
 The main difference is that the Javascript system uses a regular-old 
 Javascript list for its "spec object", rather than an opaque 
 runtime-defined type.
Frankly, I hate the opaque thing too and it is going to change. In my mind, it *must* be introspectable to be useful (without that, it also
Well it looks like that opaque thing should be the result of "tuple" and what's now "idup" should be "text", which takes us somewhere in between the previous DIP (and what people opine in this thread) and this DIP. Lowering for this: i"Hello, $name" would be: tuple("Hello, ", name) and that's the way the cookie crumbles. Of course the problem is "tuple" is somewhere in std instead of being in object.d. But if we zero in on this notion that we want a simple lowering, no support for all that %s nonsense, and something that people don't need to design functions especially for, that's an easy problem to look at. BTW people will do this: auto var = i"Hello, $name"; They will expect a string. Now maybe we can talk them into well that's a tuple, which is nice because nogc, has full type info, etc. etc. But if we start talking about yet another __opaqueTypeWithItsOwnAPI then we've lost already.
Sep 11 2020
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Friday, 11 September 2020 at 20:04:35 UTC, Andrei Alexandrescu 
wrote:
 Of course the problem is "tuple" is somewhere in std instead of 
 being in object.d.
could be a compiler tuple which doesn't need std nor object.d.
Sep 11 2020
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/11/20 5:36 PM, Stefan Koch wrote:
 On Friday, 11 September 2020 at 20:04:35 UTC, Andrei Alexandrescu wrote:
 Of course the problem is "tuple" is somewhere in std instead of being 
 in object.d.
could be a compiler tuple which doesn't need std nor object.d.
Shouldn't because it needs to be expandable on demand, not implicitly.
Sep 12 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Saturday, 12 September 2020 at 12:37:14 UTC, Andrei 
Alexandrescu wrote:
 On 9/11/20 5:36 PM, Stefan Koch wrote:
 
 could be a compiler tuple which doesn't need std nor object.d.
Shouldn't because it needs to be expandable on demand, not implicitly.
The only way I can think of to do this that works in the general case is something like the following: // Before writeln(i"Hello $name!".expand); // After template Pack(Args...) { alias expand = Args; } auto ref __interpexpr1() { return name; } writeln(Pack!("Hello ", __interpexpr1, "!").expand); The reason you can't use a struct (that is, a "run=time tuple") is that the mapping from *expressions* to *values* is not injective--it discards information about ref-ness and lazy-ness (and maybe others I haven't thought of?). And the reason you have to "quote" each expression by wrapping it in a function is that template argument lists only accept symbols, not expressions. I'm not sure if I like this better or worse than DIP 1027's "naked argument list" approach.
Sep 12 2020
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/12/20 9:44 AM, Paul Backus wrote:
 On Saturday, 12 September 2020 at 12:37:14 UTC, Andrei Alexandrescu wrote:
 On 9/11/20 5:36 PM, Stefan Koch wrote:
 could be a compiler tuple which doesn't need std nor object.d.
Shouldn't because it needs to be expandable on demand, not implicitly.
The only way I can think of to do this that works in the general case is something like the following: // Before writeln(i"Hello $name!".expand); // After template Pack(Args...) {     alias expand = Args; }
Affirmative. We have that already: https://dlang.org/library/std/typecons/tuple.expand.html A dead simple Pack would have a good place in druntime and have Tuple be an elaboration thereof.
 auto ref __interpexpr1() { return name; }
 
 writeln(Pack!("Hello ", __interpexpr1, "!").expand);
 
 The reason you can't use a struct (that is, a "run=time tuple") is that 
 the mapping from *expressions* to *values* is not injective--it discards 
 information about ref-ness and lazy-ness (and maybe others I haven't 
 thought of?). And the reason you have to "quote" each expression by 
 wrapping it in a function is that template argument lists only accept 
 symbols, not expressions.
 
 I'm not sure if I like this better or worse than DIP 1027's "naked 
 argument list" approach.
I'd say don't complicate with that. Copy everything into the tuple. When one reaches for interpolated strings, it's not like they're hoping for a speed demon. Okay to draw the line at nogc.
Sep 12 2020
parent Paul Backus <snarwin gmail.com> writes:
On Saturday, 12 September 2020 at 14:47:47 UTC, Andrei 
Alexandrescu wrote:
 On 9/12/20 9:44 AM, Paul Backus wrote:
 // After
 template Pack(Args...)
 {
      alias expand = Args;
 }
Affirmative. We have that already: https://dlang.org/library/std/typecons/tuple.expand.html A dead simple Pack would have a good place in druntime and have Tuple be an elaboration thereof.
There's a version in std.meta, though it's currently marked as private: https://github.com/dlang/phobos/blob/v2.093.1/std/meta.d#L1796
 I'd say don't complicate with that. Copy everything into the 
 tuple. When one reaches for interpolated strings, it's not like 
 they're hoping for a speed demon. Okay to draw the line at 
  nogc.
It's not really about speed, it's about making sure that code that *looks* equivalent actually *is* equivalent. Do we want to have to explain to users that these two lines of code, which do the same thing: writeln(i"Hello $name!".expand); writeln("Hello ", name, "!"); ...actually have subtly different evaluation semantics, and that very occasionally they may have to stop think about whether they want the first or the second one? This is the same kind of situation as C++ is in w.r.t. initialization, which has been described as a "nightmare". [1] Obviously the scale of the issue here is much smaller, but even small annoyances can add up over time. [1] https://www.youtube.com/watch?v=7DTlWPgX6zs
Sep 12 2020
prev sibling parent reply claptrap <clap trap.com> writes:
On Friday, 11 September 2020 at 16:32:28 UTC, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 10:43:54 UTC, Paul Backus wrote:
 Anyway, I don't expect my idea to satisfy everyone equally.
This right here is why the idup mechanism is how it is. There's ten cases we identified from various people to try to hit: 1. string s = i""; should work. 2. nogc use of i"" should be possible. 3. foo(i""); should work where it is foo(string) {} 4. for createWindow(string s, int width = 0, int height = 0), calling createWindow(i"Connected $id") should NOT result in createWindow("Connected %s", id). It should either error, or convert the entire expression to a string. 5. db.query(i""); should be possibly to do safely 6. int x; verbose_debug!(i"$x assertion failed"); should be possible 7. readf(i"$foo"); should be possible as well as other ref, scope, etc. types 8. compile-time checking of format strings should be possible 9. mixin(i"T $name;"); should work 10. printf(i""); should work Hitting all ten is impossible; some of them are directly contradictory. But if we loosen some of those "should work" things to "works with .idup", then we actually can do them all.
The most critical part of global optimisation is making sure your cost function is good. If you dont account for all the things you want to achieve, and weight them appropriately then you will end up with a sub optimal solution. IE. In setting those 10 requirements you will pay somewhere else in the design. So the question is are those 10 requirements all thats important? Are they all more important than... "Is it easy to explain to newbies?" "Is it easy to use correctly?" "Will it just work with existing code?" etc.. Did you account for everything you want in the cost function?
Sep 11 2020
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 September 2020 at 22:04:43 UTC, claptrap wrote:
 "Is it easy to explain to newbies?"
I've personally answered ~18% of all D questions on Stack Overflow and while I don't have easily-accessible metrics for the other D help channels, it is likely a similar proportion. I'm keenly aware that there might be explanations to new users, and I know I'm probably going to be answering about 1/6th of them myself. Just like I frequently explain why `int[] a = [1,2].map!(a => a*2);` doesn't compile. There's a reason for that, so it is a chance for them to learn something new. Or they can just slap `.array` on it and move on. But if they are willing to learn something new, D opens up a whole new world of possibilities.
Sep 11 2020
prev sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
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
Sep 11 2020
parent reply Paul Backus <snarwin gmail.com> writes:
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.
Sep 11 2020
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
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.
Sep 11 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 11 September 2020 at 14:05:51 UTC, 12345swordy wrote:
 On Friday, 11 September 2020 at 13:46:52 UTC, Paul Backus wrote:
 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.
I don't understand the objection. Both `printf` and `writefln` are standard-library features in their respective languages. I guess I could have been more precise and written "Phobos" and "libc" instead of "D" and "C", but I assumed that was clear from context.
Sep 11 2020
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 11 September 2020 at 14:15:23 UTC, Paul Backus wrote:
 On Friday, 11 September 2020 at 14:05:51 UTC, 12345swordy wrote:
 On Friday, 11 September 2020 at 13:46:52 UTC, Paul Backus 
 wrote:
 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.
I don't understand the objection.
You request people who maintain c/c++ binding libraries to put into the extra effort of preventing users from accidentally call the wrong function when using string interpolate. That is just plan unreasonable.
Sep 11 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 11 September 2020 at 14:56:10 UTC, 12345swordy wrote:
 You request people who maintain c/c++ binding libraries to put 
 into the extra effort of preventing users from accidentally 
 call the wrong function when using string interpolate. That is 
 just plan unreasonable.
I request that library maintainers, *in general*, put in the extra effort of preventing users from accidentally calling the wrong function, *in general*, because it's a basic tenet of good library design. The fact that it also helps with string interpolation is just a nice bonus. :) If someone insists on using a badly-designed C library without wrapping it, that's their problem. No amount of compiler cleverness is going to make badly-designed C libraries pleasant to use.
Sep 11 2020
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 11 September 2020 at 15:14:29 UTC, Paul Backus wrote:
 On Friday, 11 September 2020 at 14:56:10 UTC, 12345swordy wrote:
 You request people who maintain c/c++ binding libraries to put 
 into the extra effort of preventing users from accidentally 
 call the wrong function when using string interpolate. That is 
 just plan unreasonable.
I request that library maintainers, *in general*, put in the extra effort of preventing users from accidentally calling the wrong function, *in general*, because it's a basic tenet of good library design. The fact that it also helps with string interpolation is just a nice bonus. :)
Do you think that the d language should allow opimplicit conversion if think that preventing calling the wrong function rest on the library and not the language?
Sep 11 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 11 September 2020 at 15:27:08 UTC, 12345swordy wrote:
 Do you think that the d language should allow opimplicit 
 conversion if think that preventing calling the wrong function 
 rest on the library and not the language?
I think the D language should give programmers the tools they need to write good code, and should trust programmers to use the tools it gives them responsibly. If D can't trust programmers to use this style of interpolated string (that lowers to an argument list) responsibly, then it shouldn't have them at all. A crippled version like DIP 1036 is not the solution.
Sep 11 2020
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 11 September 2020 at 16:10:17 UTC, Paul Backus wrote:
 On Friday, 11 September 2020 at 15:27:08 UTC, 12345swordy wrote:
 Do you think that the d language should allow opimplicit 
 conversion if think that preventing calling the wrong function 
 rest on the library and not the language?
I think the D language should give programmers the tools they need to write good code, and should trust programmers to use the tools it gives them responsibly. If D can't trust programmers to use this style of interpolated string (that lowers to an argument list) responsibly, then it shouldn't have them at all. A crippled version like DIP 1036 is not the solution.
That doesn't answer my question.
Sep 11 2020
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.com> writes:
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:


 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.
Sep 10 2020
prev sibling next sibling parent reply zoujiaqing <zoujiaqing gmail.com> writes:
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":

 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. Discussion in this 
 thread may continue beyond that point.

 Here in the discussion thread, you are free to discuss anything 
 and everything related to the DIP. Express your support or 
 opposition, debate alternatives, argue the merits, etc.

 However, if you have any specific feedback on how to improve 
 the proposal itself, then please post it in the feedback 
 thread. The feedback thread will be the source for the review 
 summary that I will write at the end of this review round. I 
 will post a link to that thread immediately following this 
 post. Just be sure to read and understand the Reviewer 
 Guidelines before posting there:

 https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md

 And my blog post on the difference between the Discussion and 
 Feedback threads:

 https://dlang.org/blog/2020/01/26/dip-reviews-discussion-vs-feedback/

 Please stay on topic here. I will delete posts that are 
 completely off-topic.
Please support like this: int i = 10; string b = "test " ~ i; writeln(b); // test 10
Sep 10 2020
next sibling parent reply Matheus <matheus gmail.com> writes:
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.
Sep 10 2020
parent Matheus <matheus gmail.com> writes:
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.
Sep 10 2020
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
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
Sep 10 2020
prev sibling next sibling parent reply SHOO <zan77137 nifty.com> writes:
I'm eagerly awaiting the inclusion of this feature in the D 
language!

Well, I have a few questions and points about this DIP.

1. Although the Abstract says "embedding arguments in the string 
itself", the DIP does not propose a syntax for embedding 
arguments in the string; the DIP proposes a syntax for splitting 
the string into tuples. I think, as I do, that what most people 
want is "embedding arguments in the string itself", so the 
essence of DIP should be the same. It might be a good idea to add 
a `f"..."` syntax that has the same meaning as `i"...".idup`.

2. It doesn't seem to work well with the {} style formatting 

correct?
`String.Format("You are now {0} years old.", years - 1)` eq 
`String.Format(i"You are now ${\{0\}}(years - 1) years old.")`
This is a commonly used formatting style, so it would be nice to 
have an aid to this.

3. The object.idup in the DIP uses `import std.format`, is it 
permissible for the druntime to be dependent on Phobos?

4. Are there any reasons why backquotes (i`...`) are not allowed? 
Of the several string literals currently available, back-quoting 
string literals seem to be a good match for this DIP.

5. Although you use the name idup, idup should be used to create 
`immutable(_d_interpolated_string!Parts)`, which is an immutable 
duplication. In other words, I think you should avoid using this 
name. A good alternative is `toString`. On the other hand, this 
alternative may dilute the implications of the GC being used, but 
idup does not imply that the GC will be used in the first place.
Sep 11 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 September 2020 at 17:37:36 UTC, SHOO wrote:
 2. It doesn't seem to work well with the {} style formatting 

 correct?
 `String.Format("You are now {0} years old.", years - 1)`
You'd do it more like `String.Format(i"You are now ${{0}}(years - 1) years old.")` No backslashes. But it isn't really ideal for positional ones like that since you'd have to keep the count going right yourself. At this point you would ideally write an overload to String.Format that checks for the interpolation spec then translates. The DIP's text as submitted right now makes this unnecessarily difficult, so we're gonna reword it. The same implementation still works though.
 3. The object.idup in the DIP uses `import std.format`, is it 
 permissible for the druntime to be dependent on Phobos?
Technically, druntime is still independent. Since it is a template, its dependency falls on the user, not the library. When you compile druntime, that code is completely ignored. It is not present in the compiled library and the import is not processed. If you use the idup function, the instance appears in *your* code and only then is Phobos actually imported. So formally, the dependency is on phobos from your code at the use point. So if you never use it, there's no dependency. This is one of D's coolest features to me btw.
 4. Are there any reasons why backquotes (i`...`) are not 
 allowed?
Trying to just define the simplest thing that can work. D has a lot of string types and adding i to each of them is a lot.... All these cases are possible with the juxtaposition thing though: i""`....` would work the same way.
 5. Although you use the name idup, idup should be used to 
 create `immutable(_d_interpolated_string!Parts)`
There's two pieces to the interpolated tuple: the spec definition and the arguments. The _d_interpolated_string!Parts thing is just the spec definition. So your example is wrong: you left the arguments out. idup makes no sense without combining it. The main reason for using idup over toString though is just reusing an existing global name... it won't break any code since it isn't introducing anything new. And since it already works on string it has some precedent: char[] a; string b = a; // cannot convert, you need to idup it. string b = i"xxx"; // cannot convert, also need to idup it.
Sep 11 2020
parent reply SHOO <zan77137 nifty.com> writes:
On Friday, 11 September 2020 at 18:17:10 UTC, Adam D. Ruppe wrote:
 On Friday, 11 September 2020 at 17:37:36 UTC, SHOO wrote:
 2. It doesn't seem to work well with the {} style formatting 

 correct?
 `String.Format("You are now {0} years old.", years - 1)`
You'd do it more like `String.Format(i"You are now ${{0}}(years - 1) years old.")` No backslashes. But it isn't really ideal for positional ones like that since you'd have to keep the count going right yourself. At this point you would ideally write an overload to String.Format that checks for the interpolation spec then translates. The DIP's text as submitted right now makes this unnecessarily difficult, so we're gonna reword it. The same implementation still works though.
I understand.
 3. The object.idup in the DIP uses `import std.format`, is it 
 permissible for the druntime to be dependent on Phobos?
Technically, druntime is still independent. Since it is a template, its dependency falls on the user, not the library. When you compile druntime, that code is completely ignored. It is not present in the compiled library and the import is not processed. If you use the idup function, the instance appears in *your* code and only then is Phobos actually imported. So formally, the dependency is on phobos from your code at the use point. So if you never use it, there's no dependency. This is one of D's coolest features to me btw.
I am understanding that this is technically possible, but I am still skeptical of this. Whether or not it is technically possible and whether or not it is permissible as a policy are two entirely different things. idup is part of the druntime. And idup uses std.format. In general, this would be considered druntime is dependent on std.format. It appears to be somewhat gray to claim that there is no dependency. I do not recommend doing anything gray.
 4. Are there any reasons why backquotes (i`...`) are not 
 allowed?
Trying to just define the simplest thing that can work. D has a lot of string types and adding i to each of them is a lot.... All these cases are possible with the juxtaposition thing though: i""`....` would work the same way.
If there is no particular negative reason, I think it would be a better DIP to include it. The way i""`....` is written seems redundant. Also, there is a history of concatenation when multiple string literals are written in succession, which has been previously deprecated. It seems to be a bad idea to adopt a similar method.
 5. Although you use the name idup, idup should be used to 
 create `immutable(_d_interpolated_string!Parts)`
There's two pieces to the interpolated tuple: the spec definition and the arguments. The _d_interpolated_string!Parts thing is just the spec definition. So your example is wrong: you left the arguments out. idup makes no sense without combining it.
Sorry, I was wrong. But my point is that converting to another type is the wrong feature of idup.
 The main reason for using idup over toString though is just 
 reusing an existing global name... it won't break any code 
 since it isn't introducing anything new. And since it already 
 works on string it has some precedent:

 char[] a;
 string b = a; // cannot convert, you need to idup it.

 string b = i"xxx"; // cannot convert, also need to idup it.
The following code will express my point better than above code: string b = "xxx"w.idup; // cannot implicitly convert expression idup("xxx"w) of type wstring to string string b = i"xxx".idup; // cannot implicitly convert expression idup(i"xxx") of type ?????? to string
Sep 12 2020
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 12 September 2020 at 09:06:00 UTC, SHOO wrote:
 And idup uses std.format.
We're thinking about dropping the format string part, which would immensely simplify this implementation to the point where there's no need for the import anymore. It also simplifies the syntax and the explanations. The cost is a bit less compatibility with existing functions, and if you do need to specify formatting, it would be done by functions instead of by strings. So like i"${%x}number" would have to be i"$(number.hex)" or something instead. There's some details to work out but it looks like a good direction right now.
Sep 12 2020
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
The DIP mentions a problem with DIP1027:

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

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

and the pid value inadvertently being matched to `width`. The DIP says:

   "Without a way to detect this misuse"

There is a way, as the expansion will be:

    createWindow(tuple("Process debugger %s", pid));

and the compiler can warn if a tuple argument precedes a default argument. I do 
not necessarily agree, however, that this is a problem that needs solving, just 
that there are ways.
Sep 12 2020
prev sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
Couldn't this be implemented entirely in library?
Sep 12 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 13 September 2020 at 03:00:34 UTC, Yuxuan Shui wrote:
 Couldn't this be implemented entirely in library?
Yes, but not with exactly the same syntax. The library version looks like this: writeln(mixin(i!"Hello $name!"));
Sep 13 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 13 September 2020 at 10:20:19 UTC, Paul Backus wrote:
 On Sunday, 13 September 2020 at 03:00:34 UTC, Yuxuan Shui wrote:
 Couldn't this be implemented entirely in library?
Yes, but not with exactly the same syntax. The library version looks like this: writeln(mixin(i!"Hello $name!"));
That's not the same. mixin cannot create tuples.
Sep 13 2020
parent reply Jackel <jackel894_394 gmail.com> writes:
On Sunday, 13 September 2020 at 13:03:23 UTC, Adam D. Ruppe wrote:
 On Sunday, 13 September 2020 at 10:20:19 UTC, Paul Backus wrote:
 On Sunday, 13 September 2020 at 03:00:34 UTC, Yuxuan Shui 
 wrote:
 Couldn't this be implemented entirely in library?
Yes, but not with exactly the same syntax. The library version looks like this: writeln(mixin(i!"Hello $name!"));
That's not the same. mixin cannot create tuples.
It potentially can, or at least wasn't that part of the rationale for deprecating the comma expression?
Sep 13 2020
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 13 September 2020 at 15:40:25 UTC, Jackel wrote:
 It potentially can, or at least wasn't that part of the 
 rationale for deprecating the comma expression?
Yeah, maybe some day (and actually this DIP as written would be a practical tuple literal, though the more recent drafts we're throwing around are not anymore), but right now there isn't. An AliasSeq comes close, but forces CTFE. A std.typecons.tuple comes close, but forces object member storage. A function parameter list might be closest but that's its own level of werid. But yeah, a non-string tuple literal is perhaps something to explore separately too.
Sep 13 2020