www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Just another example of missing string interpolation

reply Andrea Fontana <nospam example.org> writes:
Real life example. Render a string like this:

```
\x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 15.5 
KB/s
```

now (error prone and difficult to debug, try to code it!):


```
stderr.write(format("%s\r%sProgress:%s %5.1f%% %s\tSpeed:%s %6.1f 
%s%s", clear, white, clear, progress, white, clear, curSpeed, 
unit));
```

(or with string concat, good luck!)

vs:

```
stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
\t${white}Speed:${clear} ${curSpeed} ${unit}");
```

Andrea
Oct 12 2023
next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Thursday, 12 October 2023 at 13:39:46 UTC, Andrea Fontana 
wrote:
 Real life example. Render a string like this:

 ```
 \x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 
 15.5 KB/s
 ```

 now (error prone and difficult to debug, try to code it!):


 ```
 stderr.write(format("%s\r%sProgress:%s %5.1f%% %s\tSpeed:%s 
 %6.1f %s%s", clear, white, clear, progress, white, clear, 
 curSpeed, unit));
 ```

 (or with string concat, good luck!)

 vs:

 ```
 stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
 \t${white}Speed:${clear} ${curSpeed} ${unit}");
 ```

 Andrea
like the most used feature lol
Oct 12 2023
prev sibling next sibling parent reply bachmeier <no spam.net> writes:
On Thursday, 12 October 2023 at 13:39:46 UTC, Andrea Fontana 
wrote:
 Real life example. Render a string like this:

 ```
 \x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 
 15.5 KB/s
 ```

 now (error prone and difficult to debug, try to code it!):


 ```
 stderr.write(format("%s\r%sProgress:%s %5.1f%% %s\tSpeed:%s 
 %6.1f %s%s", clear, white, clear, progress, white, clear, 
 curSpeed, unit));
 ```

 (or with string concat, good luck!)

 vs:

 ```
 stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
 \t${white}Speed:${clear} ${curSpeed} ${unit}");
 ```

 Andrea
