digitalmars.D - Discussion Thread: DIP 1036--Formatted String Tuple
- Mike Parker (21/21) Sep 08 2020 This is the discussion thread for the first round of Community
- Mike Parker (3/8) Sep 08 2020 The feedback thread is here:
- Avrina (28/28) Sep 08 2020 What's the purpose of toFormatString with a default spec? Why
- Steven Schveighoffer (29/57) Sep 08 2020 Because the default spec should not be constrained by the language (e.g....
- Avrina (41/105) Sep 08 2020 That doesn't answer the question. A type map to specifier would
- Adam D. Ruppe (2/4) Sep 08 2020 What would this look like?
- Avrina (4/8) Sep 09 2020 Don't have access to a computer ATM, not writing on a phone. I'll
- Steven Schveighoffer (51/125) Sep 09 2020 Sorry, I didn't read the full question. So yes, a type map would work.
- James Blachly (21/27) Sep 08 2020 I am really, really happy to see string interpolation coming to D, but I...
- James Blachly (7/7) Sep 08 2020 On 9/8/20 2:50 PM, James Blachly wrote:
- Steven Schveighoffer (45/91) Sep 08 2020 One thing to note here is that i"..." results not in a single thing, but...
- Paul Backus (7/10) Sep 08 2020 When a DIP has to devote an equal amount of space to justifying
- WebFreak001 (34/35) Sep 09 2020 I think it's a little bit awkward and risky that things like
- Adam D. Ruppe (10/16) Sep 09 2020 That would be a type mismatch error since i"..."'s first argument
- Steven Schveighoffer (20/61) Sep 09 2020 That won't compile. The interpolation spec type will not implicitly
- Paul Backus (73/128) Sep 09 2020 As per the rules, I'm responding here to Steven's post from the
- James Blachly (10/19) Sep 09 2020 This (and the related points about complexity and surprise especially of...
- Adam D. Ruppe (45/50) Sep 09 2020 Javascript is actually *very* similar to this dip, with the key
- Steven Schveighoffer (78/209) Sep 10 2020 I disagree completely. This DIP is on the right track. And I'm happy to
- Paul Backus (20/27) Sep 10 2020 Fair enough--that's your judgement call to make.
- aliak (9/38) Sep 11 2020 How about using Atila's nogc code [0] and just having `i"Hello
- Paul Backus (7/10) Sep 11 2020 The short answer is, I want to be able to write `mixin(i"...")`
- Adam D. Ruppe (45/46) Sep 11 2020 This right here is why the idup mechanism is how it is.
- 12345swordy (2/8) Sep 11 2020 You have a pull request that implement this then?
- Adam D. Ruppe (3/4) Sep 11 2020 No, but you can copy/paste the example implementation in the dip
- 12345swordy (3/7) Sep 11 2020 I think you have a better case if you have an PR showing what you
- Paul Backus (22/32) Sep 11 2020 If that's your acceptance criterion, it seems to me like my,
- Adam D. Ruppe (9/12) Sep 11 2020 Frankly, I hate the opaque thing too and it is going to change.
- Paul Backus (11/23) Sep 11 2020 Okay, here's my follow-up question:
- Adam D. Ruppe (14/16) Sep 11 2020 The complexity of the format spec may seem superfluous, however
- Paul Backus (17/30) Sep 11 2020 A much easier way to do this is to simply have no default format
- Adam D. Ruppe (49/56) Sep 11 2020 This is exactly what the DIP does!
- Paul Backus (15/23) Sep 11 2020 I guess you didn't have time to check out the video. What I mean
- Adam D. Ruppe (24/27) Sep 11 2020 yeah that's legit.
- claptrap (3/11) Sep 12 2020 Thats a step in the right direction IMO.
- Andrei Alexandrescu (20/34) Sep 12 2020 To me it seems akin to that moment you realize the practical joke has
- claptrap (31/70) Sep 13 2020 One more interpolated string ... one more brain ... more of
- Adam D. Ruppe (47/55) Sep 13 2020 Various forms of this have come up over the years.
- claptrap (12/24) Sep 15 2020 That's still not the same thing. These threads are full of
- Adam D. Ruppe (9/12) Sep 15 2020 There's only actually been two formal DIPs: Walter's and this
- Andrei Alexandrescu (2/5) Sep 12 2020 I am legitimately scared at this point.
- Adam D. Ruppe (13/14) Sep 12 2020 Posts like this add nothing of value to the conversation. You
- Andrei Alexandrescu (21/35) Sep 12 2020 The "why" is in subtext. Apologies if not obvious. It was along the
- Walter Bright (2/9) Sep 12 2020 I'll "heft a pint" to that!
- Steven Schveighoffer (5/17) Sep 13 2020 I suspect we shall be doing that in 2 weeks while discussing this DIP
- James Lu (13/42) Sep 12 2020 Too many features, too much syntax, increases mental overhead.
- Andrei Alexandrescu (4/54) Sep 12 2020 I think it's telling that now it's not only about adding two new tokens
- Adam D. Ruppe (15/17) Sep 12 2020 That's basically the C# solution.
- James Lu (4/20) Sep 13 2020 I don't know C# at all.
- Aliak (6/34) Sep 12 2020 Requiring to retype int semantically for every function that has
- Paul Backus (13/16) Sep 12 2020 Nobody is required to do anything. My point is, this kind of
- Andrei Alexandrescu (20/28) Sep 11 2020 Well it looks like that opaque thing should be the result of "tuple" and...
- Stefan Koch (3/5) Sep 11 2020 could be a compiler tuple which doesn't need std nor object.d.
- Andrei Alexandrescu (2/8) Sep 12 2020 Shouldn't because it needs to be expandable on demand, not implicitly.
- Paul Backus (21/26) Sep 12 2020 The only way I can think of to do this that works in the general
- Andrei Alexandrescu (8/39) Sep 12 2020 Affirmative. We have that already:
- Paul Backus (19/33) Sep 12 2020 There's a version in std.meta, though it's currently marked as
- claptrap (13/36) Sep 11 2020 The most critical part of global optimisation is making sure your
- Adam D. Ruppe (12/13) Sep 11 2020 I've personally answered ~18% of all D questions on Stack
- 12345swordy (11/15) Sep 11 2020 That issue that I have with your stance, is that we are dealing
- Paul Backus (10/20) Sep 11 2020 Yes, that's exactly what I'm asking. Note that this is something
- 12345swordy (3/17) Sep 11 2020 You conflicting standard library feature with built in language
- Paul Backus (6/14) Sep 11 2020 I don't understand the objection. Both `printf` and `writefln`
- 12345swordy (5/17) Sep 11 2020 You request people who maintain c/c++ binding libraries to put
- Paul Backus (10/14) Sep 11 2020 I request that library maintainers, *in general*, put in the
- 12345swordy (4/14) Sep 11 2020 Do you think that the d language should allow opimplicit
- Paul Backus (8/11) Sep 11 2020 I think the D language should give programmers the tools they
- 12345swordy (2/14) Sep 11 2020 That doesn't answer my question.
- Andrei Alexandrescu (14/165) Sep 10 2020 I quoted this in its entirety because I agree with it in its entirety.
- zoujiaqing (5/27) Sep 10 2020 Please support like this:
- Matheus (4/8) Sep 10 2020 Shouldn't a type like "i" in this example be automatically
- Matheus (5/18) Sep 10 2020 Forget... I just remembered that there was a thread about this,
- Steven Schveighoffer (3/10) Sep 10 2020 string b = i"test $i".idup;
- SHOO (28/28) Sep 11 2020 I'm eagerly awaiting the inclusion of this feature in the D
- Adam D. Ruppe (36/46) Sep 11 2020 You'd do it more like
- SHOO (24/73) Sep 12 2020 I am understanding that this is technically possible, but I am
- Adam D. Ruppe (12/13) Sep 12 2020 We're thinking about dropping the format string part, which would
- Walter Bright (10/10) Sep 12 2020 The DIP mentions a problem with DIP1027:
- Yuxuan Shui (1/1) Sep 12 2020 Couldn't this be implemented entirely in library?
- Paul Backus (4/5) Sep 13 2020 Yes, but not with exactly the same syntax. The library version
- Adam D. Ruppe (2/7) Sep 13 2020 That's not the same. mixin cannot create tuples.
- Jackel (3/13) Sep 13 2020 It potentially can, or at least wasn't that part of the rationale
- Adam D. Ruppe (9/11) Sep 13 2020 Yeah, maybe some day (and actually this DIP as written would be a
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
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
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
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
On Tuesday, 8 September 2020 at 13:32:10 UTC, Steven Schveighoffer wrote:On 9/8/20 8:10 AM, Avrina wrote: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.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 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 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 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.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?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.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.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 '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).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. -SteveIt'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
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
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:Don't have access to a computer ATM, not writing on a phone. I'll write it up when I can.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 09 2020
On 9/8/20 9:32 PM, Avrina wrote:On Tuesday, 8 September 2020 at 13:32:10 UTC, Steven Schveighoffer wrote: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.On 9/8/20 8:10 AM, Avrina wrote: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.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 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.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.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.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?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.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.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 '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 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.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.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. -SteveNote 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.
Sep 09 2020
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.mdI 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
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
On 9/8/20 2:50 PM, James Blachly wrote:On 9/8/20 6:59 AM, Mike Parker wrote: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.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.mdI 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: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.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.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
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.mdWhen 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
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
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
On 9/9/20 4:12 AM, WebFreak001 wrote:On Tuesday, 8 September 2020 at 10:59:31 UTC, Mike Parker wrote:That won't compile. The interpolation spec type will not implicitly convert to string.[...]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.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!".idupYou 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
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
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
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
On 9/9/20 5:41 PM, Paul Backus wrote:On Tuesday, 8 September 2020 at 10:59:31 UTC, Mike Parker wrote:I did not realize that was specifically in the rules! Sorry.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.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: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").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 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.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.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.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.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).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 admit that in the case where your call to printf would crash your program, we disallow compilation.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.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)?How about you tell me what the right thing is?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 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.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.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).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
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.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).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?
Sep 10 2020
On Thursday, 10 September 2020 at 20:50:24 UTC, Paul Backus wrote:On Thursday, 10 September 2020 at 18:45:02 UTC, Steven Schveighoffer wrote: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.dI 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.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).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?
Sep 11 2020
On Friday, 11 September 2020 at 09:01:31 UTC, aliak wrote:How about using Atila's nogc code [0] and just having `i"Hello $name!" lower to `text("Hello ", name, "!")` Works with both writeln, printf, and string assignment.The short answer is, I want to be able to write `mixin(i"...")` and have it work in BetterC. The long answer is something about design elegance, separation of concerns, etc. Anyway, I don't expect my idea to satisfy everyone equally. That's why it's my "personal vision," and not my "perfect solution to everyone's problems." :)
Sep 11 2020
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
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:You have a pull request that implement this then?[...]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: [...]
Sep 11 2020
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
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: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.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
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
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
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: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?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
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
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=47m15s3. 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
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
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: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.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.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
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
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:Thats a step in the right direction IMO.This solves the issue of accidentally passing the wrong thingAnd 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 12 2020
On 9/12/20 5:27 AM, claptrap wrote:On Saturday, 12 September 2020 at 02:48:38 UTC, Adam D. Ruppe wrote: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 subtletiesOn Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote:Thats a step in the right direction IMO.This solves the issue of accidentally passing the wrong thingAnd 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 12 2020
On Saturday, 12 September 2020 at 13:06:01 UTC, Andrei Alexandrescu wrote:On 9/12/20 5:27 AM, claptrap wrote: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.On Saturday, 12 September 2020 at 02:48:38 UTC, Adam D. Ruppe wrote: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.On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote:Thats a step in the right direction IMO.This solves the issue of accidentally passing the wrong thingAnd 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.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 subtletiesIm 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
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
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: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.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 15 2020
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
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
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
On 9/12/20 9:11 AM, Adam D. Ruppe wrote:On Saturday, 12 September 2020 at 12:40:21 UTC, Andrei Alexandrescu wrote: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."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 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
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
On 9/12/20 10:48 PM, Walter Bright wrote:On 9/12/2020 8:04 AM, Andrei Alexandrescu wrote:I suspect we shall be doing that in 2 weeks while discussing this DIP (hopefully updated)! #beerconfsept -SteveThere 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 13 2020
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: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.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 12 2020
On 9/12/20 10:37 AM, James Lu wrote:On Saturday, 12 September 2020 at 02:48:38 UTC, Adam D. Ruppe wrote: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?On Friday, 11 September 2020 at 20:46:05 UTC, Paul Backus wrote: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.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 12 2020
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
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:I have participated in Python language design discussions.[...]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 13 2020
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: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.On Friday, 11 September 2020 at 19:31:33 UTC, Paul Backus wrote: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);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.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
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
On 9/11/20 2:24 PM, Adam D. Ruppe wrote:On Friday, 11 September 2020 at 18:16:10 UTC, Paul Backus wrote: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.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
Sep 11 2020
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
On 9/11/20 5:36 PM, Stefan Koch wrote:On Friday, 11 September 2020 at 20:04:35 UTC, Andrei Alexandrescu wrote:Shouldn't because it needs to be expandable on demand, not implicitly.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 12 2020
On Saturday, 12 September 2020 at 12:37:14 UTC, Andrei Alexandrescu wrote:On 9/11/20 5:36 PM, Stefan Koch wrote: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.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
On 9/12/20 9:44 AM, Paul Backus wrote:On Saturday, 12 September 2020 at 12:37:14 UTC, Andrei Alexandrescu wrote: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.On 9/11/20 5:36 PM, Stefan Koch wrote: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; }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.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
On Saturday, 12 September 2020 at 14:47:47 UTC, Andrei Alexandrescu wrote:On 9/12/20 9:44 AM, Paul Backus wrote: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// 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.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
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: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?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.
Sep 11 2020
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
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
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: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.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.
Sep 11 2020
On Friday, 11 September 2020 at 13:46:52 UTC, Paul Backus wrote:On Friday, 11 September 2020 at 13:19:37 UTC, 12345swordy wrote:You conflicting standard library feature with built in language feature here, they are not the same.On Thursday, 10 September 2020 at 20:50:24 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.[...]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.
Sep 11 2020
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: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.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
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: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.On Friday, 11 September 2020 at 13:46:52 UTC, Paul Backus wrote:I don't understand the objection.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
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
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: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?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. :)
Sep 11 2020
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
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:That doesn't answer my question.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
On 9/9/20 5:41 PM, Paul Backus wrote:On Tuesday, 8 September 2020 at 10:59:31 UTC, Mike Parker wrote: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.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 10 2020
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
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 10Shouldn't a type like "i" in this example be automatically converted to string in cases like this? Matheus.
Sep 10 2020
On Thursday, 10 September 2020 at 18:40:03 UTC, Matheus wrote:On Thursday, 10 September 2020 at 18:30:26 UTC, zoujiaqing wrote: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.Please support like this: int i = 10; string b = "test " ~ i; writeln(b); // test 10Shouldn't a type like "i" in this example be automatically converted to string in cases like this? Matheus.
Sep 10 2020
On 9/10/20 2:30 PM, zoujiaqing wrote:Please support like this: int i = 10; string b = "test " ~ i; writeln(b); // test 10string b = i"test $i".idup; -Steve
Sep 10 2020
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
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
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:I understand.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 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.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.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.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.Sorry, I was wrong. But my point is that converting to another type is the wrong feature of idup.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.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
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
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
Couldn't this be implemented entirely in library?
Sep 12 2020
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
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:That's not the same. mixin cannot create tuples.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
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:It potentially can, or at least wasn't that part of the rationale for deprecating the comma expression?On Sunday, 13 September 2020 at 03:00:34 UTC, Yuxuan Shui wrote:That's not the same. mixin cannot create tuples.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
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