I agree that string interpolation needs to be added to the language (it's 2023) but for the benefit of an outsider reading your message, there are better options than calling `format`. I use a generalization of this: ``` string interp(string s, string[string] subs) { foreach(k; subs.keys) { s = s.replace("${" ~ k ~ "}", subs[k]); } return s; } ``` For your example, I'd call this ``` std.file.write("foo.txt", interp("${clear}2K\r${white}Progress:${clear}${progress}% \t${white}Speed:${clear} ${curSpeed} ${unit}", ["clear": "\x1b[", "white": "\x1b[1m", "progress": "0m 50", "curSpeed": "0m 15.5", "unit": "KB/s"])); ``` Would be much better to have this in the language, so I wouldn't have to specify all the substitutions, but a lot better than using `format` IMO.
Oct 12 2023
next sibling parent reply Commander Zot <no no.no> writes:
On Thursday, 12 October 2023 at 16:31:39 UTC, bachmeier wrote:
 On Thursday, 12 October 2023 at 13:39:46 UTC, Andrea Fontana 
 wrote:
 Real life example. Render a string like this:

 ```
 \x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 
 15.5 KB/s
 ```

 now (error prone and difficult to debug, try to code it!):


 ```
 stderr.write(format("%s\r%sProgress:%s %5.1f%% %s\tSpeed:%s 
 %6.1f %s%s", clear, white, clear, progress, white, clear, 
 curSpeed, unit));
 ```

 (or with string concat, good luck!)

 vs:

 ```
 stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
 \t${white}Speed:${clear} ${curSpeed} ${unit}");
 ```

 Andrea
I agree that string interpolation needs to be added to the language (it's 2023) but for the benefit of an outsider reading your message, there are better options than calling `format`. I use a generalization of this: ``` string interp(string s, string[string] subs) { foreach(k; subs.keys) { s = s.replace("${" ~ k ~ "}", subs[k]); } return s; } ``` For your example, I'd call this ``` std.file.write("foo.txt", interp("${clear}2K\r${white}Progress:${clear}${progress}% \t${white}Speed:${clear} ${curSpeed} ${unit}", ["clear": "\x1b[", "white": "\x1b[1m", "progress": "0m 50", "curSpeed": "0m 15.5", "unit": "KB/s"])); ``` Would be much better to have this in the language, so I wouldn't have to specify all the substitutions, but a lot better than using `format` IMO.
or like this: ``` string enableInterpolation() { return q{ string interp(string s)() { import std.algorithm; import std.meta; import std.array; import std.conv; import std.functional; enum spl = aliasSeqOf!(s.splitter(" ").array) ; template P(string e) { static if(e.startsWith("$")) { mixin("enum P = ()=>"~e[1..$]~".to!string;"); } else { string fn(){ return e;} enum P = &fn; } } return [staticMap!(P, spl)].map!(f=>f()).join(" "); } }; } int main() { import std.stdio; float speed = 42; mixin(enableInterpolation()); writeln(interp!"i has $speed !"); return 0; } ```
Oct 12 2023
next sibling parent bachmeier <no spam.net> writes:
On Thursday, 12 October 2023 at 17:25:09 UTC, Commander Zot wrote:

 or like this:

 ```
 string enableInterpolation() {
     return q{
         string interp(string s)() {
             import std.algorithm;
             import std.meta;
             import std.array;
             import std.conv;
             import std.functional;
             enum spl = aliasSeqOf!(s.splitter(" ").array) ;

             template P(string e) {
                 static if(e.startsWith("$")) {           			
                     mixin("enum P = 
 ()=>"~e[1..$]~".to!string;");
                 }
                 else {
                     string fn(){ return e;}
                     enum P = &fn;
                 }
             }

             return [staticMap!(P, spl)].map!(f=>f()).join(" ");

         }
     };
 }

 int main() {
     import std.stdio;

     float speed = 42;
     mixin(enableInterpolation());
     writeln(interp!"i has $speed !");

     return 0;
 }

 ```
I had something like that but moved away from it. The version I posted works better if I want to transform some of the variables. If I do that in a mixin, I have to parse the input. I actually do something like this using a struct: ``` string s = "String needing interpolation to insert ${y} and ${x}."; Subs subs; subs["y"] = str.split("/")[0]; subs["x"] = 2.6*j; interp(s, subs); ``` Again, though, this really should be done by the language rather than the user having to mess with it.
Oct 12 2023
prev sibling parent reply kdevel <kdevel vogtner.de> writes:
On Thursday, 12 October 2023 at 17:25:09 UTC, Commander Zot wrote:
 [...]
     writeln(interp!"i has $speed !");
What about ```d writeln(interp!"i has $speed,$speed !"); ``` ?
Oct 12 2023
parent Commander Zot <no no.no> writes:
On Thursday, 12 October 2023 at 19:56:48 UTC, kdevel wrote:
 On Thursday, 12 October 2023 at 17:25:09 UTC, Commander Zot 
 wrote:
 [...]
     writeln(interp!"i has $speed !");
What about ```d writeln(interp!"i has $speed,$speed !"); ``` ?
my code was just an example, you'd have to properly do the parsing of the string. but there are already packages on dub for that
Oct 13 2023
prev sibling parent reply kdevel <kdevel vogtner.de> writes:
On Thursday, 12 October 2023 at 16:31:39 UTC, bachmeier wrote:
 [...] I use a generalization of this:

 ```
 string interp(string s, string[string] subs) {
   foreach(k; subs.keys) {
     s = s.replace("${" ~ k ~ "}", subs[k]);
   }
   return s;
 }
 ```
What if `s` is `"${a}"` and `subs` is `["a": "${b}", "b": "x"]`?
Oct 12 2023
parent reply bachmeier <no spam.net> writes:
On Thursday, 12 October 2023 at 19:42:41 UTC, kdevel wrote:
 On Thursday, 12 October 2023 at 16:31:39 UTC, bachmeier wrote:
 [...] I use a generalization of this:

 ```
 string interp(string s, string[string] subs) {
   foreach(k; subs.keys) {
     s = s.replace("${" ~ k ~ "}", subs[k]);
   }
   return s;
 }
 ```
What if `s` is `"${a}"` and `subs` is `["a": "${b}", "b": "x"]`?
That's the reason it needs to be supported by the language. What I do in practice is replace `${` in `subs[k]` with `ControlChar.us`, then convert `ControlChar.us` to `$` before returning the final result. That's because I would never have `ControlChar.us` in a string with interpolation, and I don't have to worry about efficiency because it's just not an issue. Your example is something I don't have to worry about very often. This is in no way a solution that would be suitable for the compiler or Phobos. It's a hack that works for me.
Oct 12 2023
parent reply kdevel <kdevel vogtner.de> writes:
On Thursday, 12 October 2023 at 21:45:55 UTC, bachmeier wrote:
 [...]
 What if `s` is `"${a}"` and `subs` is `["a": "${b}", "b": 
 "x"]`?
That's the reason it needs to be supported by the language.
The problem with your code is that it loops over the wrong list. It should iterate over the variable occurrences in the string `s`. Granted that the language does support interpolation (DIP 1027): How would you implement your function string interp(string s, string[string] subs) in terms of that built-in interpolation?
Oct 13 2023
parent reply bachmeier <no spam.net> writes:
On Friday, 13 October 2023 at 12:04:18 UTC, kdevel wrote:
 On Thursday, 12 October 2023 at 21:45:55 UTC, bachmeier wrote:
 [...]
 What if `s` is `"${a}"` and `subs` is `["a": "${b}", "b": 
 "x"]`?
That's the reason it needs to be supported by the language.
The problem with your code is that it loops over the wrong list. It should iterate over the variable occurrences in the string `s`.
That depends. If you don't want to do all of the substitutions, either because you potentially have `${something}` as part of the final string, or because you don't want to do all substitutions at once, those cases are trivially handled by my function. It works for what I do.
Oct 13 2023
next sibling parent reply bachmeier <no spam.net> writes:
On Friday, 13 October 2023 at 14:25:34 UTC, bachmeier wrote:
 On Friday, 13 October 2023 at 12:04:18 UTC, kdevel wrote:
 On Thursday, 12 October 2023 at 21:45:55 UTC, bachmeier wrote:
 [...]
 What if `s` is `"${a}"` and `subs` is `["a": "${b}", "b": 
 "x"]`?
That's the reason it needs to be supported by the language.
The problem with your code is that it loops over the wrong list. It should iterate over the variable occurrences in the string `s`.
That depends. If you don't want to do all of the substitutions, either because you potentially have `${something}` as part of the final string, or because you don't want to do all substitutions at once, those cases are trivially handled by my function. It works for what I do.
An example of a pattern I sometimes use: ``` string foo(string s) { // Do a computation and substitute the result into s // return the new s } string bar(string s) { // Do a computation and substitute the result into s // return the new s } string s = "String needing interpolation to insert ${y} and ${x}."; string s2 = foo(s); string s3 = bar(s2); ```
Oct 13 2023
parent reply kdevel <kdevel vogtner.de> writes:
On Friday, 13 October 2023 at 14:31:01 UTC, bachmeier wrote:
 [...]
 An example of a pattern I sometimes use:

 ```
 string foo(string s) {
 // Do a computation and substitute the result into s
 // return the new s
 ```
At which position? Which pseudo-variable is substituted in `s`? Your functions `foo` and `bar` both not only make calls to `interp` but they also necessarily contain, in order to succeed, the name of the variable.
```
 }

 string bar(string s) {
 // Do a computation and substitute the result into s
 // return the new s
 }

 string s = "String needing interpolation to insert ${y} and 
 ${x}.";
 string s2 = foo(s);
 string s3 = bar(s2);
 ```
Your approach creates more dependencies between unrelated components than necessary. How do you unittest `foo` and `bar`? The dependencies can easily be avoided if `foo` and `bar` only returned the value of the computation, the results are stored in the AA given as `subs` in the call to `interp`.
Oct 13 2023
parent reply bachmeier <no spam.net> writes:
On Friday, 13 October 2023 at 15:34:59 UTC, kdevel wrote:

 Your functions `foo` and `bar` both not only make calls to 
 `interp` but they
 also necessarily contain, in order to succeed, the name of the 
 variable.
Yes
 Your approach creates more dependencies between unrelated 
 components than necessary.
Then don't use it? The goal of programming is to get the right output.
 How do you unittest `foo` and `bar`?
The same as any other function.
 The dependencies can easily be avoided if `foo` and `bar` only 
 returned the value of the computation, the results are stored 
 in the AA given as `subs` in the call to `interp`.
I prefer less complicated code to code that imposes arbitrary restrictions.
Oct 13 2023
parent kdevel <kdevel vogtner.de> writes:
On Friday, 13 October 2023 at 17:38:23 UTC, bachmeier wrote:
 On Friday, 13 October 2023 at 15:34:59 UTC, kdevel wrote:

 Your functions `foo` and `bar` both not only make calls to 
 `interp` but they
 also necessarily contain, in order to succeed, the name of the 
 variable.
Yes
But then you can't re-use `foo` with another string, e.g. "String needing interpolation to insert ${yold} and ${ynew}."
 Your approach creates more dependencies between unrelated 
 components than necessary.
Then don't use it? The goal of programming is to get the right output.
Your code does not meet that requirement.
 How do you unittest `foo` and `bar`?
The same as any other function.
Having the signature of `foo` and `bar` alone I am not able to write a unittest.
 The dependencies can easily be avoided if `foo` and `bar` only 
 returned the value of the computation, the results are stored 
 in the AA given as `subs` in the call to `interp`.
I prefer less complicated code to code that imposes arbitrary restrictions.
In your code of `foo` and `bar` you have to assemble the AA and call `interp` twice compared to once. I would call my approach less complicated and my `foo` and `bar` versions do not suffer from the arbitrary restriction of beeing applicable only to strings having a predefined variable name.
Oct 13 2023
prev sibling parent reply kdevel <kdevel vogtner.de> writes:
On Friday, 13 October 2023 at 14:25:34 UTC, bachmeier wrote:
 On Friday, 13 October 2023 at 12:04:18 UTC, kdevel wrote:
 On Thursday, 12 October 2023 at 21:45:55 UTC, bachmeier wrote:
 [...]
 What if `s` is `"${a}"` and `subs` is `["a": "${b}", "b": 
 "x"]`?
That's the reason it needs to be supported by the language.
The problem with your code is that it loops over the wrong list. It should iterate over the variable occurrences in the string `s`.
That depends. If you don't want to do all of the substitutions,
You don't have to do all substitutions in one go. If a key is missing in `subs` one alternative to throwing `MissingKey` could be to silently skip that variable occurrence.
 either because you potentially have `${something}` as part of 
 the final string,
How do you convey that intent inside the string? `format` does it by estabilishing a special syntax for `%` (`%%` -> `%`). How do you handle that case with DIP 1027? And reminder: How do you implement your `interp` function in terms of DIP 1027's string interpolation?
Oct 13 2023
parent reply bachmeier <no spam.net> writes:
On Friday, 13 October 2023 at 15:16:27 UTC, kdevel wrote:

 either because you potentially have `${something}` as part of 
 the final string,
How do you convey that intent inside the string? `format` does it by estabilishing a special syntax for `%` (`%%` -> `%`).
I don't need to.
 How do you handle that case with DIP 1027?

 And reminder: How do you implement your `interp` function in 
 terms of
 DIP 1027's string interpolation?
I don't know, but I also don't know why I would want to, because DIP 1027 was not accepted.
Oct 13 2023
next sibling parent kdevel <kdevel vogtner.de> writes:
On Friday, 13 October 2023 at 17:31:29 UTC, bachmeier wrote:
 And reminder: How do you implement your `interp` function in 
 terms of
 DIP 1027's string interpolation?
I don't know, but I also don't know why I would want to, because DIP 1027 was not accepted.
Maybe I misunderstood you in "Again, though, this really should be done by the language rather than the user having to mess with it."
Oct 13 2023
prev sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Friday, 13 October 2023 at 17:31:29 UTC, bachmeier wrote:
 I don't know, but I also don't know why I would want to, 
 because DIP 1027 was not accepted.
dip 1027 was utter trash, but there's future good dips that would easily solve these things. pity D's leadership is so clueless and obstinate.
Oct 13 2023
next sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 13 October 2023 at 18:24:08 UTC, Adam D Ruppe wrote:
 On Friday, 13 October 2023 at 17:31:29 UTC, bachmeier wrote:
 I don't know, but I also don't know why I would want to, 
 because DIP 1027 was not accepted.
dip 1027 was utter trash, but there's future good dips that would easily solve these things. pity D's leadership is so clueless and obstinate.
We just want to be able to do string s = "Hello {name}, you are {age} years old and have {money - 42} dollars in the bank"; Is it too much to ask? 😭
Oct 13 2023
next sibling parent reply Commander Zot <no no.no> writes:
On Saturday, 14 October 2023 at 06:25:15 UTC, Imperatorn wrote:
 On Friday, 13 October 2023 at 18:24:08 UTC, Adam D Ruppe wrote:
 On Friday, 13 October 2023 at 17:31:29 UTC, bachmeier wrote:
 I don't know, but I also don't know why I would want to, 
 because DIP 1027 was not accepted.
dip 1027 was utter trash, but there's future good dips that would easily solve these things. pity D's leadership is so clueless and obstinate.
We just want to be able to do string s = "Hello {name}, you are {age} years old and have {money - 42} dollars in the bank"; Is it too much to ask? 😭
yes. this would break existing code.
Oct 14 2023
parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Saturday, 14 October 2023 at 11:31:53 UTC, Commander Zot wrote:
 On Saturday, 14 October 2023 at 06:25:15 UTC, Imperatorn wrote:
 On Friday, 13 October 2023 at 18:24:08 UTC, Adam D Ruppe wrote:
 On Friday, 13 October 2023 at 17:31:29 UTC, bachmeier wrote:
 I don't know, but I also don't know why I would want to, 
 because DIP 1027 was not accepted.
dip 1027 was utter trash, but there's future good dips that would easily solve these things. pity D's leadership is so clueless and obstinate.
We just want to be able to do string s = "Hello {name}, you are {age} years old and have {money - 42} dollars in the bank"; Is it too much to ask? 😭
yes. this would break existing code.
Oct 14 2023
prev sibling parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Saturday, 14 October 2023 at 06:25:15 UTC, Imperatorn wrote:
 On Friday, 13 October 2023 at 18:24:08 UTC, Adam D Ruppe wrote:
 On Friday, 13 October 2023 at 17:31:29 UTC, bachmeier wrote:
 I don't know, but I also don't know why I would want to, 
 because DIP 1027 was not accepted.
dip 1027 was utter trash, but there's future good dips that would easily solve these things. pity D's leadership is so clueless and obstinate.
We just want to be able to do string s = "Hello {name}, you are {age} years old and have {money - 42} dollars in the bank"; Is it too much to ask? 😭
Why does not this work for you? ```d string s = text("Hello ",name,", you are ",age," years old and have ",money - 42," dollars in the bank"); ```
Oct 14 2023
next sibling parent mw <mw g.c> writes:
On Saturday, 14 October 2023 at 14:47:26 UTC, Andrey Zherikov 
wrote:
 On Saturday, 14 October 2023 at 06:25:15 UTC, Imperatorn wrote:
 On Friday, 13 October 2023 at 18:24:08 UTC, Adam D Ruppe wrote:
 On Friday, 13 October 2023 at 17:31:29 UTC, bachmeier wrote:
 I don't know, but I also don't know why I would want to, 
 because DIP 1027 was not accepted.
dip 1027 was utter trash, but there's future good dips that would easily solve these things. pity D's leadership is so clueless and obstinate.
We just want to be able to do string s = "Hello {name}, you are {age} years old and have {money - 42} dollars in the bank"; Is it too much to ask? 😭
Why does not this work for you? ```d string s = text("Hello ",name,", you are ",age," years old and have ",money - 42," dollars in the bank"); ```
Too many unnecessary quotes and commas, tedious to write and read. And for debug purpose I also want to print the variable names ... string interpolation is nothing fancy, but just syntax sugar to make the life easier. People have been asking it for years, but still not available. So, why not just do it?
Oct 14 2023
prev sibling next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Saturday, 14 October 2023 at 14:47:26 UTC, Andrey Zherikov 
wrote:
 On Saturday, 14 October 2023 at 06:25:15 UTC, Imperatorn wrote:
 On Friday, 13 October 2023 at 18:24:08 UTC, Adam D Ruppe wrote:
 On Friday, 13 October 2023 at 17:31:29 UTC, bachmeier wrote:
 I don't know, but I also don't know why I would want to, 
 because DIP 1027 was not accepted.
dip 1027 was utter trash, but there's future good dips that would easily solve these things. pity D's leadership is so clueless and obstinate.
We just want to be able to do string s = "Hello {name}, you are {age} years old and have {money - 42} dollars in the bank"; Is it too much to ask? 😭
Why does not this work for you? ```d string s = text("Hello ",name,", you are ",age," years old and have ",money - 42," dollars in the bank"); ```
Oct 14 2023
prev sibling next sibling parent bachmeier <no spam.net> writes:
On Saturday, 14 October 2023 at 14:47:26 UTC, Andrey Zherikov 
wrote:

 Why does not this work for you?
 ```d
 string s = text("Hello ",name,", you are ",age," years old and 
 have ",money - 42," dollars in the bank");
 ```
We had a discussion on this a few years ago where someone said the same thing, but they had a missing space, and it wasn't immediately obvious. I'll sometimes create strings that are fed to the shell. Keeping the quoting straight is not the highlight of your day. That was probably the reason I rolled my own solution. `text` works for some things, but I find other approaches easier on the brain cells. I don't mind typing a few extra characters. I want to write it once and know I never have to think about it again.
Oct 14 2023
prev sibling parent reply Andrea Fontana <nospam example.org> writes:
On Saturday, 14 October 2023 at 14:47:26 UTC, Andrey Zherikov 
wrote:
 Why does not this work for you?
 ```d
 string s = text("Hello ",name,", you are ",age," years old and 
 have ",money - 42," dollars in the bank");
 ```
Check the first post.
Oct 14 2023
parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Saturday, 14 October 2023 at 20:05:42 UTC, Andrea Fontana 
wrote:
 On Saturday, 14 October 2023 at 14:47:26 UTC, Andrey Zherikov 
 wrote:
 Why does not this work for you?
 ```d
 string s = text("Hello ",name,", you are ",age," years old and 
 have ",money - 42," dollars in the bank");
 ```
Check the first post.
I would actually be fine with smith like interp!"Hello {name}, your name is {name} and you have {money -42} dollars in the bank" until he have a character to use for it
Oct 15 2023
parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Sunday, 15 October 2023 at 07:10:06 UTC, Imperatorn wrote:
 On Saturday, 14 October 2023 at 20:05:42 UTC, Andrea Fontana 
 wrote:
 On Saturday, 14 October 2023 at 14:47:26 UTC, Andrey Zherikov 
 wrote:
 Why does not this work for you?
 ```d
 string s = text("Hello ",name,", you are ",age," years old 
 and have ",money - 42," dollars in the bank");
 ```
Check the first post.
I would actually be fine with smith like interp!"Hello {name}, your name is {name} and you have {money -42} dollars in the bank" until he have a character to use for it
Typo but you get the point 😅
Oct 15 2023
parent reply Andrea Fontana <nospam example.org> writes:
On Sunday, 15 October 2023 at 07:10:39 UTC, Imperatorn wrote:
 On Sunday, 15 October 2023 at 07:10:06 UTC, Imperatorn wrote:
 On Saturday, 14 October 2023 at 20:05:42 UTC, Andrea Fontana 
 wrote:
 On Saturday, 14 October 2023 at 14:47:26 UTC, Andrey Zherikov 
 wrote:
 Why does not this work for you?
 ```d
 string s = text("Hello ",name,", you are ",age," years old 
 and have ",money - 42," dollars in the bank");
 ```
Check the first post.
I would actually be fine with smith like interp!"Hello {name}, your name is {name} and you have {money -42} dollars in the bank" until he have a character to use for it
Typo but you get the point 😅
Yes these versions are fine too i"hello ${world+1} $another_var" or: """hello ${word+1} $another_var""" or: $"hello ${world+1} $another_var" or: "hello %{world+1} %another_var"! or whatever enables string interpolation :)
Oct 15 2023
parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Sunday, 15 October 2023 at 08:18:04 UTC, Andrea Fontana wrote:
 On Sunday, 15 October 2023 at 07:10:39 UTC, Imperatorn wrote:
 On Sunday, 15 October 2023 at 07:10:06 UTC, Imperatorn wrote:
 On Saturday, 14 October 2023 at 20:05:42 UTC, Andrea Fontana 
 wrote:
 On Saturday, 14 October 2023 at 14:47:26 UTC, Andrey 
 Zherikov wrote:
 [...]
Check the first post.
I would actually be fine with smith like interp!"Hello {name}, your name is {name} and you have {money -42} dollars in the bank" until he have a character to use for it
Typo but you get the point 😅
Yes these versions are fine too i"hello ${world+1} $another_var" or: """hello ${word+1} $another_var""" or: $"hello ${world+1} $another_var" or: "hello %{world+1} %another_var"! or whatever enables string interpolation :)
Agreed!
Oct 15 2023
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/13/2023 11:24 AM, Adam D Ruppe wrote:
 pity D's leadership is so clueless and obstinate.
Criticize ideas, not people. Personal attacks are not welcome here.
Oct 17 2023
prev sibling next sibling parent reply mw <m g.c> writes:
On Thursday, 12 October 2023 at 13:39:46 UTC, Andrea Fontana 
wrote:
 Real life example. Render a string like this:

 ```
 \x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 
 15.5 KB/s
 ```

 now (error prone and difficult to debug, try to code it!):


 ```
 stderr.write(format("%s\r%sProgress:%s %5.1f%% %s\tSpeed:%s 
 %6.1f %s%s", clear, white, clear, progress, white, clear, 
 curSpeed, unit));
 ```

 (or with string concat, good luck!)

 vs:

 ```
 stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
 \t${white}Speed:${clear} ${curSpeed} ${unit}");
 ```
There are library solutions, e.g shameless self-plug: https://code.dlang.org/packages/jdiutil ``` writeln(mixin(_S!"with var name: {i; d; thePoint}")); ``` output: ``` with var name: i=100 d=1.23457 thePoint=app.Point(_x=3 _y=0.456 _label=default value _counter=0) ```
Oct 12 2023
parent mw <m g.c> writes:
On Thursday, 12 October 2023 at 17:56:29 UTC, mw wrote:
 On Thursday, 12 October 2023 at 13:39:46 UTC, Andrea Fontana 
 wrote:
 Real life example. Render a string like this:

 ```
 \x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 
 15.5 KB/s
 ```

 now (error prone and difficult to debug, try to code it!):


 ```
 stderr.write(format("%s\r%sProgress:%s %5.1f%% %s\tSpeed:%s 
 %6.1f %s%s", clear, white, clear, progress, white, clear, 
 curSpeed, unit));
 ```

 (or with string concat, good luck!)

 vs:

 ```
 stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
 \t${white}Speed:${clear} ${curSpeed} ${unit}");
 ```
There are library solutions, e.g shameless self-plug: https://code.dlang.org/packages/jdiutil ``` writeln(mixin(_S!"with var name: {i; d; thePoint}")); ``` output: ``` with var name: i=100 d=1.23457 thePoint=app.Point(_x=3 _y=0.456 _label=default value _counter=0) ```
The package is called: Just-Do-It Because things like this have been talked about so long ,and so many times (and even so many previous DIPs), but nothing materialized. So, I decided Just-Do-It!
Oct 12 2023
prev sibling next sibling parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Thursday, 12 October 2023 at 13:39:46 UTC, Andrea Fontana 
wrote:
 Real life example. Render a string like this:

 ```
 \x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 
 15.5 KB/s
 ```

 now (error prone and difficult to debug, try to code it!):


 ```
 stderr.write(format("%s\r%sProgress:%s %5.1f%% %s\tSpeed:%s 
 %6.1f %s%s", clear, white, clear, progress, white, clear, 
 curSpeed, unit));
 ```

 (or with string concat, good luck!)

 vs:

 ```
 stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
 \t${white}Speed:${clear} ${curSpeed} ${unit}");
 ```

 Andrea
If you are using `write*` then you can simply do this: ```d stderr.write(clear,"\r",white,"Progress:",clear," ",progress,"% ",white,"\tSpeed:",clear," ",curSpeed," ",unit); ``` If you want just to get a string - use `text`: ```d stderr.write(text(clear,"\r",white,"Progress:",clear," ",progress,"% ",white,"\tSpeed:",clear," ",curSpeed," ",unit)); ``` The result is the same so IMHO `text` is good alternative to string interpolation. You can also wrap styling into functions to make code more readable: ```d string white(A...)(A args) { return text("\x1b[1m", args, "\x1b[0m"); } stderr.write(clear,"\r",white("Progress: "),progress,"% \t",white("Speed: "),curSpeed," ",unit); ```
Oct 12 2023
prev sibling next sibling parent kdevel <kdevel vogtner.de> writes:
On Thursday, 12 October 2023 at 13:39:46 UTC, Andrea Fontana 
wrote:
 Real life example. Render a string like this:

 ```
 \x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 
 15.5 KB/s
 ```

 now (error prone and difficult to debug, try to code it!):
Where is the specific problem? ``` import std.stdio; int main (string [] args) { enum fmt = "\x1b[2K\r\x1b[1mProgress:\x1b[0m %s%% \x1b[1m\tSpeed:\x1b[0m > %s KB/s"; writeln (fmt); writefln!fmt (75, 11.11); return 0; } $ ./prgs Progress: %s%% Speed: > %s KB/s Progress: 75% Speed: > 11.11 KB/s ``` The words `Progress` and `Speed` appear highlighted in my console.
Oct 13 2023
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md
Oct 17 2023
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/12/2023 6:39 AM, Andrea Fontana wrote:
 ```
 stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
 \t${white}Speed:${clear} ${curSpeed} ${unit}");
 ```
With DIP1027: ``` stderr.write("$clear\r$(white)Progress:$clear$progress% \t$(white)Speed:$clear $curSpeed $unit"); ``` If it's a simple identifier, the { } are not necessary. https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md#description
Oct 17 2023
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 10:24 AM, Walter Bright wrote:
 ```
 stderr.write("$clear\r$(white)Progress:$clear$progress%
 \t$(white)Speed:$clear $curSpeed $unit");
 ```
Oops, forgot the leading 'i': ``` stderr.write(i"$clear\r$(white)Progress:$clear$progress% \t$(white)Speed:$clear $curSpeed $unit"); ```
Oct 17 2023
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 17 October 2023 at 17:27:41 UTC, Walter Bright wrote:
 Oops, forgot the leading 'i':

 ```
 stderr.write(i"$clear\r$(white)Progress:$clear$progress%
 \t$(white)Speed:$clear $curSpeed $unit");
 ```
Still won't work. Your dip1027 would write %s\r%sProgress:%s%s%\t%sSpeed:%s %s %s\e[09m\e01m5\[30m\0[09m5bytes/sec if you used it like that. This is one of the reasons why it was rejected. If we want to move forward, there's actually a good proposal out there: https://github.com/John-Colvin/YAIDIP
Oct 17 2023
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 10:37 AM, Adam D Ruppe wrote:
 On Tuesday, 17 October 2023 at 17:27:41 UTC, Walter Bright wrote:
 Oops, forgot the leading 'i':

 ```
 stderr.write(i"$clear\r$(white)Progress:$clear$progress%
 \t$(white)Speed:$clear $curSpeed $unit");
 ```
Still won't work. Your dip1027 would write %s\r%sProgress:%s%s%\t%sSpeed:%s %s %s\e[09m\e01m5\[30m\0[09m5bytes/sec if you used it like that.
That's a misunderstanding of how it works.
Oct 17 2023
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 17 October 2023 at 19:03:48 UTC, Walter Bright wrote:
 That's a misunderstanding of how it works.
No, that's exactly how it works. Read the document: writefln(i"I ate $apples and ${%d}bananas totalling $(apples + bananas) fruit."); gets rewritten as: writefln("I ate %s and %d totalling %s fruit.", apples, bananas, apples + bananas); And read the post above, which uses *write*, not write*f*. Think about the implications of that for a second.
Oct 17 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 12:20 PM, Adam D Ruppe wrote:
 And read the post above, which uses *write*, not write*f*. Think about the 
 implications of that for a second.
Yes, it means I forgot to use writef instead of write.
Oct 17 2023
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 17 October 2023 at 20:05:59 UTC, Walter Bright wrote:
 On 10/17/2023 12:20 PM, Adam D Ruppe wrote:
 And read the post above, which uses *write*, not write*f*. 
 Think about the implications of that for a second.
Yes, it means I forgot to use writef instead of write.
Your version left off the format specifiers, but I don't think that's all that significant.
Oct 17 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 1:23 PM, jmh530 wrote:
 Yes, it means I forgot to use writef instead of write.
Your version left off the format specifiers, but I don't think that's all that significant.
The %s format specifiers are inserted by default.
Oct 17 2023
prev sibling next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 17 October 2023 at 20:05:59 UTC, Walter Bright wrote:
 Yes, it means I forgot to use writef instead of write.
And the compiler wouldn't have told you about this. This is one of the (several) reasons why the dip was rejected. and Javascript both have much better facilities.
Oct 17 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 1:44 PM, Adam D Ruppe wrote:
 On Tuesday, 17 October 2023 at 20:05:59 UTC, Walter Bright wrote:
 Yes, it means I forgot to use writef instead of write.
And the compiler wouldn't have told you about this.
Neither would YAIDIP. write() takes a variadic argument list. YAIDIP also requires the correct version of user-defined InterpolationHeader to be the one in scope. It's not immediately clear what would happen if the wrong one was in scope.
Oct 17 2023
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 18 October 2023 at 00:27:16 UTC, Walter Bright 
wrote:
 Neither would YAIDIP. write() takes a variadic argument list.
Which is irrelevant because it *works correctly* when passed to write(), so there's no need for the compiler to say anything.
 YAIDIP also requires the correct version of user-defined 
 InterpolationHeader to be the one in scope.
The text of the yaidip doesn't specify this, but this is utterly trivial to solve; the dip 1036 specified a fully qualified name for it and this one could too.
Oct 17 2023
next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 18 October 2023 at 00:45:40 UTC, Adam D Ruppe wrote:
 The text of the yaidip doesn't specify this
Actually, looking again, it states: "Every i-string lowering introduces a header rvalue object that so far we conventionally denoted as __header (the exact name is uniquely compiler-generated and hence inaccessible)." so this may not matter anyway, nevertheless, I just did the 30 second find+replace of the abbreviated name with the fully qualified name to concretely specify this. Refresh the page.
Oct 17 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 6:07 PM, Adam D Ruppe wrote:
 On Wednesday, 18 October 2023 at 00:45:40 UTC, Adam D Ruppe wrote:
 The text of the yaidip doesn't specify this
Actually, looking again, it states: "Every i-string lowering introduces a header rvalue object that so far we conventionally denoted as __header (the exact name is uniquely compiler-generated and hence inaccessible)." so this may not matter anyway, nevertheless, I  just did the 30 second find+replace of the abbreviated name with the fully qualified name to concretely specify this. Refresh the page.
How does the user specify the fully-qualified name of a compiler generated object?
Oct 17 2023
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 5:45 PM, Adam D Ruppe wrote:
 On Wednesday, 18 October 2023 at 00:27:16 UTC, Walter Bright wrote:
 Neither would YAIDIP. write() takes a variadic argument list.
Which is irrelevant because it *works correctly* when passed to write(), so there's no need for the compiler to say anything.
I don't see how, from my reading of the proposal. It doesn't matter that much if write() does not give a compile time error, as this is normal and accepted for variadic functions. But as you've characterized it as a fatal error, the YAIDIP spec should be improved to address it.
 YAIDIP also requires the correct version of user-defined InterpolationHeader 
 to be the one in scope.
The text of the yaidip doesn't specify this, but this is utterly trivial to solve; the dip 1036 specified a fully qualified name for it and this one could too.
If it's trivial, then please fix the proposal. BTW, it's normal to uncover errors like this in a proposal for a new feature.
Oct 17 2023
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 18 October 2023 at 02:19:21 UTC, Walter Bright 
wrote:
 I don't see how, from my reading of the proposal.
The first example under the Description shows this exact situation and then goes on to explain how and why it works as expected.
 But as you've characterized it as a fatal error, the YAIDIP 
 spec should be improved to address it.
It is a fatal error for YOUR (rejected) dip 1027, as it silently leads to wrong results in common cases. This was all explained in detail in the review process four years ago. Things work correctly with this proposal, you either get the expected results or a compiler error, as a natural consequence of the existing type system. Nothing needs to be spelled out about this as there are not any special cases.
 If it's trivial, then please fix the proposal.
Already did, over an hour ago. It took about 30 seconds to specify. This isn't a big deal. (And btw, even if it didn't specify, the behavior is well-defined in the D Programming Language, and such things are already similar in other places, including other existing compiler hooks, see _d_cmain <http://dpldocs.info/this-week-in-d/Blog.Posted_2022_07_18.html>. But now the text does specify the fully qualified name anyway, so this is all moot.
Oct 17 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 7:39 PM, Adam D Ruppe wrote:
 On Wednesday, 18 October 2023 at 02:19:21 UTC, Walter Bright wrote:
 I don't see how, from my reading of the proposal.
The first example under the Description shows this exact situation and then goes on to explain how and why it works as expected.
The line in question: ``` writeln(__header, "I ate ", apples, " apples and ", bananas, " bananas totalling ", apples + bananas, " fruit.") ``` What does writeln() do with __header?
 Things work correctly with this proposal, you either get the expected results
or 
 a compiler error, as a natural consequence of the existing type system.
Nothing 
 needs to be spelled out about this as there are not any special cases.
Does that mean writeln() gets rewritten to handle __header? If so, ok, but the YAIDIP doesn't say that. Today, the only difference between writef() and write() is the former takes the first argument as the format string. Is this a fatal error? I suppose you could consider it as one, but that's an issue typical with variadic functions.
 Already did, over an hour ago.
Ok, I saw it after I posted that.
 It took about 30 seconds to specify. This isn't a 
 big deal. (And btw, even if it didn't specify, the behavior is well-defined in 
 the D Programming Language, and such things are already similar in other
places, 
 including other existing compiler hooks, see _d_cmain 
 <http://dpldocs.info/this-week-in-d/Blog.Posted_2022_07_18.html>.
 
 But now the text does specify the fully qualified name anyway, so this is all
moot.
I think we're misunderstanding each other. What I am asking about is how does the user specify his own custom implementation of InterpolatedExpression?
Oct 17 2023
next sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 18 October 2023 at 03:57:52 UTC, Walter Bright 
wrote:
 The line in question:

 ```
 writeln(__header, "I ate ", apples, " apples and ", bananas, " 
 bananas totalling ", apples + bananas, " fruit.")
 ```

 What does writeln() do with __header?
__header is implicitly converted to null string by writeln (the struct will have a toString method that returns null), so from the point of view of existing text methods such as writeln, text, everything is fine.
 Does that mean writeln() gets rewritten to handle __header? If 
 so, ok, but the YAIDIP doesn't say that.

 Today, the only difference between writef() and write() is the 
 former takes the first argument as the format string. Is this a 
 fatal error? I suppose you could consider it as one, but that's 
 an issue typical with variadic functions.
It's a pain to parse it (DIP 1027) when you'd like to define your own function accepting interpolated strings, compared to suggested DIP.
 Already did, over an hour ago.
Ok, I saw it after I posted that.
 It took about 30 seconds to specify. This isn't a big deal.
I think we're misunderstanding each other. What I am asking about is how does the user specify his own custom implementation of InterpolatedExpression?
I think the assumption is that __header type is passed as template argument, then there are no issues with voldemort types. If you really like to specify type not through template argument, I guess DIP could be enhanced saying that __header could implicitly convert to a predefined struct, i.e. RuntimeStoredInterpolationInfo. Best regards, Alexandru.
Oct 18 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/18/2023 12:53 AM, Alexandru Ermicioi wrote:
 __header is implicitly converted to null string by writeln (the struct will
have 
 a toString method that returns null), so from the point of view of existing
text 
 methods such as writeln, text, everything is fine.
Ok. So does the user have to define his own InterpolatedExpression to get something different to happen?
Oct 18 2023
prev sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 18 October 2023 at 03:57:52 UTC, Walter Bright 
wrote:
 What does writeln() do with __header?
"The __header value, to be discussed later, is generated by the compiler and contains compile-time information about the interpolated string." <a few moments later> "The header object has a trivial toString method that expands to the null string. This method makes it possible to pass interpolated strings directly to functions such as writeln and text because these functions detect and use toString to convert unknown data types to strings." It just uses the existing rules for a struct. No special case here. It doesn't spell this out, but you can think about what happens to normal D functions if you pass some `struct` to a function expecting a `string` - an ordinary type mismatch error. This is what gives library authors such power with this proposal: they can overload a function to provided specialized behavior. Which brings me to:
 I think we're misunderstanding each other. What I am asking 
 about is how does the user specify his own custom 
 implementation of InterpolatedExpression?
There's no need. You just pass it to a function. Library authors overload functions on the type of what was passed, including an interpolated type if desired, same as any other overload. End users call a particular function uses the given arguments to create their desired result; a generic function forwarder still works, preserving the full interpolated argument, since it works like any other set of function arguments. This gives *enormous* capability to both sides - mostly by using already existing features in the D language.
Oct 18 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/18/2023 1:27 PM, Adam D Ruppe wrote:
 On Wednesday, 18 October 2023 at 03:57:52 UTC, Walter Bright wrote:
 What does writeln() do with __header?
"The __header value, to be discussed later, is generated by the compiler and contains compile-time information about the interpolated string." <a few moments later> "The header object has a trivial toString method that expands to the null string. This method makes it possible to pass interpolated strings directly to functions such as writeln and text because these functions detect and use toString to convert unknown data types to strings." It just uses the existing rules for a struct. No special case here. It doesn't spell this out, but you can think about what happens to normal D functions if you pass some `struct` to a function expecting a `string` - an ordinary type mismatch error. This is what gives library authors such power with this proposal: they can overload a function to provided specialized behavior.
Ok. The lowering to arguments to InterpolatedExpression seem to all be string versions of the argument identifiers, rather than what the types are. "the header gives the callee complete access to the strings corresponding to the expressions passed in." I don't know what that is useful for. Note that if write() is a template, it already has access to all the arguments and their types.
 Library authors overload functions on the type of what was passed, including
an 
 interpolated type if desired, same as any other overload. End users call a 
 particular function uses the given arguments to create their desired result; a 
 generic function forwarder still works, preserving the full interpolated 
 argument, since it works like any other set of function arguments.
 
 This gives *enormous* capability to both sides - mostly by using already 
 existing features in the D language.
I'd like to see an example of code of how this customization might work, because I don't see it. P.S. there are several errors in the document, such as '$' appearing in the lowered code. What "normalization" means is unclear.
Oct 18 2023
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 19 October 2023 at 00:57:35 UTC, Walter Bright wrote:
 The lowering to arguments to InterpolatedExpression seem to all 
 be string versions of the argument identifiers, rather than 
 what the types are.
The types are attached to the parameters themselves, so it is purely redundant to list them again. The interpolated header's job is to preserve the original string, allowing for compile time manipulation of it. The arguments are processed the same as any other `T...` tuple in D.
 "the header gives the callee complete access to the strings 
 corresponding to the expressions passed in."

 I don't know what that is useful for. Note that if write() is a 
 template, it already has access to all the arguments and their 
 types.
The strings are not the types. The compiler has this information, the user wrote it, even if you don't see the value, why discard it? But here's one example: this year's DConf had a talk on gnu gettext. In current D code, they use a template argument string to make a user-defined literal which is collected into the translation files. This is pretty cool. But it loses some information, comments are added by hand: tr!("One license.", "%d licenses.", Context(“driver's"))(n); With the interpolation header, it could quite plausibly be: tr(i"One license.", i"$(driversLicenseCount) licenses."); (i renamed the variable there because it is now meaningful so you can). The full string written in the source - i"$(driversLicenseCount) licenses." - is available for inspection. The tr function can even extract that variable name and automatically add it as a comment to the translator, giving them the additional context without needing to write it again in the code. It also potentially opens up library implementations of something like assert with checkaction=context, showing the original code that led to the result. Please note that it is just a string in another scope, it is not useful for `mixin` or anything like that. You still inspect the *value* using the argument. But the *string* can be used as a *string* for these other tasks.
 I'd like to see an example of code of how this customization 
 might work, because I don't see it.
Element makeHtmlFromTemplate(T...)(T t) if(T.length && is(T[0] == core.interpolation.InterpolationHeader!Parts, Parts...)) { string html; foreach(idx, str; Parts) { if(idx % 2 == 0) html ~= str; // i know this is html string literal thanks to noramlization else // note i also know what code this came from in case i need it for error messages, debug info, etc, it is in `str` html ~= htmlEntitiesEncode(to!string(t[idx / 2])); } return Element.make(Html(html)); } auto element = makeHtmlFromTemplate(i` <html> <p class="foo" title="$(title)"> $(content) </p> </html> `); Note the VERY important fact that the makeHtmlFromTemplate *knows for a fact* what is html and what is data coming from the outside, so it can be sure about what to encode and what not to. Also worth noting it has the option of validating the HTML at compile time, using CTFE, because it can reconstruct the string from the InterpolationHeader too - this is a runtime error in most languages, but in D it doesn't have to be. Javascript can do this kind of thing, with runtime error throwing. The JSX extensions to the language exist to add compile time validation. D ought to be able to do the same thing *without* a custom add-on compiler. We have CTFE.
 P.S. there are several errors in the document, such as '$' 
 appearing in the lowered code. What "normalization" means is 
 unclear.
typos are irrelevant but whatever i'll fix them. "Normalization" means what it says under the "normalization" header, which ensures you can distinctively tell the difference between format string and arguments.
Oct 18 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/18/2023 7:47 PM, Adam D Ruppe wrote:
 I'd like to see an example of code of how this customization might work, 
 because I don't see it.
Element makeHtmlFromTemplate(T...)(T t) if(T.length && is(T[0] == core.interpolation.InterpolationHeader!Parts, Parts...)) {     string html;     foreach(idx, str; Parts) {       if(idx % 2 == 0)         html ~= str; // i know this is html string literal thanks to noramlization       else        // note i also know what code this came from in case i need it for error messages, debug info, etc, it is in `str`         html ~= htmlEntitiesEncode(to!string(t[idx / 2]));     }     return Element.make(Html(html)); } auto element = makeHtmlFromTemplate(i`    <html>       <p class="foo" title="$(title)">            $(content)       </p>    </html> `);
Thanks for the example. I thought I'd show the equivalent with DIP1027. It's a bit crude, and I didn't bother with the details of html generation, but this shows the method and can be compiled and run: ``` import std.conv; string makeHtmlFromTemplate(Parts...)(const char[] fmt, Parts parts) { string html; size_t i; void advance() { while (i < fmt.length) { if (fmt[i] == '%' && i + 1 < fmt.length && fmt[i + 1] == 's') { i += 2; return; } html ~= fmt[i]; ++i; } } advance(); foreach (part; parts) { html ~= to!string(part); // or htmlEntityEncode advance(); } return html; } void main() { import std.stdio; string abc = "def"; string html = makeHtmlFromTemplate("format %s %s sss", abc, 73); // tuple generated by DIP1027 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // from i"format $abc $(73) sss" writeln(html); } ``` which prints: format def 73 sss This code can be adapted to do whatever output schema one wants. Compare the tuple generated by DIP1027: ``` tuple("format %s %s sss", abc, 73) ``` and with YAIDIP: ``` tuple(.object.imported!"core.interpolation".InterpolationHeader!("", "format ", "", abc, "", 73, "", " sss", ""), "", "format ", "", abc, "", 73, "", " sss", "") ```
Oct 20 2023
next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright wrote:
 On 10/18/2023 7:47 PM, Adam D Ruppe wrote:
 [...]
Thanks for the example. I thought I'd show the equivalent with DIP1027. It's a bit crude, and I didn't bother with the details of html generation, but this shows the method and can be compiled and run: ``` import std.conv; string makeHtmlFromTemplate(Parts...)(const char[] fmt, Parts parts) { string html; size_t i; void advance() { while (i < fmt.length) { if (fmt[i] == '%' && i + 1 < fmt.length && fmt[i + 1] == 's') { i += 2; return; } html ~= fmt[i]; ++i; } } advance(); foreach (part; parts) { html ~= to!string(part); // or htmlEntityEncode advance(); } return html; } void main() { import std.stdio; string abc = "def"; string html = makeHtmlFromTemplate("format %s %s sss", abc, 73); // tuple generated by DIP1027 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // from i"format $abc $(73) sss" writeln(html); } ``` which prints: format def 73 sss This code can be adapted to do whatever output schema one wants. Compare the tuple generated by DIP1027: ``` tuple("format %s %s sss", abc, 73) ``` and with YAIDIP: ``` tuple(.object.imported!"core.interpolation".InterpolationHeader!("", "format ", "", abc, "", 73, "", " sss", ""), "", "format ", "", abc, "", 73, "", " sss", "") ```
Whatever happens, can we please either merge the new dip or your dip? Please? Whatever dip is the simplest and performs the best should win. Just so we get somewhere. The community is begging you all to settle for something. Maybe a "winner" could be chosen emperically instead? Write some examples and run. Measure the performance. Fastest that is also currect wins. Easy 😍
Oct 20 2023
prev sibling next sibling parent reply Max Samukha <maxsamukha gmail.com> writes:
On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright wrote:

 ```
 tuple("format %s %s sss", abc, 73)
 ```
This requires cumbersome workarounds for the format string to be accessible at compile time: alias tmp = i"format %s %s sss"; string html = makeHtmlFromTemplate!(tmp[0])(tmp[1..$]); The simple tuple approach could work in Zig - they have "comptime" for partial evaluation (D's old 'static' function parameters plan put into practice).
Oct 20 2023
parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 20 October 2023 at 08:26:35 UTC, Max Samukha wrote:
 On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright wrote:

 ```
 tuple("format %s %s sss", abc, 73)
 ```
This requires cumbersome workarounds for the format string to be accessible at compile time: alias tmp = i"format %s %s sss"; string html = makeHtmlFromTemplate!(tmp[0])(tmp[1..$]); The simple tuple approach could work in Zig - they have "comptime" for partial evaluation (D's old 'static' function parameters plan put into practice).
I didn't know about that old "'static' function parameters", what was that?
Oct 20 2023
parent Max Samukha <maxsamukha gmail.com> writes:
On Friday, 20 October 2023 at 09:43:47 UTC, Imperatorn wrote:

 I didn't know about that old "'static' function parameters", 
 what was that?
`void foo(static T t);`
Oct 20 2023
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright wrote:

 This code can be adapted to do whatever output schema one 
 wants. Compare the tuple generated by DIP1027:

 ```
 tuple("format %s %s sss", abc, 73)
 ```
 and with YAIDIP:
 ```
 tuple(.object.imported!"core.interpolation".InterpolationHeader!("", "format
", "", abc, "", 73, "", " sss", ""), "", "format ", "", abc, "", 73, "", "
sss", "")
 ```
If this is supposed to be a favorable comparison of 1027, this has failed. 1027 requires runtime processing of a compile-time format string. It requires that you implement escapes for the %s spec and for literal %, or just know that your domain doesn't have a valid use for %s normally (though this always can be proven to be a mistake by users). It is not friendly to multiple interpolation strings sent to the same function (how does the function know this is a new header?) YAIDIP or 1036, there is no discarding of the processing the *compiler already did* to parse the format string. Think about that -- with 1027 the compiler parsed the interpolation tuple, and built a puzzle string for you to have to figure out what it did during runtime. Who cares what the generated tuple looks like? Nobody will see it. Do you care what other lowerings in the compiler look like? Because a lot of times they are god-awful monstrosities that nobody would write themselves. Is that something to object to? All the proposed solutions, including 1027, can be worked with for most cases. It's just that the code to adapt 1027 to calls except for printf and writef is awful. It doesn't handle other situations at all. And 1027 still has the problem of matching functions it shouldn't match. Do you recall Adam's example of exception construction? ```d throw new Exception(i"Invalid integer value in $file: $val"); ``` -Steve
Oct 20 2023
next sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 20 October 2023 at 13:45:40 UTC, Steven Schveighoffer 
wrote:
 On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright wrote:

 This code can be adapted to do whatever output schema one 
 wants. Compare the tuple generated by DIP1027:
I'm just happy that I now can do this ![String interpolation](https://i.ibb.co/4WVYSnr/interp.gif) Next is just to integrate into the rest of the tools.
Oct 20 2023
parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 20 October 2023 at 14:13:44 UTC, Imperatorn wrote:
 On Friday, 20 October 2023 at 13:45:40 UTC, Steven 
 Schveighoffer wrote:
 On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright 
 wrote:

 This code can be adapted to do whatever output schema one 
 wants. Compare the tuple generated by DIP1027:
I'm just happy that I now can do this ![String interpolation](https://i.ibb.co/4WVYSnr/interp.gif) Next is just to integrate into the rest of the tools.
Just look at this. You know you want it 😅
Oct 20 2023
parent reply Daniel N <no public.email> writes:
On Friday, 20 October 2023 at 15:47:17 UTC, Imperatorn wrote:
 On Friday, 20 October 2023 at 14:13:44 UTC, Imperatorn wrote:
 On Friday, 20 October 2023 at 13:45:40 UTC, Steven 
 Schveighoffer wrote:
 On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright 
 wrote:

 This code can be adapted to do whatever output schema one 
 wants. Compare the tuple generated by DIP1027:
I'm just happy that I now can do this ![String interpolation](https://i.ibb.co/4WVYSnr/interp.gif) Next is just to integrate into the rest of the tools.
Just look at this. You know you want it 😅
LGTM merge... (if I could :p)
Oct 20 2023
parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 20 October 2023 at 16:15:52 UTC, Daniel N wrote:
 On Friday, 20 October 2023 at 15:47:17 UTC, Imperatorn wrote:
 On Friday, 20 October 2023 at 14:13:44 UTC, Imperatorn wrote:
 On Friday, 20 October 2023 at 13:45:40 UTC, Steven 
 Schveighoffer wrote:
 On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright 
 wrote:
 LGTM merge... (if I could :p)
Hehe, I posted some instructions here if you want to try it out: https://forum.dlang.org/post/rkevblyfgvmvmsuhtqmr forum.dlang.org
Oct 20 2023
prev sibling next sibling parent reply Commander Zot <no no.no> writes:
On Friday, 20 October 2023 at 13:45:40 UTC, Steven Schveighoffer 
wrote:
 On Friday, 20 October 2023 at 07:14:45 UTC, Walter Bright wrote:

 [...]
If this is supposed to be a favorable comparison of 1027, this has failed. 1027 requires runtime processing of a compile-time format string. It requires that you implement escapes for the %s spec and for literal %, or just know that your domain doesn't have a valid use for %s normally (though this always can be proven to be a mistake by users). It is not friendly to multiple interpolation strings sent to the same function (how does the function know this is a new header?) YAIDIP or 1036, there is no discarding of the processing the *compiler already did* to parse the format string. Think about that -- with 1027 the compiler parsed the interpolation tuple, and built a puzzle string for you to have to figure out what it did during runtime. Who cares what the generated tuple looks like? Nobody will see it. Do you care what other lowerings in the compiler look like? Because a lot of times they are god-awful monstrosities that nobody would write themselves. Is that something to object to? All the proposed solutions, including 1027, can be worked with for most cases. It's just that the code to adapt 1027 to calls except for printf and writef is awful. It doesn't handle other situations at all. And 1027 still has the problem of matching functions it shouldn't match. Do you recall Adam's example of exception construction? ```d throw new Exception(i"Invalid integer value in $file: $val"); ``` -Steve
thank you. i agree, YAIDIP is the best solution so far, but i think we should take a step back and think about the real porblem: why can't we do it with existing language features, and what would be required to simply make ```foo(i!"cool ${var} rox");``` work instead. because adding that feature might benefit a lot more use cases.
Oct 20 2023
parent Paul Backus <snarwin gmail.com> writes:
On Friday, 20 October 2023 at 15:29:29 UTC, Commander Zot wrote:
 why can't we do it with existing language features, and what 
 would be required to simply make ```foo(i!"cool ${var} 
 rox");``` work instead. because adding that feature might 
 benefit a lot more use cases.
Because templates are lexically scoped, the body of the `i` template would not be able to access `var` when expanding the string `"cool ${var} rox"`. The only way in D for a template to access the scope where it's *used* instead of the scope where it's *defined* is to use a `mixin` (either string or template). So the best we can do with current language features is `foo(mixin(i!"cool ${var} rox"))`. (And indeed, there are libraries on code.dlang.org that do this.) So, I guess the minimal language feature that would allow your example to work would be the ability to define a template whose result is implicitly mixed-in to the instantiating scope, without having to use the `mixin` keyword. However, I doubt such a feature would be accepted. The whole point of requiring the `mixin` keyword is to signal to anyone reading the code that this is a place where D's normal scoping rules might be violated. Allowing that to happen implicitly would defeat the purpose of having a `mixin` keyword in the first place.
Oct 20 2023
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On Friday, 20 October 2023 at 13:45:40 UTC, Steven Schveighoffer 
wrote:
 All the proposed solutions, including 1027, can be worked with 
 for most cases. It's just that the code to adapt 1027 to calls 
 except for printf and writef is awful. It doesn't handle other 
 situations at all.
I misspoke, 1027 doesn't actually handle `printf` very well, you still have to include the format specifiers for anything other than a `char *`. Only `writef` makes sense. Whereas, with DIP1036, I [already wrote](https://forum.dlang.org/post/rv6f0l$ke7$1 digitalmars.com) an overload that works with `printf` without needing any specifiers, and is betterC compatible, it should lower to one call to `core.stdc.stdio.printf`. ```d import core.stdc.stdio; import std.traits; struct interp(string s) { static string toString() { return s; } } alias printf = core.stdc.stdio.printf; auto printf(Args...)(Args args) if (isInstanceOf!(interp, Args[0])) { static immutable formatStr = () { string result; foreach(T; Args) static if(isInstanceOf!(interp, T)) result ~= T.toString(); else static if(is(T == int)) result ~= "%d"; else static if(is(T : const(char)[])) result ~= "%.*s"; else static if(is(T == float) || is(T == double)) result ~= "%f"; // .. and so on return result ~ "\0"; }(); mixin(() { string result = "return core.stdc.stdio.printf(formatStr.ptr"; foreach(i, T; Args) static if(!isInstanceOf!(interp, T)){ static if(is(T : const(char)[])) result ~= ", cast(int)args[" ~ i.stringof ~ "].length, args[" ~ i.stringof ~ "].ptr"; else result ~= ", args[" ~ i.stringof ~ "]"; } return result ~ ");"; }()); } extern(C) void main() { string name = "Walter"; int age = 42; // equivalent of printf(i"Hello, ${name}, you are ${age} years old.\n"); printf(interp!"Hello, "(), name, interp!", you are "(), age, interp!" years old.\n"()); printf("And normal printf works too, %s\n", name.ptr); } ``` -Steve
Oct 20 2023
prev sibling parent reply Andrea Fontana <nospam example.org> writes:
On Tuesday, 17 October 2023 at 20:05:59 UTC, Walter Bright wrote:
 On 10/17/2023 12:20 PM, Adam D Ruppe wrote:
 And read the post above, which uses *write*, not write*f*. 
 Think about the implications of that for a second.
Yes, it means I forgot to use writef instead of write.
The DIP linked by Adam is very appealing to me. All the modern programming languages I frequently use have some form of string interpolation, and when I write code in D, I miss it. I genuinely don't understand the opposition to such a highly desired feature that can only enhance code readability. I am less fond of the proposal related to printf/writef/writelnf/format/sformat, etc. It appears to add complexity to the code, introduces unnecessary noise, and is prone to errors. Andrea
Oct 18 2023
next sibling parent Bradley Chatha <sealabjaster gmail.com> writes:
On Wednesday, 18 October 2023 at 22:43:56 UTC, Andrea Fontana 
wrote:
 I genuinely don't understand the opposition to such a highly 
 desired feature that can only enhance code readability.
Because the parts of the D community that are both vocal and motivated enough to discuss language improvements are a mix of opposing egos striving for their own visions of perfection, and any slight compromise is deemed unacceptable, unworkable, and nothing short of heresy in the eyes of the all mighty Perfect Solution. I mean this in a relatively sincere way as everyone wants what they think is best for the language, but failure to come to a common ground results in things like several years of on-and-off bike shedding around features other languages (that don't have the same challenges and complications as D for what its worth) could have pushed through several times over since then. features and syntax sugar they add, as it's often well designed, well integrated, has tooling support straight away, and generally just helps make code feel cleaner... (well not all the time lol). Meanwhile we still can't figure out a way to get string interpolation into the language that isn't shot dead in its entirety on arrival :D However if DIP1030 (Named arguments) - which I'm slightly surprise wasn't bikeshedded to rejection - managed to get through, then I'm optimistic in another 5 years we'll have settled on something for interpolation, whether it be outright rejection of the entire idea, or an actual implementable solution.
Oct 18 2023
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/18/2023 3:43 PM, Andrea Fontana wrote:
 I am less fond of the proposal related to
printf/writef/writelnf/format/sformat, 
 etc. It appears to add complexity to the code
Example of the complexity? It's probably the simplest string interpolation I could find.
 introduces unnecessary noise
Example please.
 is prone to errors
It's not prone to errors any more than writef() is, because writef() checks the format against the type of the corresponding argument. As for printf(), we've added format string checking to printf() calls which have virtually eliminated such errors.
Oct 18 2023
parent reply Andrea Fontana <nospam example.org> writes:
On Thursday, 19 October 2023 at 01:05:59 UTC, Walter Bright wrote:
 On 10/18/2023 3:43 PM, Andrea Fontana wrote:
 I am less fond of the proposal related to 
 printf/writef/writelnf/format/sformat, etc. It appears to add 
 complexity to the code
Example of the complexity? It's probably the simplest string interpolation I could find.
 introduces unnecessary noise
Example please.
For example: ``` string t = format(i"....")); ^^^^^^ ```
 is prone to errors
Well, you know, even you posted a wrong example earlier in the thread. I'm also somewhat concerned about potential error messages that might confuse users due to the non-obvious abstraction: f.e. what happens if someone writes ```myfunction(i"hello $name!");``` Andrea
Oct 19 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/19/2023 12:29 AM, Andrea Fontana wrote:
 is prone to errors
Well, you know, even you posted a wrong example earlier in the thread.
The error won't result in anything other than oops there's a format string in the output. If that's the only prone-ness to errors, it's doing very well.
 I'm also somewhat concerned about potential error messages that might confuse 
 users due to the non-obvious abstraction: f.e. what happens if someone writes 
 ```myfunction(i"hello $name!");```
Do you mean someone accidentally prefixing with 'i'? How would that be any different from the other proposal?
Oct 19 2023
parent reply Andrea Fontana <nospam example.org> writes:
On Thursday, 19 October 2023 at 07:51:38 UTC, Walter Bright wrote:
 On 10/19/2023 12:29 AM, Andrea Fontana wrote:
 is prone to errors
Well, you know, even you posted a wrong example earlier in the thread.
The error won't result in anything other than oops there's a format string in the output. If that's the only prone-ness to errors, it's doing very well.
 I'm also somewhat concerned about potential error messages 
 that might confuse users due to the non-obvious abstraction: 
 f.e. what happens if someone writes ```myfunction(i"hello 
 $name!");```
Do you mean someone accidentally prefixing with 'i'? How would that be any different from the other proposal?
Not by mistake, but intentionally because I want to pass a formatted string to my function. And if I'm not mistaken, that string will be expanded into a tuple that could mess up the call to my function, returning an error that might confuse the user. In the worst case, it could call my function with extra parameters I didn't even expect, causing some unexpected side-effects. ``` // This function delete all the file passed (just a joke) void deleteFiles(string[]... files) { ... } // Example deleteFiles("/tmp/test.txt", "/tmp/old.txt"); deleteFiles(i"/tmp/$dirname/$file"); <-- ooops this will be expanded? ```
Oct 19 2023
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
As long as the literal cannot expand out into regular strings and only 
structs, this shouldn't be possible for it to occur silently.

 From there its just a matter of having good error message writing where 
it sees what you tried to do and tell you why its wrong. This can happen 
incrementally.
Oct 19 2023
parent reply Andrea Fontana <nospam example.org> writes:
On Thursday, 19 October 2023 at 10:53:08 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 As long as the literal cannot expand out into regular strings 
 and only structs, this shouldn't be possible for it to occur 
 silently.

 From there its just a matter of having good error message 
 writing where it sees what you tried to do and tell you why its 
 wrong. This can happen incrementally.
But walter's proposal expands it to a tuple if I understand it correctly: https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
Oct 19 2023
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
Don't worry about it, it has already been rejected and this was one of 
the reasons why.

https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md#final-review
Oct 19 2023
next sibling parent Daniel N <no public.email> writes:
On Thursday, 19 October 2023 at 11:10:47 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 Don't worry about it, it has already been rejected and this was 
 one of the reasons why.

 https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md#final-review
I think the simplest solution is to give up on one-size-fits-all. slow"this allocates a string" fast"this creates a fast tuple for meta-programming" Even though the user-facing part is quite different, it would be possible to share much code between the two implementations inside the compiler. obviously slow and fast are placeholder names.
Oct 19 2023
prev sibling next sibling parent claptrap <clap trap.com> writes:
On Thursday, 19 October 2023 at 11:10:47 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 Don't worry about it, it has already been rejected and this was 
 one of the reasons why.

 https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md#final-review
I don't think Walter has given up on it :P
Oct 19 2023
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/19/2023 4:10 AM, Richard (Rikki) Andrew Cattermole wrote:
 Don't worry about it, it has already been rejected and this was one of the 
 reasons why.
 
 https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md#final-review
It doesn't give that as a reason.
Oct 19 2023
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/19/2023 3:40 AM, Andrea Fontana wrote:
 // Example
 deleteFiles("/tmp/test.txt", "/tmp/old.txt");
 deleteFiles(i"/tmp/$dirname/$file"); <-- ooops this will be expanded?
It will be: ``` deleteFiles("/tmp/%s/%s", dirname, file); ``` And you'll probably get a message like: "Could not find /tmp/%s/%s"
Oct 19 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Thursday, 19 October 2023 at 23:45:19 UTC, Walter Bright wrote:
 On 10/19/2023 3:40 AM, Andrea Fontana wrote:
 // Example
 deleteFiles("/tmp/test.txt", "/tmp/old.txt");
 deleteFiles(i"/tmp/$dirname/$file"); <-- ooops this will be 
 expanded?
It will be: ``` deleteFiles("/tmp/%s/%s", dirname, file); ``` And you'll probably get a message like: "Could not find /tmp/%s/%s"
You might get a message like: ``` Could not find `/tmp/%s/%s` successfully removed directory and all files under `importantApp` Could not find `tempfile.cache` ``` The point is that it's too easy to match to strings, compile, and do a completely unexpected thing. And yes, that's the major reason why 1027 is so bad. -Steve
Oct 19 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/19/2023 6:52 PM, Steven Schveighoffer wrote:
 The point is that it's too easy to match to strings, compile, and do a 
 completely unexpected thing. And yes, that's the major reason why 1027 is so
bad.
I don't recall this issue even being discussed in the old review of it. It isn't listed in the review objections for DIP1027. https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md#description If you can point the discussion out to me, I'd appreciate it. But I undestand you don't like this, and there is a rather nice solution. Recall Andrea Fontana's example: ``` void deleteFiles(string[]... files) { ... } ``` As a special case, an i-string will not be a match for `string[]...`. This makes sense, as a function requiring a format string would not be expecting no string. A match would have to be of the form: ``` void deleteFiles(string fmt, ...) { ... } ``` which is the natural form a formatting function would take. If the user wanted to use i-strings to pass to `deleteFiles(string[]...)`, he'd use: ``` string dirname = "project"; string file = "main.o"; deleteFiles(format(i"/tmp/$dirname/$file")); ``` which looks rather nice and self-evident. Hope you like it!
Oct 20 2023
next sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 20 October 2023 at 08:03:55 UTC, Walter Bright wrote:
 On 10/19/2023 6:52 PM, Steven Schveighoffer wrote:
 [...]
I don't recall this issue even being discussed in the old review of it. It isn't listed in the review objections for DIP1027. [...]
What are your main objections to this https://github.com/John-Colvin/YAIDIP
Oct 20 2023
parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 20 October 2023 at 13:03:45 UTC, Imperatorn wrote:
 On Friday, 20 October 2023 at 08:03:55 UTC, Walter Bright wrote:
 On 10/19/2023 6:52 PM, Steven Schveighoffer wrote:
 [...]
I don't recall this issue even being discussed in the old review of it. It isn't listed in the review objections for DIP1027. [...]
What are your main objections to this https://github.com/John-Colvin/YAIDIP
It looks like a good DIP, and as a plus it has an implementation: https://github.com/dlang/dmd/pull/15714 And the DIP is based on prior DIPs and co-written by Andrei. I think it looks reasonable. Please take a second look if possible.
Oct 20 2023
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Friday, 20 October 2023 at 08:03:55 UTC, Walter Bright wrote:
 On 10/19/2023 6:52 PM, Steven Schveighoffer wrote:
 The point is that it's too easy to match to strings, compile, 
 and do a completely unexpected thing. And yes, that's the 
 major reason why 1027 is so bad.
I don't recall this issue even being discussed in the old review of it. It isn't listed in the review objections for DIP1027.
No it's not listed (which surprises me), and the thread is huge, I don't feel like going through it all. I do remember objecting to it though, on the grounds that you can't overload based on a string. For example, I have in mysql-native a function: ```d ulong exec(T...) (Connection conn, const(char[]) sql, T args) ``` Which accepts the statement in the mysql format of using `?` for placeholders. In order to accept an interpolation tuple, I'd have to name a new function: ```d ulong execi(T...) (Connection conn, const(char[]) sql, T args) ``` Which then forwards to the real `exec`. And there would be no way for the compiler to prevent the user from using either with the incorrect parameters. *AND* the `execi` function needs to parse the format string at runtime replacing "%s" with "?". Whereas, YAIDIP and DIP1036 provide a way for the `exec` function to be overloaded with interpolation literals, and always do the right thing at pretty much no runtime cost (the building of the string can be at compile-time).
 But I undestand you don't like this, and there is a rather nice 
 solution. Recall Andrea Fontana's example:

 ```
 void deleteFiles(string[]... files) { ... }
 ```

 As a special case, an i-string will not be a match for 
 `string[]...`. This makes sense, as a function requiring a 
 format string would not be expecting no string. A match would 
 have to be of the form:

 ```
 void deleteFiles(string fmt, ...) { ... }
 ```
Just another whacked mole? What about the Exception problem? ```d throw new Exception(i"Invalid integer value in $file: $val"); ``` -Steve
Oct 20 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/20/2023 9:52 AM, Steven Schveighoffer wrote:
 Just another whacked mole? What about the Exception problem?
 
 ```d
 throw new Exception(i"Invalid integer value in $file: $val");
 ```
You'll get an exception message: Exception at FILE(LINE): Invalid integer value in %s: %s which is pretty much a nothingburger as a problem. YAIDIP can also call the wrong function if you're not careful to make sure the right one is in scope. YAIDIP is also going to match any template that has a first argument of type T with a weird struct that frankly few users will know exists. Anything that generates tuples is going to have minor issues with overload matching.
Oct 20 2023
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On Friday, 20 October 2023 at 19:58:44 UTC, Walter Bright wrote:
 On 10/20/2023 9:52 AM, Steven Schveighoffer wrote:
 Just another whacked mole? What about the Exception problem?
 
 ```d
 throw new Exception(i"Invalid integer value in $file: $val");
 ```
You'll get an exception message: Exception at FILE(LINE): Invalid integer value in %s: %s which is pretty much a nothingburger as a problem.
So you think it's a nothingburger to have zero idea where this exception was thrown from so you can figure it out? e.g. ``` object.Exception foo.txt(18446744073709551574): Invalid integer value in %s: %s ```
 YAIDIP can also call the wrong function if you're not careful 
 to make sure the right one is in scope.
Can you explain this? What function needs to be in scope?
 YAIDIP is also going to match any template that has a first 
 argument of type T with a weird struct that frankly few users 
 will know exists.
Yes, and it's possible the compiler can help out here, just like it says `string` instead of `immutable(char)*` -Steve
Oct 20 2023
prev sibling parent max haughton <maxhaton gmail.com> writes:
On Friday, 20 October 2023 at 19:58:44 UTC, Walter Bright wrote:
 On 10/20/2023 9:52 AM, Steven Schveighoffer wrote:
 Just another whacked mole? What about the Exception problem?
 
 ```d
 throw new Exception(i"Invalid integer value in $file: $val");
 ```
You'll get an exception message: Exception at FILE(LINE): Invalid integer value in %s: %s which is pretty much a nothingburger as a problem.
This feels like the kind of thing that "Make illegal states unrepresentable" is supposed to be prevent, no?
Oct 20 2023
prev sibling parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Tue, Oct 17, 2023 at 05:37:15PM +0000, Adam D Ruppe via Digitalmars-d wrote:
[...]
 If we want to move forward, there's actually a good proposal out there:
 https://github.com/John-Colvin/YAIDIP
Just read through this. This is one of the better interpolated string DIPs I've seen yet; I'd definitely support this over the dip1027 if John would be willing to formally submit it for DIP review. T -- English is useful because it is a mess. Since English is a mess, it maps well onto the problem space, which is also a mess, which we call reality. Similarly, Perl was designed to be a mess, though in the nicest of all possible ways. -- Larry Wall
Oct 17 2023
parent Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 17 October 2023 at 19:33:13 UTC, H. S. Teoh wrote:
 Just read through this.  This is one of the better interpolated 
 string DIPs I've seen yet; I'd definitely support this over the 
 dip1027 if John would be willing to formally submit it for DIP 
 review.
Yeah, this proposal is actually just plain excellent, and the depths of what it enables go well beyond what the text of the document states. It came out of an attempt to solve a real problem John and Andrei were facing, and they listened to what me and Steven had discussed previously. It brings type safety, tuple compatibility, CTFE *and* runtime flexibility, user extensibility, and rich metainfo about each use. It is easy to make this compatible with normal strings, but also html templates, sql queries, gnu gettext, shell commands, even things like assert handlers and detailed exception construction that defers string construction to the end... the list goes on and on. And the implementation is easy too. This is a proposal worthy of D.
Oct 17 2023
prev sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
I decided to have a go and do my own little proposal. Its a pretty big 
mesh of things, with one key difference, the notion of a binary-less 
expression. This simplifies the grammar quite a bit and should do the 
same for the implementation.

https://gist.github.com/rikkimax/90a4b21feabcf34dbecb8efcb587f8e1

```d
stderr.write("$clear\r${white}Progress:$clear$progress% 
\t${white}Speed:$clear $curSpeed $unit");
```

It should be familiar to both C++ and Python folk.

I've already implemented a formatter read/write for ``{:}`` syntax so I 
might be a tad biased, especially since I want to use ``$Identifier`` 
for something (not that it conflicts here).
Oct 17 2023
prev sibling parent reply Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Thursday, 12 October 2023 at 13:39:46 UTC, Andrea Fontana 
wrote:
 Real life example. Render a string like this:

 ```
 \x1b[2K\r\x1b[1mProgress:\x1b[0m 50% \x1b[1m\tSpeed:\x1b[0m 
 15.5 KB/s
 ```

 now (error prone and difficult to debug, try to code it!):


 ```
 stderr.write(format("%s\r%sProgress:%s %5.1f%% %s\tSpeed:%s 
 %6.1f %s%s", clear, white, clear, progress, white, clear, 
 curSpeed, unit));
 ```

 (or with string concat, good luck!)

 vs:

 ```
 stderr.write("${clear}\r{$white}Progress:${clear}${progress}% 
 \t${white}Speed:${clear} ${curSpeed} ${unit}");
 ```

 Andrea
Just a quick comment. Probably with string interpolation, less is more. So the simplest DIP probably wins. ❤️
Oct 17 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/17/2023 10:14 PM, Imperatorn wrote:
 Just a quick comment. Probably with string interpolation, less is more.
Solving for 90% of the cases with a simple solution is preferable than a much more complex one to get a few more %. This is a winning strategy with programming. For example, with Ddoc and Unittest, the idea was to go for a simple-as-possible scheme to cover 90%, and it proved to be a winner.
Oct 18 2023
next sibling parent reply monkyyy <crazymonkyyy gmail.com> writes:
On Thursday, 19 October 2023 at 01:12:53 UTC, Walter Bright wrote:
 On 10/17/2023 10:14 PM, Imperatorn wrote:
 Just a quick comment. Probably with string interpolation, less 
 is more.
Solving for 90% of the cases with a simple solution is preferable than a much more complex one to get a few more %. This is a winning strategy with programming. For example, with Ddoc and Unittest, the idea was to go for a simple-as-possible scheme to cover 90%, and it proved to be a winner.
hmmmmm I would think its nonlinear and you could easily justify 90 -> 95% being 2x the complexity cost
Oct 18 2023
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/18/2023 6:42 PM, monkyyy wrote:
 I would think its nonlinear and you could easily justify 90 -> 95% being 2x
the 
 complexity cost
For another example, the iphone camera pretty much destroyed the market for standalone cameras other than special purpose ones.
Oct 19 2023
parent monkyyy <crazymonkyyy gmail.com> writes:
On Thursday, 19 October 2023 at 07:45:44 UTC, Walter Bright wrote:
 On 10/18/2023 6:42 PM, monkyyy wrote:
 I would think its nonlinear and you could easily justify 90 -> 
 95% being 2x the complexity cost
For another example, the iphone camera pretty much destroyed the market for standalone cameras other than special purpose ones.
I didn't misunderstand you I disagree with your numbers and what they implied you were thinking about the tradeoff space. The difference between 90% and 95%, isn't *linear*, 0-1 probalitys are an s-curve, and 90% means it breaks 1 out of 10, 95% means it breaks 1 out of 20, 99% means it breaks 1 out of 100. etc. Given a complexity increase of 2x going from 90% to 95% means on the user's end they will get 1/2 the number of headaches, so I would feel that's a good and realistic trade-off. By all means don't chase 100%, but 95,97,99% different story.
Oct 19 2023
prev sibling next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 19 October 2023 at 01:12:53 UTC, Walter Bright wrote:
 Solving for 90% of the cases with a simple solution is 
 preferable than a much more complex one to get a few more %. 
 This is a winning strategy with programming.
YAIDIP is an incredibly simple solution that has enormous bang for buck. Its implementation is very simple.
Oct 18 2023
parent Bruce Carneal <bcarneal gmail.com> writes:
On Thursday, 19 October 2023 at 02:48:43 UTC, Adam D Ruppe wrote:
 On Thursday, 19 October 2023 at 01:12:53 UTC, Walter Bright 
 wrote:
 Solving for 90% of the cases with a simple solution is 
 preferable than a much more complex one to get a few more %. 
 This is a winning strategy with programming.
YAIDIP is an incredibly simple solution that has enormous bang for buck. Its implementation is very simple.
I like YAIDIP a lot from what I've read. I also trust Adam and Steve and others in the discord universe who are demonstrated app/template wizards. Me, not so wizardly in that arena so grain of salt advised :-) .
Oct 19 2023
prev sibling next sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Thursday, 19 October 2023 at 01:12:53 UTC, Walter Bright wrote:
 On 10/17/2023 10:14 PM, Imperatorn wrote:
 Just a quick comment. Probably with string interpolation, less 
 is more.
Solving for 90% of the cases with a simple solution is preferable than a much more complex one to get a few more %. This is a winning strategy with programming. For example, with Ddoc and Unittest, the idea was to go for a simple-as-possible scheme to cover 90%, and it proved to be a winner.
Agreed
Oct 18 2023
prev sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Thursday, 19 October 2023 at 01:12:53 UTC, Walter Bright wrote:
 On 10/17/2023 10:14 PM, Imperatorn wrote:
 Just a quick comment. Probably with string interpolation, less 
 is more.
Solving for 90% of the cases with a simple solution is preferable than a much more complex one to get a few more %. This is a winning strategy with programming. For example, with Ddoc and Unittest, the idea was to go for a simple-as-possible scheme to cover 90%, and it proved to be a winner.
Please give us something, anything at all 😭 As long as it's safe and doesn't destroy anything 🙏
Oct 19 2023