www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP 1027---String Interpolation---Community Review Round 1

reply Mike Parker <aldacron gmail.com> writes:
This is the feedback thread for the first round of Community 
Review for DIP 1027, "String Interpolation":

https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

All review-related feedback on and discussion of the DIP should 
occur in this thread. The review period will end at 11:59 PM ET 
on December 25, or when I make a post declaring it complete.

At the end of Round 1, if further review is deemed necessary, the 
DIP will be scheduled for another round of Community Review. 
Otherwise, it will be queued for the Final Review and Formal 
Assessment.

Anyone intending to post feedback in this thread is expected to 
be familiar with the reviewer guidelines:

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

*Please stay on topic!*

Thanks in advance to all who participate.
Dec 11 2019
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
 printf("I ate %s and %d totalling %s fruit.\n", apples, bananas, apples + 
bananas); Gaah, that should be: printf("I ate %d and %d totalling %d fruit.\n", apples, bananas, apples + bananas);
Dec 11 2019
prev sibling next sibling parent reply Rumbu <rumbu rumbu.ro> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
So we cannot have variables named d, s, f, g, x and so on because they are standard format specifiers. What happens with custom format specifiers, any one letter variable cannot be interpolated? Why reinvent the wheel and not adopt the common wisdom of {var}
Dec 11 2019
parent reply MrSmith <mrsmith33 yandex.ru> writes:
On Wednesday, 11 December 2019 at 10:48:56 UTC, Rumbu wrote:
 So we cannot have variables named d, s, f, g, x and so on 
 because they are standard format specifiers. What happens with 
 custom format specifiers, any one letter variable cannot be 
 interpolated?
According to proposal you would wrap format specifiers into {}, like i"%{d}bananas"
Dec 11 2019
parent reply rumbu <rumbu rumbu.ro> writes:
On Wednesday, 11 December 2019 at 11:00:12 UTC, MrSmith wrote:
 On Wednesday, 11 December 2019 at 10:48:56 UTC, Rumbu wrote:
 So we cannot have variables named d, s, f, g, x and so on 
 because they are standard format specifiers. What happens with 
 custom format specifiers, any one letter variable cannot be 
 interpolated?
According to proposal you would wrap format specifiers into {}, like i"%{d}bananas"
Nope, that means "use %d format specifier to print number of bananas". According to the DIP, this is invalid: string what = "bread"; int d = 10; writefln(i"making %what using %d ingredients");
Dec 11 2019
next sibling parent drug <drug2004 bk.ru> writes:
On 12/11/19 2:35 PM, rumbu wrote:
 Nope, that means "use %d format specifier to print number of bananas". 
 According to the DIP, this is invalid:
 
 string what = "bread";
 int d = 10;
 writefln(i"making %what using %d ingredients");
 
According to the DIP this is valid. It would be interpreted as writefln("making %s using %s ingredients", what, d);
Dec 11 2019
prev sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 11 December 2019 at 11:35:05 UTC, rumbu wrote:
 On Wednesday, 11 December 2019 at 11:00:12 UTC, MrSmith wrote:
 On Wednesday, 11 December 2019 at 10:48:56 UTC, Rumbu wrote:
 So we cannot have variables named d, s, f, g, x and so on 
 because they are standard format specifiers. What happens 
 with custom format specifiers, any one letter variable cannot 
 be interpolated?
According to proposal you would wrap format specifiers into {}, like i"%{d}bananas"
Nope, that means "use %d format specifier to print number of bananas". According to the DIP, this is invalid:
No. Read the grammar. Format specifiers MUST be in {}. Element: Character '%%' '%' Argument '%' FormatString Argument FormatString: '{' FormatString '}' CharacterNoBraces CharacterNoBraces: CharacterNoBrace CharacterNoBrace CharacterNoBraces CharacterNoBrace: characters excluding '{' and '}' characters does not exclude s, d, f, g etc.
 string what = "bread";
 int d = 10;
 writefln(i"making %what using %d ingredients");
which is transformed in writefln("making %s using %s ingredients", what, d);
Dec 11 2019
prev sibling next sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 All review-related feedback on and discussion of the DIP should 
 occur in this thread. The review period will end at 11:59 PM ET 
 on December 25, or when I make a post declaring it complete.

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of Community 
 Review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment.

 Anyone intending to post feedback in this thread is expected to 
 be familiar with the reviewer guidelines:

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

 *Please stay on topic!*

 Thanks in advance to all who participate.
Why not just split interpolated string into just a tuple of args & strings. For example: Given: (i"I ate %apples and %bananas totalling %(apples + bananas) fruit.") Is lowered to a tuple: ("I ate ", apples, " and ", bananas," totalling ", apples + bananas," fruit.") It seems current version unnecessarily ties to printf formatting syntax, and makes harder for them to be used in custom user code. Also user still needs call a function to get assembled string which differs from what other languages are doing with interpolated strings. Best regards, Alexandru.
Dec 11 2019
next sibling parent reply MrSmith <mrsmith33 yandex.ru> writes:
On Wednesday, 11 December 2019 at 10:57:13 UTC, Alexandru 
Ermicioi wrote:
 Why not just split interpolated string into just a tuple of 
 args & strings. For example:
 Given: (i"I ate %apples and %bananas totalling %(apples + 
 bananas) fruit.")
 Is lowered to a tuple: ("I ate ", apples, " and ", bananas," 
 totalling ", apples + bananas," fruit.")
That's an option, but one would also need to figure out handling of format specifiers
Dec 11 2019
parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 11 December 2019 at 11:01:58 UTC, MrSmith wrote:
 On Wednesday, 11 December 2019 at 10:57:13 UTC, Alexandru 
 Ermicioi wrote:
 Why not just split interpolated string into just a tuple of 
 args & strings. For example:
 Given: (i"I ate %apples and %bananas totalling %(apples + 
 bananas) fruit.")
 Is lowered to a tuple: ("I ate ", apples, " and ", bananas," 
 totalling ", apples + bananas," fruit.")
That's an option, but one would also need to figure out handling of format specifiers
Do we really need support for format specifiers which are mostly appliable for primitive numeric type? I doubt existing format specifiers could be used with structs, classes, or any aggregate structures. An alternative to specifiers we could define free functions that would format numeric values as needed allowing us to write smth like: i"I ate %apples and %bananas totalling %(apples + bananas).format(formatargs))" then, accepting function wouldn't require to meddle with specific printf semantics, and will get properly pre-formatted data to process. if format specifiers are still desired they could be passed as separate arguments similar how it is done for getopts, and then accepting function would need to treat them in context of passed args. Best regards, Alexandru.
Dec 11 2019
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 10:57:13 UTC, Alexandru 
Ermicioi wrote:
 Why not just split interpolated string into just a tuple of 
 args & strings. For example:
 Given: (i"I ate %apples and %bananas totalling %(apples + 
 bananas) fruit.")
 Is lowered to a tuple: ("I ate ", apples, " and ", bananas," 
 totalling ", apples + bananas," fruit.")

 It seems current version unnecessarily ties to printf 
 formatting syntax, and makes harder for them to be used in 
 custom user code.
Agree. Your suggestion is much more in line with metaprogramming and offers the right flexibility. Although I think you should just use braces. Also, change the prefix to "f", so that is is similar to other languages like Python. So you could get: log(f"I have {dec(3,2)}{account.total} USD in my pocket") Becomes log("I have ", dec(3,2), account.total," USD in my pocket") That way people can use modern custom formatters if the called function knows how to deal with it. printf is archaic and hardcoding it into the language just makes the language stuck.
Dec 11 2019
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 11:21:08 UTC, Ola Fosheim 
Grøstad wrote:
 log(f"I have {dec(3,2)}{account.total} USD in my pocket")

 Becomes
 log("I have ", dec(3,2), account.total," USD in my pocket")
Actually, make that a tuple, but add proper tuples first. So that you can write log("Vector {vec_formatter(3,2)}{myvec} is ready.", log_channel) and it becomes log (〈"Vector ", vec_formatter(3,2), myvec, " is ready."〉, log_channel ) Where «〈» and «〉» signifies the language-builtin tuple.
Dec 11 2019
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 11:40:44 UTC, Ola Fosheim 
Grøstad wrote:
 On Wednesday, 11 December 2019 at 11:21:08 UTC, Ola Fosheim 
 Grøstad wrote:
 log(f"I have {dec(3,2)}{account.total} USD in my pocket")
Note: the above suggestion is close to Python 3. https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals
Dec 11 2019
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 11 December 2019 at 11:21:08 UTC, Ola Fosheim 
Grøstad wrote:
 Agree. Your suggestion is much more in line with 
 metaprogramming and offers the right flexibility.
But then it is impossible to tell which parts were in the string literal and which parts are outside data. If you are going to do the tuple thing it absolutely must put a string in every other slot so this can be predicted. Walter's proposal at least separates them cleanly.
Dec 11 2019
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 13:43:48 UTC, Adam D. Ruppe 
wrote:
 On Wednesday, 11 December 2019 at 11:21:08 UTC, Ola Fosheim 
 Grøstad wrote:
 Agree. Your suggestion is much more in line with 
 metaprogramming and offers the right flexibility.
But then it is impossible to tell which parts were in the string literal and which parts are outside data.
Can't you handle this by taking the head of the tuple and then let the formatter absorb what it needs? Then continue with the rest of the tuple? Anyway, that was just a suggestion for making something that was close enough to Python 3 to be easy to use for simple cases (but slightly more difficult for advanced meta programming). No problem with clever tricks in libraries, but it should not be complex on the surface, like this DIP. D needs to 1. embrace metaprogramming and 2. provide a simple surface for newbies.
 If you are going to do the tuple thing it absolutely must put a 
 string in every other slot so this can be predicted.
Not necessarily, if you have a protocol then you can identify the type. However, it is probably better to let the formatting object wrap the data. If you want it simple: add tuples. You either get something that can be turned into a string or you get a tuple, if you get a tuple then the first item in the tuple is a formatter and the rest is data. Probably 100 ways to do this, but the key is to support custom formatters in an efficient manner that does not require high level allocation optimizations (GC languages can optimize away allocations because they control the allocator and all allocations).
Dec 11 2019
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 13:57:20 UTC, Ola Fosheim 
Grøstad wrote:
 If you want it simple: add tuples. You either get something 
 that can be turned into a string or you get a tuple, if you get 
 a tuple then the first item in the tuple is a formatter and the 
 rest is data.
You could use «,» to indicate a formatter like this: f"This is {"my money"}: {dec(3,2), my_account}!" => ("This is ", "my money", ": ", ( dec(3,2), my_account ), "!")
Dec 11 2019
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 11 December 2019 at 11:21:08 UTC, Ola Fosheim 
Grøstad wrote:
 [snip]
 Also, change the prefix to "f", so  that is is similar to other 
 languages like Python.
 [snip]
Python has f interpolation that looks like print(f'Hello {name}! This is {program}') but it also has % formatting that looks like print(‘Hello %(name)s! This is %(program)s.’%(name,program)) This %(name) is probably the closest that compares to this DIP, but it seems like the Python 3.6 string interpolation was meant to replace that. Scala also has f interpolation, but they also have s and raw interpolation. The f is like println(f"$name%s is $height%2.2f meters tall") the s is like println(s"Hello, $name") and the raw is like raw"a\nb" The raw strings would correspond to D's r strings. However, from that string interpolation page from wikipedia, I'm not seeing a lot of other examples of languages that use the f. Many of the languages on there do not require a prefix, though it seems to be mostly dynamic languages. It looks to me like most of use a $ interpolation as in Console.WriteLine($"Hello, {name}") It looks most common to use $var, ${var}, ${expression}, or a little more rarely just {var}. I like Scala's syntax, but you could probably bring together the f and s strings by just providing a default if there is no format provided.
Dec 11 2019
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 14:41:39 UTC, jmh530 wrote:
 This %(name) is probably the closest that compares to this DIP, 
 but it seems like the Python 3.6 string interpolation was meant 
 to replace that.
Yes, I no longer use % in Python. It is baggage. I either use format or f"…". A good reason to aim for modern Python is that newbies will know it. Python is taught in universities... It will look familiar to the next batch of programmers.
Dec 11 2019
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 11 December 2019 at 14:59:27 UTC, Ola Fosheim 
Grøstad wrote:
 [snip]
 Yes, I no longer use % in Python. It is baggage. I either use 
 format or f"…".

 A good reason to aim for modern Python is that newbies will 
 know it. Python is taught in universities... It will look 
 familiar to the next batch of programmers.
Please see my reply above to bachmeier on Python's format strings versus Scala's. Because of the formatting options, I wouldn't lean too heavily on Python's syntax. I think we should look to what other languages do, but ultimately do what is right for D and consistent with the language that is already there.
Dec 11 2019
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 15:13:20 UTC, jmh530 wrote:
 Because of the formatting options, I wouldn't lean too heavily 
 on Python's syntax. I think we should look to what other 
 languages do, but ultimately do what is right for D and 
 consistent with the language that is already there.
Sure, but as I pointed out you can do both. Just upgrade "%d" and "%f" to formatting objects and rewrite them. So, if you want oldstyle you just write f"%...d{variablename}" and it will be turned into f"{std.formatter.format_d(…), variablename}" Having formatting objects is important for many reasons, one is localization. You need that for float and ints. "3,14" vs "3.14" or "1,000,000" vs "1'000'000" etc. So you can do: auto d = some_custom_formatter(…) f"{d, variablename}...{d, somothervariable}" *shrug* printf style is only useful for logging and text file formats. It does not work for GUIs or anything that is user facing. You need to be able to customize and provide your own formatters. (Just think currency "100 USD" vs "100 SEK")
Dec 11 2019
prev sibling next sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 11 December 2019 at 10:57:13 UTC, Alexandru 
Ermicioi wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 [...]
Why not just split interpolated string into just a tuple of args & strings. For example: Given: (i"I ate %apples and %bananas totalling %(apples + bananas) fruit.") Is lowered to a tuple: ("I ate ", apples, " and ", bananas," totalling ", apples + bananas," fruit.") It seems current version unnecessarily ties to printf formatting syntax, and makes harder for them to be used in custom user code. Also user still needs call a function to get assembled string which differs from what other languages are doing with interpolated strings.
This wouldn't work for C formats like printf. The proposition has the nice property of being usable for DasBetterC and interfacing with C libraries that use format specifiers (libxml2 anyone?).
Dec 11 2019
next sibling parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 11 December 2019 at 15:41:56 UTC, Patrick Schluter 
wrote:
 On Wednesday, 11 December 2019 at 10:57:13 UTC, Alexandru 
 Ermicioi wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 [...]
Why not just split interpolated string into just a tuple of args & strings. For example: Given: (i"I ate %apples and %bananas totalling %(apples + bananas) fruit.") Is lowered to a tuple: ("I ate ", apples, " and ", bananas," totalling ", apples + bananas," fruit.") It seems current version unnecessarily ties to printf formatting syntax, and makes harder for them to be used in custom user code. Also user still needs call a function to get assembled string which differs from what other languages are doing with interpolated strings.
This wouldn't work for C formats like printf. The proposition has the nice property of being usable for DasBetterC and interfacing with C libraries that use format specifiers (libxml2 anyone?).
Indeed it doesn't, yet it falls nicely with std.conv.text, and variadic args versions of writeln, has less development overhead (no need to parse string for printf placeholders) when writing functions accepting resulting tuple from interpolation string, and could be made compatible with betterC mode by having a util func that transforms tuple to printf compliant version. Best regards, Alexandru.
Dec 11 2019
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 7:41 AM, Patrick Schluter wrote:
 This wouldn't work for C formats like printf. The proposition has the nice 
 property of being usable for DasBetterC and interfacing with C libraries that 
 use format specifiers (libxml2 anyone?).
It definitely needs to work for printf and writef.
Dec 13 2019
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Saturday, 14 December 2019 at 07:37:49 UTC, Walter Bright 
wrote:
 It definitely needs to work for printf and writef.
That's an odd requirement, considering you can update writef with the compiler, and printf is legacy.
Dec 14 2019
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 2:57 AM, Alexandru Ermicioi wrote:
 Why not just split interpolated string into just a tuple of args & strings.
For 
 example:
 Given: (i"I ate %apples and %bananas totalling %(apples + bananas) fruit.")
 Is lowered to a tuple: ("I ate ", apples, " and ", bananas," totalling ",
apples 
 + bananas," fruit.")
I don't see the point of that. The user could write it that way to begin with.
Dec 13 2019
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/14/19 2:34 AM, Walter Bright wrote:
 On 12/11/2019 2:57 AM, Alexandru Ermicioi wrote:
 Why not just split interpolated string into just a tuple of args & 
 strings. For example:
 Given: (i"I ate %apples and %bananas totalling %(apples + bananas) 
 fruit.")
 Is lowered to a tuple: ("I ate ", apples, " and ", bananas," totalling 
 ", apples + bananas," fruit.")
I don't see the point of that. The user could write it that way to begin with.
Walter, this is literally the point of string interpolation. A similar response to your entire proposal could be, why not just use writeln and write out all the items? The point is not just to put the expressions where they belong, but to be less verbose about it. The dance of quotes and commas is hard to read and hard to write. -Steve
Dec 14 2019
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/14/2019 7:07 AM, Steven Schveighoffer wrote:
 On 12/14/19 2:34 AM, Walter Bright wrote:
 On 12/11/2019 2:57 AM, Alexandru Ermicioi wrote:
 Why not just split interpolated string into just a tuple of args & strings. 
 For example:
 Given: (i"I ate %apples and %bananas totalling %(apples + bananas) fruit.")
 Is lowered to a tuple: ("I ate ", apples, " and ", bananas," totalling ", 
 apples + bananas," fruit.")
I don't see the point of that. The user could write it that way to begin with.
Walter, this is literally the point of string interpolation. A similar response to your entire proposal could be, why not just use writeln and write out all the items?
String interpolation for format strings is quite different.
 The point is not just to put the expressions where they belong, but to be less 
 verbose about it. The dance of quotes and commas is hard to read and hard to
write.
"I ate ", apples, " and ", bananas, " totalling ", apples + bananas, " fruit." isn't too bad. Formatting, though, won't change the issue with format strings and the disconnect between the arguments and their positions.
Dec 14 2019
parent reply Tove <tove fransson.se> writes:
On Saturday, 14 December 2019 at 21:22:41 UTC, Walter Bright 
wrote:
 On 12/14/2019 7:07 AM, Steven Schveighoffer wrote:
 The point is not just to put the expressions where they 
 belong, but to be less verbose about it. The dance of quotes 
 and commas is hard to read and hard to write.
"I ate ", apples, " and ", bananas, " totalling ", apples + bananas, " fruit." isn't too bad. Formatting, though, won't change the issue with format strings and the disconnect between the arguments and their positions.
Is format strings worth building on? With UFCS we could create types which control formatting "pi=", pi.dec(10), 255, " in hex ", 255.hex
Dec 14 2019
parent mipri <mipri minimaltype.com> writes:
On Saturday, 14 December 2019 at 21:35:51 UTC, Tove wrote:
 Is format strings worth building on?

 With UFCS we could create types which control formatting
 "pi=", pi.dec(10),
 255, " in hex ", 255.hex
This is already possible, though: import std; struct HexPrinter(T) { T item; void toString(scope void delegate(string) sink, FormatSpec!char fmt) const { sink(format("%x", item)); } } HexPrinter!T hex(T)(T n) { return HexPrinter!T(n); } void main() { writefln("255 = %s hex", 255.hex); } so with DIP-1027 it'd remain possible with a syntax like writefln(i"255 = $(255.hex) hex");
Dec 14 2019
prev sibling next sibling parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Saturday, 14 December 2019 at 07:34:05 UTC, Walter Bright 
wrote:
 On 12/11/2019 2:57 AM, Alexandru Ermicioi wrote:
 Why not just split interpolated string into just a tuple of 
 args & strings. For example:
 Given: (i"I ate %apples and %bananas totalling %(apples + 
 bananas) fruit.")
 Is lowered to a tuple: ("I ate ", apples, " and ", bananas," 
 totalling ", apples + bananas," fruit.")
I don't see the point of that. The user could write it that way to begin with.
Yes he could. The main concern I have is that current proposal is tied to printf syntax (template string first, and then args to replace) which will be quite cumbersome for people who would like to use tuple resulting from interpolation. They will need to parse template string to find all args placeholders and then split template string on those locations in most basic case. This is unnecessary boilerplate code thrown onto user. Example above solves this issue by removing the need to parse this template string since it won't be there anymore. In any case Adam's version seems more versatile and could work nicely, allowing user to choose what he would get from interpolation. For example it could alias itself to a built version of interpolated string, and expose interface to get interpolated tuple in printf format, or in format suitable for text function. Also having such structure we could encode other information such as variable prefix syntax used in interpolation string if it is decided to have the ability to change prefix, which could be then used nicely to throw asserts on wrong interpolation syntax being used and etc. The only thing is I don't understand why a struct is not sufficient for interpolated string in Adam's proposal. Best regards, Alexandru
Dec 14 2019
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Saturday, 14 December 2019 at 07:34:05 UTC, Walter Bright 
wrote:
 I don't see the point of that. The user could write it that way 
 to begin with.
Translations. Marking all your sentence fragments as translatable is messy, but there's a far worse impact on translators. They will have some trouble piecing together the sentence, then they will find it almost impossible to translate the fragments in the correct order for the data arguments. Spoken languages are not word for word equivalent.
Dec 16 2019
prev sibling next sibling parent reply Sebastiaan Koppe <mail skoppe.eu> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
Nice! I just have a few nitpicks: - I don't mind the required prefix 'i', but what about q{} strings? I probably want to use interpolation there as well - I know it is bikeshedding but since string interpolation is 99% syntax, I vote for "either a single $colon for variables or ${expression} for expressions", like literally every other modern language. Besides that, this is really nice.
Dec 11 2019
next sibling parent reply Martin Tschierschke <mt smartdolphin.de> writes:
On Wednesday, 11 December 2019 at 11:05:25 UTC, Sebastiaan Koppe 
wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
Nice! I just have a few nitpicks: - I don't mind the required prefix 'i', but what about q{} strings? I probably want to use interpolation there as well - I know it is bikeshedding but since string interpolation is 99% syntax, I vote for "either a single $colon for variables or ${expression} for expressions", like literally every other modern language. Besides that, this is really nice.
Yes +1! It should be something common, not a dlang only syntax. => $var and ${expression} https://en.wikipedia.org/wiki/String_interpolation But this alone gives no way for formatting numbers, so maybe ${%9.6f}{fvar} ?
Dec 11 2019
next sibling parent reply bachmeier <no spam.net> writes:
On Wednesday, 11 December 2019 at 12:11:34 UTC, Martin 
Tschierschke wrote:

 Yes +1! It should be something common, not a dlang only syntax.
 => $var and ${expression}

 https://en.wikipedia.org/wiki/String_interpolation

 But this alone gives no way for formatting numbers, so maybe 
 ${%9.6f}{fvar} ?
My recollection is that in Python 3 that would be done {fvar: 9.6f} or something like that (not a Python programmer).
Dec 11 2019
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 11 December 2019 at 14:55:08 UTC, bachmeier wrote:
 [snip]

 My recollection is that in Python 3 that would be done {fvar: 
 9.6f} or something like that (not a Python programmer).
Python's formatting is described here: https://www.python.org/dev/peps/pep-0498/#id30 so I think it would be more like {var: {9}.{6}} Scala's would be more like $val%9.6f, which I find both more concise and consistent with other D code.
Dec 11 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 6:55 AM, bachmeier wrote:
 But this alone gives no way for formatting numbers, so maybe ${%9.6f}{fvar} ?
My recollection is that in Python 3 that would be done {fvar: 9.6f} or something like that (not a Python programmer).
Both these have parsing problems. The idea is to keep it parse-able with minimal grammar, which will make it easiest for people to understand.
Dec 13 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 4:11 AM, Martin Tschierschke wrote:
 It should be something common, not a dlang only syntax.
Unfortunately, there is enough variation in common use that there's no such thing as a common syntax.
 But this alone gives no way for formatting numbers
Yup. It's not good enough.
Dec 13 2019
prev sibling next sibling parent bachmeier <no spam.net> writes:
On Wednesday, 11 December 2019 at 11:05:25 UTC, Sebastiaan Koppe 
wrote:

 - I know it is bikeshedding but since string interpolation is 
 99% syntax, I vote for "either a single $colon for variables or 
 ${expression} for expressions", like literally every other 
 modern language.
That's definitely not bikeshedding. Given how late D is to the party on this, there's no excuse to not steal the best available syntax from other languages.
Dec 11 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 3:05 AM, Sebastiaan Koppe wrote:
 - I don't mind the required prefix 'i', but what about q{} strings? I probably 
 want to use interpolation there as well
The interpolation string needs to be a separate token. But I was thinking about i strings being concatenated with other strings if the others immediately follow it.
 - I know it is bikeshedding but since string interpolation is 99% syntax, I
vote 
 for "either a single $colon for variables or ${expression} for expressions", 
 like literally every other modern language.
Have to fit in format specifiers, too.
Dec 13 2019
prev sibling next sibling parent reply Andrea Fontana <nospam example.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 All review-related feedback on and discussion of the DIP should 
 occur in this thread. The review period will end at 11:59 PM ET 
 on December 25, or when I make a post declaring it complete.

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of Community 
 Review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment.

 Anyone intending to post feedback in this thread is expected to 
 be familiar with the reviewer guidelines:

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

 *Please stay on topic!*

 Thanks in advance to all who participate.
Nice but it sounds a bit "hacky" to me. If i'm right this code will output "Hello %textworld123" string text = "world"; text(i"Hello %text", "123"); I hoped it was expanded to a function call rather than to a tuple... Andrea
Dec 11 2019
next sibling parent Andrea Fontana <nospam example.com> writes:
On Wednesday, 11 December 2019 at 11:45:07 UTC, Andrea Fontana 
wrote:
 If i'm right this code will output "Hello %textworld123"
Oops, I mean "Hello %sworld123"
Dec 11 2019
prev sibling next sibling parent reply Andre Pany <andre s-e-a-p.de> writes:
On Wednesday, 11 December 2019 at 11:45:07 UTC, Andrea Fontana 
wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 All review-related feedback on and discussion of the DIP 
 should occur in this thread. The review period will end at 
 11:59 PM ET on December 25, or when I make a post declaring it 
 complete.

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of Community 
 Review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment.

 Anyone intending to post feedback in this thread is expected 
 to be familiar with the reviewer guidelines:

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

 *Please stay on topic!*

 Thanks in advance to all who participate.
Nice but it sounds a bit "hacky" to me. If i'm right this code will output "Hello %textworld123" string text = "world"; text(i"Hello %text", "123"); I hoped it was expanded to a function call rather than to a tuple... Andrea
If my understanding is right, string assignment is not supported by the dip, only the 2 functions writeln/printf. Which would be a quite big limitation. This would only cover 20% of my use case of string interpolation. Is my understanding correct? Kind regards André
Dec 11 2019
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 11 December 2019 at 12:31:28 UTC, Andre Pany wrote:
 supported by the dip, only the 2 functions writeln/printf.
No, it can be passed to anything. std.string.format does it returning a string. Or you can write custom functions to read it.
Dec 11 2019
prev sibling parent Andrea Fontana <nospam example.com> writes:
On Wednesday, 11 December 2019 at 12:31:28 UTC, Andre Pany wrote:
 If my understanding is right, string assignment is not 
 supported by the dip, only the 2 functions writeln/printf.
 Which would be a quite big limitation. This would only cover 
 20% of my use case
 of string interpolation.
 Is my understanding correct?

 Kind regards
 André
Probably we're going to add format everywhere write: string t = i"%count iterations done.".format; Andrea
Dec 11 2019
prev sibling next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 11:45:07 UTC, Andrea Fontana 
wrote:
 I hoped it was expanded to a function call rather than to a 
 tuple...
Or maybe some kind of formatting-objects protocol? Then you could things like: f" …%1.3f{some_float}…{otherstuff}" => ( "…", string_format_f!typeof(some_float)(1,3)(some_float), "…", otherstuff ) *shrugs*
Dec 11 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 3:45 AM, Andrea Fontana wrote:
 I hoped it was expanded to a function call rather than to a tuple...
Functions currently can't return tuples, meaning you couldn't make it work with printf.
Dec 13 2019
prev sibling next sibling parent reply Rumbu <rumbu rumbu.ro> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 writefln(i"I ate %apples and %{d}bananas")
What if I don't want any space after %apples?
Dec 11 2019
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 11 December 2019 at 12:35:54 UTC, Rumbu wrote:
 writefln(i"I ate %apples and %{d}bananas")
What if I don't want any space after %apples?
i"I ate %(apples)and " just use the parenthesis version.
Dec 11 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 5:48 AM, Adam D. Ruppe wrote:
 just use the parenthesis version.
Note that this is similar to how text macros work in the make program.
Dec 13 2019
prev sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 11 December 2019 at 12:35:54 UTC, Rumbu wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 writefln(i"I ate %apples and %{d}bananas")
What if I don't want any space after %apples?
Then you write %(apples)nospace.
Dec 11 2019
prev sibling next sibling parent reply Ernesto Castellotti <erny.castell gmail.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 All review-related feedback on and discussion of the DIP should 
 occur in this thread. The review period will end at 11:59 PM ET 
 on December 25, or when I make a post declaring it complete.

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of Community 
 Review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment.

 Anyone intending to post feedback in this thread is expected to 
 be familiar with the reviewer guidelines:

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

 *Please stay on topic!*

 Thanks in advance to all who participate.
From the dip it seems that it is only valid for writefln & co So a code like: auto myText = i"I ate% apples" would not be valid. Correct me if I'm wrong but from my point of view this "String interpolation" is completely useless. I wish D had a string interpolation like Kotlin
Dec 11 2019
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 12:50:34 UTC, Ernesto 
Castellotti wrote:
 e if I'm wrong but from my point of view this "String 
 interpolation" is completely useless.
 I wish D had a string interpolation like Kotlin
The problem is making it work with something like a string-appender. If you don't have GC then you might want to estimate buffer size before allocating, so you need 2 passes. * pass 1: run over all items and caculate length *allocate buffer * pass 2: call formatting-objects on each item and ask them to write themselves to a slice. But a metaprogramming oriented language really should to support custom formatters well in interpolated strings.
Dec 11 2019
prev sibling next sibling parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 11 December 2019 at 12:50:34 UTC, Ernesto 
Castellotti wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 All review-related feedback on and discussion of the DIP 
 should occur in this thread. The review period will end at 
 11:59 PM ET on December 25, or when I make a post declaring it 
 complete.

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of Community 
 Review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment.

 Anyone intending to post feedback in this thread is expected 
 to be familiar with the reviewer guidelines:

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

 *Please stay on topic!*

 Thanks in advance to all who participate.
From the dip it seems that it is only valid for writefln & co So a code like: auto myText = i"I ate% apples" would not be valid. Correct me if I'm wrong but from my point of view this "String interpolation" is completely useless. I wish D had a string interpolation like Kotlin
this code should be valid although it wont be a string but a tuple of string & args ready for printing by stdio family of printer functions. Current implementation also requires that a function call to be used to get a string, which defies the entire purpose of interpolated strings. It either should be a simple tuple as suggested above (then i could live with additional func call to get resulting string), or return an interpolated string ready to be used (no additional function call). Best regards, Alexandru.
Dec 11 2019
prev sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 11 December 2019 at 12:50:34 UTC, Ernesto 
Castellotti wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 [...]
From the dip it seems that it is only valid for writefln & co So a code like: auto myText = i"I ate% apples" would not be valid.
It is allowed everywhere where a tuple expression is allowed auto myText = "I ate%s", apples doesn't make sense
 Correct me if I'm wrong but from my point of view this "String 
 interpolation" is completely useless.
 I wish D had a string interpolation like Kotlin
Dec 11 2019
parent reply Meta <jared771 gmail.com> writes:
On Wednesday, 11 December 2019 at 15:55:35 UTC, Patrick Schluter 
wrote:
 On Wednesday, 11 December 2019 at 12:50:34 UTC, Ernesto 
 Castellotti wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 [...]
From the dip it seems that it is only valid for writefln & co So a code like: auto myText = i"I ate% apples" would not be valid.
It is allowed everywhere where a tuple expression is allowed auto myText = "I ate%s", apples doesn't make sense
It works already (un?)fortunately: auto test = AliasSeq!("The product of %s and %s is %s", 2, 5, 10); writeln(test); //Prints "The product of %s and %s is %s2510" writefln(test); //Print "The product of 2 and 5 is 10" This DIP is just taking that 1 extra small step to allow i"" strings to be lowered to tuple literals.
Dec 11 2019
next sibling parent Ernesto Castellotti <erny.castell gmail.com> writes:
On Wednesday, 11 December 2019 at 17:49:45 UTC, Meta wrote:
 On Wednesday, 11 December 2019 at 15:55:35 UTC, Patrick 
 Schluter wrote:
 On Wednesday, 11 December 2019 at 12:50:34 UTC, Ernesto 
 Castellotti wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 [...]
From the dip it seems that it is only valid for writefln & co So a code like: auto myText = i"I ate% apples" would not be valid.
It is allowed everywhere where a tuple expression is allowed auto myText = "I ate%s", apples doesn't make sense
It works already (un?)fortunately: auto test = AliasSeq!("The product of %s and %s is %s", 2, 5, 10); writeln(test); //Prints "The product of %s and %s is %s2510" writefln(test); //Print "The product of 2 and 5 is 10" This DIP is just taking that 1 extra small step to allow i"" strings to be lowered to tuple literals.
Yes this is the purpose of the dip, but it is not what I expect for the string interpolation. This would require explicitly calling the functions of a library to convert the tuple into a string, I would like it to be done literals implicitly.
Dec 11 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 9:49 AM, Meta wrote:
 This DIP is just taking that 1 extra small step to allow i"" strings to be 
 lowered to tuple literals.
You're right. That's really all it does. It will work anywhere a tuple will work.
Dec 13 2019
prev sibling next sibling parent reply Sebastiaan Koppe <mail skoppe.eu> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
What happens in a template? --- string str = "work"; template myTemplate(string str, Args...) {} myTemplate!(i"will this %str as expected?"); --- How will the params be passed? Aliased?
Dec 11 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 5:00 AM, Sebastiaan Koppe wrote:
 ---
 string str = "work";
 template myTemplate(string str, Args...) {}
 
 myTemplate!(i"will this %str as expected?");
 ---
 
 How will the params be passed? Aliased?
As if you wrote: myTemplate!("will this %s as expected", str);
Dec 13 2019
prev sibling next sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:

The transformation is WRONG!
'%%', a '%' is written to the output string.

it must be
'%%', a '%%' is written to the output string or else you will 
have problems

Example. If I have following expression

writefln(i"I ate %{d}apples and %{d}bananas totalling 
%{d}(100*apples/bananas) %%fruit\n");

it would be lowered to

writefln("I ate %d and %d totalling %d %fruit\n", apples, 
bananas, (100*apples/bananas));

The %% being transformed to a simple %, we now have a %f with no 
parameter => compilation error or worse undefined behaviour in 
case of printf.

I would have to write

writefln(i"I ate %{d}apples and %{d}bananas totalling 
%{d}(100*apples/bananas) %%%%fruit\n");

which is not good.

So '%%' have to be untouched by the lowering
Dec 11 2019
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 7:37 AM, Patrick Schluter wrote:
 The transformation is WRONG!
You're quite right. I missed that. With some noodling about with this problem, I've decided to replace the % with $. Then, % just becomes an ordinary character. Using $ also has the advantage of visually distinguishing a % format string from an interpolated format string.
Dec 14 2019
parent Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Saturday, 14 December 2019 at 08:00:41 UTC, Walter Bright 
wrote:
 I've decided to replace the % with $. Then, % just becomes an 
 ordinary character.

 Using $ also has the advantage of visually distinguishing a % 
 format string from an interpolated format string.
Nice. It’s also more like what several other languages do. Bastiaan.
Dec 14 2019
prev sibling next sibling parent reply Anonymouse <zorael gmail.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
 [...]
This is amazing and I would use it straight away. To preempt any suggestion to just use format with %n$s positional specifiers instead, I present to you non-trivial cases of Bash colour highlighting. enum logtint = "\033[1;32m"; enum warningtint = "\033[1;31m"; enum resettint = "\033[0m"; writefln("%3$sException: %1$s%2$s%3$s (at %1$s%4$s%3$s:%1$s%5$d%3$s)%6$s", logtint, e.msg, warningtint, e.file, e.line, resettint);
Dec 11 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 10:40 AM, Anonymouse wrote:
 To preempt any suggestion to just use format with %n$s positional specifiers 
 instead, I present to you non-trivial cases of Bash colour highlighting.
 
 enum logtint = "\033[1;32m";
 enum warningtint = "\033[1;31m";
 enum resettint = "\033[0m";
 
 writefln("%3$sException: %1$s%2$s%3$s (at %1$s%4$s%3$s:%1$s%5$d%3$s)%6$s",
      logtint, e.msg, warningtint, e.file, e.line, resettint);
Not going to use positional specifiers: 1. I don't see much point to them 2. more complexity 3. problems with evaluating an argument multiple times when there are side effects.
Dec 14 2019
prev sibling next sibling parent reply Robert Schadek <rschadek symmetryinvestments.com> writes:
I'm not really sure if the balance of added complexity vs. payoff 
is in favor of payoff.
They only time I felt the need for such a feature was when I had 
very long DelimitedStrings.
And those long strings where a constant source bugs, so I split 
them up and the field need for interpolated strings want away 
with the bugs.

Not being able to use * will stop me using this feature in many 
places.


The rationale about "missing arguments, wrong format 
specifier,... " Is a mute point IMO. format!"%d"(13.37) does the 
same thing already without any language change.
I thought the idea was not to introduce language changes if a 
library solution can do most of it already.
I find that the readability argument is highly subjective.
The first part of the rationale is, IHO,
already pointing to the solution. Short strings are easy to 
manage.
So let's promote short strings in
combination with format!"%s" and
output ranges.

How will this feature work at CT.
Format doesn't even work completely at CT.

I know this goes a bit off topic,
but IMO this is a feature that is wanted,
because other languages have it.
And we want to say we have it too.
I think it's a lot nicer to say, we don't need this, because our 
templates
can already do that.

TL/DR: not a fan
Dec 11 2019
next sibling parent reply Meta <jared771 gmail.com> writes:
On Wednesday, 11 December 2019 at 18:58:46 UTC, Robert Schadek 
wrote:
 I'm not really sure if the balance of added complexity vs. 
 payoff is in favor of payoff.
 They only time I felt the need for such a feature was when I 
 had very long DelimitedStrings.
 And those long strings where a constant source bugs, so I split 
 them up and the field need for interpolated strings want away 
 with the bugs.

 Not being able to use * will stop me using this feature in many 
 places.


 The rationale about "missing arguments, wrong format 
 specifier,... " Is a mute point IMO. format!"%d"(13.37) does 
 the same thing already without any language change.
 I thought the idea was not to introduce language changes if a 
 library solution can do most of it already.
 I find that the readability argument is highly subjective.
 The first part of the rationale is, IHO,
 already pointing to the solution. Short strings are easy to 
 manage.
 So let's promote short strings in
 combination with format!"%s" and
 output ranges.

 How will this feature work at CT.
 Format doesn't even work completely at CT.

 I know this goes a bit off topic,
 but IMO this is a feature that is wanted,
 because other languages have it.
 And we want to say we have it too.
 I think it's a lot nicer to say, we don't need this, because 
 our templates
 can already do that.

 TL/DR: not a fan
It can *almost* already be done with templates: https://github.com/Abscissa/scriptlike#string-interpolation The main sticking point is that you have to write mixin(interp!"....") so the symbols will be looked up in the proper scope. Unfortunately, that also means that the above syntax is the best a library solution can do, currently.
Dec 11 2019
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 19:15:18 UTC, Meta wrote:
 The main sticking point is that you have to write 
 mixin(interp!"....") so the symbols will be looked up in the 
 proper scope. Unfortunately, that also means that the above 
 syntax is the best a library solution can do, currently.
Maybe "mixin" could be a return type requiring CTFE and re-evaluated in the calling context? A bit dangerous perhaps.
Dec 11 2019
parent reply Meta <jared771 gmail.com> writes:
On Wednesday, 11 December 2019 at 20:28:21 UTC, Ola Fosheim 
Grøstad wrote:
 On Wednesday, 11 December 2019 at 19:15:18 UTC, Meta wrote:
 The main sticking point is that you have to write 
 mixin(interp!"....") so the symbols will be looked up in the 
 proper scope. Unfortunately, that also means that the above 
 syntax is the best a library solution can do, currently.
Maybe "mixin" could be a return type requiring CTFE and re-evaluated in the calling context? A bit dangerous perhaps.
Yeah, I think if it comes down to adding a new language feature to the compiler, or changing how mixins behave in such a way that may be cause for security concerns, it's less costly to add the language feature. Really, though, all that's needed is to allow mixin templates to be mixed in without using the `mixin` keyword (I say "all", but that's quite a large language change): string interp(string s)() { .... } mixin template i(string s) { enum i = mixin(interp!s); } auto n = 2, m = 5; auto s = i!"The product of ${n} and ${m} is ${n * m}"; writefln(s);
Dec 11 2019
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 20:46:03 UTC, Meta wrote:
 Really, though, all that's needed is to allow mixin templates 
 to be mixed in without using the `mixin` keyword (I say "all", 
 but that's quite a large language change):
Could one option be to use another symbol than «!» and make it imply the mixin? … f = some_formatter_that_builds_a_string …; immutable s = f!!"My name is {this.name}";
Dec 11 2019
parent reply Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Wednesday, 11 December 2019 at 20:57:35 UTC, Ola Fosheim 
Grøstad wrote:
 On Wednesday, 11 December 2019 at 20:46:03 UTC, Meta wrote:
 Really, though, all that's needed is to allow mixin templates 
 to be mixed in without using the `mixin` keyword (I say "all", 
 but that's quite a large language change):
Could one option be to use another symbol than «!» and make it imply the mixin? … f = some_formatter_that_builds_a_string …; immutable s = f!!"My name is {this.name}";
I like this. A universal improvement that also happens to enable all kinds of string interpolation, including SQL. Bastiaan.
Dec 11 2019
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 23:17:37 UTC, Bastiaan Veelo 
wrote:
 On Wednesday, 11 December 2019 at 20:57:35 UTC, Ola Fosheim 
 Grøstad wrote:
 immutable s = f!!"My name is {this.name}";
I like this. A universal improvement that also happens to enable all kinds of string interpolation, including SQL.
Another option is to add unicode support: fmt«I am {name}!» ==> mixin(fmt!"I am {name}!") (on my mac I get those symbols by hitting alt-shift-v and alt-shift-b)
Dec 11 2019
prev sibling parent reply Ernesto Castellotti <erny.castell gmail.com> writes:
On Wednesday, 11 December 2019 at 20:46:03 UTC, Meta wrote:
 On Wednesday, 11 December 2019 at 20:28:21 UTC, Ola Fosheim 
 Grøstad wrote:
 [...]
Yeah, I think if it comes down to adding a new language feature to the compiler, or changing how mixins behave in such a way that may be cause for security concerns, it's less costly to add the language feature. Really, though, all that's needed is to allow mixin templates to be mixed in without using the `mixin` keyword (I say "all", but that's quite a large language change): string interp(string s)() { .... } mixin template i(string s) { enum i = mixin(interp!s); } auto n = 2, m = 5; auto s = i!"The product of ${n} and ${m} is ${n * m}"; writefln(s);
This would be really cool
Dec 11 2019
next sibling parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 12 December 2019 at 06:47:28 UTC, Ernesto 
Castellotti wrote:
 On Wednesday, 11 December 2019 at 20:46:03 UTC, Meta wrote:
 Really, though, all that's needed is to allow mixin templates 
 to be mixed in without using the `mixin` keyword (I say "all", 
 but that's quite a large language change):

 string interp(string s)()
 {
     ....
 }

 mixin template i(string s)
 {
     enum i = mixin(interp!s);
 }

 auto n = 2, m = 5;
 auto s = i!"The product of ${n} and ${m} is ${n * m}";
 writefln(s);
This would be really cool
One idea I've seen floated in a previous thread is to introduce a new unary operator that could take the place of the "mixin" keyword. So instead of auto s = mixin(interp!"My ${vehicle} is full of ${creature}s!"); you could instead write something like this: auto s = interp!"My ${vehicle} is full of ${creature}s!";
Dec 11 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 10:47 PM, Ernesto Castellotti wrote:
 This would be really cool
I tried that (the enum in template trick). It's close, but still no banana.
Dec 14 2019
prev sibling next sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 11 December 2019 at 18:58:46 UTC, Robert Schadek 
wrote:
 I'm not really sure if the balance of added complexity vs. 
 payoff is in favor of payoff.
Disagree. This proposition strikes exactly the right balance would agree with you. This proposition though is just a simple composition of the existing C heritage and the availaible D feature (tuple).
 They only time I felt the need for such a feature was when I 
 had very long DelimitedStrings.
 And those long strings where a constant source bugs, so I split 
 them up and the field need for interpolated strings want away 
 with the bugs.
So you complexified your code because of a restriction of the language.
 Not being able to use * will stop me using this feature in many 
 places.


 The rationale about "missing arguments, wrong format 
 specifier,... " Is a mute point IMO. format!"%d"(13.37) does
MOOT not mute
 the same thing already without any language change.
 I thought the idea was not to introduce language changes if a 
 library solution can do most of it already.
 I find that the readability argument is highly subjective.
It is but it is also true that from more than 4 parameters in a format string it gets more and more noisy.
 The first part of the rationale is, IHO,
 already pointing to the solution. Short strings are easy to 
 manage.
 So let's promote short strings in
 combination with format!"%s" and
 output ranges.

 How will this feature work at CT.
 Format doesn't even work completely at CT.
It's a problem with format and is perpendicular to this DIP, i.e. if this DIP is adopted or not, it will not change anything to the issues of format.
 I know this goes a bit off topic,
 but IMO this is a feature that is wanted,
 because other languages have it.
 And we want to say we have it too.
May be sometimes it is good to look why certain features are spreading like wildfire. C format specifiers were a regression compared to what was available at that time (in Pascal or even Cobol), but as C had so much other things to it, people tended to accept the strange and ugly printf formatting, but it's clear that i was universally loathed. That's why C++ tried this worse shift syntax and other languages tried other solutions. It is not because we in the end managed to get used to the outdated and dangerous printf format that it is good in the first place. This DIP is simple enough that it is a good candidate imho to be tried.
 I think it's a lot nicer to say, we don't need this, because 
 our templates
 can already do that.
Dec 11 2019
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 11 December 2019 at 19:34:01 UTC, Patrick Schluter 
wrote:
 Cobol), but as C had so much other things to it, people tended 
 to accept the strange and ugly printf formatting, but it's 
 clear that i was universally loathed. That's why C++ tried this 
 worse shift syntax and other languages tried other solutions.
 It is not because we in the end managed to get used to the 
 outdated and dangerous printf format that it is good in the 
 first place.
 This DIP is simple enough that it is a good candidate imho to 
 be tried.
If something is bad… (…and I agree, printf is not good.) Why would you embrace it by making it part of the language? Currently it only part of a library and can be phased out. Make it part of the language and you'll be stuck with it. Creating a better solution and create a wrapper for printf and other C-APIs would be the better approach. Otherwise you'll end up with another interpolated string version... down the road. How many string-literals can a language handle?
Dec 11 2019
prev sibling parent Robert burner Schadek <rburners gmail.com> writes:
On Wednesday, 11 December 2019 at 19:34:01 UTC, Patrick Schluter 
wrote:
 So you complexified your code because of a restriction of the 
 language.
Not at all, before I was trying to do to much. With multiple format calls, I made the code boring and easy to follow.
 Not being able to use * will stop me using this feature in 
 many places.


 The rationale about "missing arguments, wrong format 
 specifier,... " Is a mute point IMO. format!"%d"(13.37) does
MOOT not mute
 the same thing already without any language change.
 I thought the idea was not to introduce language changes if a 
 library solution can do most of it already.
 I find that the readability argument is highly subjective.
It is but it is also true that from more than 4 parameters in a format string it gets more and more noisy.
True, so you would split up the code, right!? If both format styles don't work with more than x arguments, why do I need to styles to not get the work done. One is enough to shoot myself in the foot, isn't it.
 The first part of the rationale is, IHO,
 already pointing to the solution. Short strings are easy to 
 manage.
 So let's promote short strings in
 combination with format!"%s" and
 output ranges.

 How will this feature work at CT.
 Format doesn't even work completely at CT.
It's a problem with format and is perpendicular to this DIP, i.e. if this DIP is adopted or not, it will not change anything to the issues of format.
Why do we need it then?
 I know this goes a bit off topic,
 but IMO this is a feature that is wanted,
 because other languages have it.
 And we want to say we have it too.
May be sometimes it is good to look why certain features are spreading like wildfire. C format specifiers were a regression compared to what was available at that time (in Pascal or even Cobol), but as C had so much other things to it, people tended to accept the strange and ugly printf formatting, but it's clear that i was universally loathed. That's why C++ tried this worse shift syntax and other languages tried other solutions. It is not because we in the end managed to get used to the outdated and dangerous printf format that it is good in the first place. This DIP is simple enough that it is a good candidate imho to be tried.
format!""() is not dangerous, if it is please show me why, I use it all over the place. I'm also not sure why it is outdated, format is very flexible and powerful, i.e. array formatting is just awesome.
Dec 11 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 10:58 AM, Robert Schadek wrote:
 Not being able to use * will stop me using this feature in many places.
That's right. I have a fix for that!
 I thought the idea was not to introduce language changes if a library solution 
 can do most of it already.
I tried. It just doesn't get us there without some awkward syntax.
 TL/DR: not a fan
A reasonable point of view. D works fine without interpolated strings. This also motivated the design to stick to something as simple as possible - just a dash of syntactic sugar.
Dec 14 2019
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Dec 11, 2019 at 09:52:21AM +0000, Mike Parker via Digitalmars-d wrote:
 This is the feedback thread for the first round of Community Review
 for DIP 1027, "String Interpolation":
 
 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
[...] 1) The way this DIP is worded belies its true power, which I suspect some people are unaware of. Part of this is because the writefln/printf example chosen for the Description section makes it appear as though this DIP is only about writefln or printf formatting. It would be nice(r) if the DIP included a section describing use cases outside of writefln. For example: readable yet type-safe database query formatting: by writing a format string parser that turns '%x' into '?' and generates SQL bind commands for the corresponding arguments: string table = "mytable"; string key = "key-that!needs'escap1ng"; double value = 3.14159; int index = 12345; DateTime lastTime = getCurDate(); database.exec(i"UPDATE %table SET key=%key, value=%{f}value WHERE index < %{d}index AND timestamp > %{D}lastTime"); (Note that '%D' is not a writefln-supported format, presumably it's something database.exec() understands.) 2) The previous example does bring up another issue: is there a nice way to handle long interpolated strings, i.e., wrap long interpolated strings to multiple lines? I.e., does the following work? database.exec(i"UPDATE %table SET key=%key, value=%{f}value "~ "WHERE index < %{d}index AND "~ "timestamp > %{D}lastTime"); If not, is there an alternative? One of the key arguments of the DIP is that traditional format strings become unwieldy when the length increases and the number of arguments increases. But how does the proposed interpolated string syntax mitigate the very same problems in its own syntax? 3) Someone has already pointed out the problem of interpreting %% as %, because: double grade = 89.5; writefln(i"Your grade is %{.2f}grade%%."); gets turned into: double grade = 89.5; writefln("Your grade is %.2f%.", grade); Note the dangling % at the end, which will writefln to throw an error. Under the current syntax, you'd have to write "%%%%" to get a single '%' in the writefln output, which seems excessive. Counterproposal: %% should be copied literally as %% in the output. T -- PNP = Plug 'N' Pray
Dec 11 2019
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 11:33 AM, H. S. Teoh wrote:
 2) The previous example does bring up another issue: is there a nice way
 to handle long interpolated strings, i.e., wrap long interpolated
 strings to multiple lines?  I.e., does the following work?
 
 	database.exec(i"UPDATE %table SET key=%key, value=%{f}value "~
 			"WHERE index < %{d}index AND "~
 			"timestamp > %{D}lastTime");
No. The trouble happens with how semantic analysis is done - leaves first, then non-leaves. It's just the wrong order to make the concatenation make sense. I've thought about this for the last week. The most practical idea is to simply concatenate adjacent strings, as in: database.exec(i"UPDATE %table SET key=%key, value=%{f}value " "WHERE index < %{d}index AND " "timestamp > %{D}lastTime"); I.e. the 'i' string comes first, and gets concatenated with any following string literals. This also enables using 'q' strings as interpolated strings: i"" q{a + b}
Dec 14 2019
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2019-12-14 09:36, Walter Bright wrote:

 I've thought about this for the last week. The most practical idea is to 
 simply concatenate adjacent strings, as in:
 
    database.exec(i"UPDATE %table SET key=%key, value=%{f}value "
                    "WHERE index < %{d}index AND "
                    "timestamp > %{D}lastTime");
 
 I.e. the 'i' string comes first, and gets concatenated with any 
 following string literals. This also enables using 'q' strings as 
 interpolated strings:
 
      i"" q{a + b}
Implicit string concatenation is deprecated and gives an error. -- /Jacob Carlborg
Dec 14 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/14/2019 5:34 AM, Jacob Carlborg wrote:
 Implicit string concatenation is deprecated and gives an error.
I know. But i strings aren't string literals, and this would be special cased for that. And I wouldn't have proposed that if ~ would work, but it does not work for this.
Dec 14 2019
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/14/19 3:36 AM, Walter Bright wrote:
 On 12/11/2019 11:33 AM, H. S. Teoh wrote:
 2) The previous example does bring up another issue: is there a nice way
 to handle long interpolated strings, i.e., wrap long interpolated
 strings to multiple lines?  I.e., does the following work?

     database.exec(i"UPDATE %table SET key=%key, value=%{f}value "~
             "WHERE index < %{d}index AND "~
             "timestamp > %{D}lastTime");
No. The trouble happens with how semantic analysis is done - leaves first, then non-leaves. It's just the wrong order to make the concatenation make sense.
What if the strings are all interpolated strings? e.g.: database.exec(i"UPDATE %table SET key=$key, value=${f}value "~ i"WHERE index < ${d}index AND "~ i"timestamp > ${D}lastTime"); I don't know enough about the grammar/implementation to know if this makes more sense or not.
 
 I've thought about this for the last week. The most practical idea is to 
 simply concatenate adjacent strings, as in:
 
    database.exec(i"UPDATE %table SET key=%key, value=%{f}value "
                    "WHERE index < %{d}index AND "
                    "timestamp > %{D}lastTime");
But we deprecated that because it's too error prone.
 I.e. the 'i' string comes first, and gets concatenated with any 
 following string literals. This also enables using 'q' strings as 
 interpolated strings:
 
      i"" q{a + b}
I actually think 'i' should be able to go before any string literal. e.g.: iq{$a + $b} i`$a + $b` Just like suffixes can be applied to any string literal to alter the width. -Steve
Dec 14 2019
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/14/2019 6:47 AM, Steven Schveighoffer wrote:
 What if the strings are all interpolated strings? e.g.:
 
 database.exec(i"UPDATE %table SET key=$key, value=${f}value "~
              i"WHERE index < ${d}index AND "~
              i"timestamp > ${D}lastTime");
Then you'll get a tuple that looks like: "UPDATE %s SET key=%s, value=%f ", key, value, "WHERE index < %d AND ", index, "timestamp > %D", lastTime which won't work for printf or writefln.
 I actually think 'i' should be able to go before any string literal.
 e.g.:
 
 iq{$a + $b}
 i`$a + $b`
Since the other method works, I am striving to keep things as simple as possible. There needs to be very good reasons for gratuitous multiple ways of doing something, and I don't see one here. Of course, then there's "what about qi strings", aaggghhhh.
Dec 14 2019
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/14/19 8:21 PM, Walter Bright wrote:
 On 12/14/2019 6:47 AM, Steven Schveighoffer wrote:
 What if the strings are all interpolated strings? e.g.:

 database.exec(i"UPDATE %table SET key=$key, value=${f}value "~
              i"WHERE index < ${d}index AND "~
              i"timestamp > ${D}lastTime");
Then you'll get a tuple that looks like:     "UPDATE %s SET key=%s, value=%f ", key, value, "WHERE index < %d AND ", index, "timestamp > %D", lastTime
Why? I mean concatenation of Tuples isn't defined to do anything. pragma(msg, AliasSeq!("hello", "there") ~ AliasSeq!("world", "and everyone else")); Error: incompatible types for (tuple("hello", "there")) ~ (tuple("world", "and everyone else")): both operands are of type (string, string) But we could define it for interpolated string tuples to be the concatenation of the format strings followed by the AliasSeq of all the fields in order. This is the time to make these decisions, because it will be hard to add later. Removing automatic string concatenation was a great addition, but took a long time to get into the language, due to not breaking existing code. I'd hate to have to do it again.
 I actually think 'i' should be able to go before any string literal.
 e.g.:

 iq{$a + $b}
 i`$a + $b`
Since the other method works, I am striving to keep things as simple as possible. There needs to be very good reasons for gratuitous multiple ways of doing something, and I don't see one here.
I'm proposing you DON'T make the other method work (it doesn't now). There doesn't need to be multiple ways to do string literals. And in fact, concatenation of interpolated string literals (as proposed above) would work well to provide the most expressive power, as you could concatenate any style of interpolated literals together, just like you can for uninterpolated literals. And it's not complicated. The postfix characters of `c`, `w`, and `d` do not warrant complicated explanations in the spec, and are usable on any of the string literal types. An `i` prefix is similar. All that is needed is to say "if you put `i` in front of a string literal (any string literal) it becomes an interpolated string literal"
 Of course, then 
 there's "what about qi strings", aaggghhhh.
That's not grammatically correct. It would be rejected. The "interpolated" property is orthogonal to the string literal method, and must come before it. -Steve
Dec 16 2019
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/16/2019 9:31 AM, Steven Schveighoffer wrote:
 Why? I mean concatenation of Tuples isn't defined to do anything.
I did concatenate the tuples in the most obvious manner - concatenating them. It produces an unusable result.
 But we could define it for interpolated string tuples to be the concatenation
of 
 the format strings followed by the AliasSeq of all the fields in order.
Yes, we could, and then tuple concatenation would be useless for any other use of tuple concatenation.
 This is the time to make these decisions, because it will be hard to add
later. 
 Removing automatic string concatenation was a great addition, but took a long 
 time to get into the language, due to not breaking existing code. I'd hate to 
 have to do it again.
There isn't a better way - and it won't be string concatenation. It'll be interpolated string concatenation, as interpolated strings are not strings at all.
 Since the other method works, I am striving to keep things as simple as 
 possible. There needs to be very good reasons for gratuitous multiple ways of 
 doing something, and I don't see one here.
I'm proposing you DON'T make the other method work (it doesn't now).
It works in the PR I've submitted for this DIP.
 And it's not complicated.
I know supporting iq tokens is not complicated. It's just unnecessary. We can always add it later as necessary without breaking things.
 Of course, then there's "what about qi strings", aaggghhhh.
That's not grammatically correct. It would be rejected. The "interpolated" property is orthogonal to the string literal method, and must come before it.
D supports u, Lu, uL, U, UL, LU integer literals because I was stupid. At least `l` is not allowed.
Dec 17 2019
parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Tuesday, 17 December 2019 at 09:13:52 UTC, Walter Bright wrote:
 On 12/16/2019 9:31 AM, Steven Schveighoffer wrote:
 I know supporting iq tokens is not complicated. It's just 
 unnecessary. We can always add it later as necessary without 
 breaking things.
Well they would be a tremendous addition for metaprogramming facilities that are using mixins, since they will increase by a lot mixin code readability. Best regards, Alexandru.
Dec 17 2019
prev sibling parent Meta <jared771 gmail.com> writes:
On Saturday, 14 December 2019 at 08:36:15 UTC, Walter Bright 
wrote:
 On 12/11/2019 11:33 AM, H. S. Teoh wrote:
 2) The previous example does bring up another issue: is there 
 a nice way
 to handle long interpolated strings, i.e., wrap long 
 interpolated
 strings to multiple lines?  I.e., does the following work?
 
 	database.exec(i"UPDATE %table SET key=%key, value=%{f}value "~
 			"WHERE index < %{d}index AND "~
 			"timestamp > %{D}lastTime");
No. The trouble happens with how semantic analysis is done - leaves first, then non-leaves. It's just the wrong order to make the concatenation make sense. I've thought about this for the last week. The most practical idea is to simply concatenate adjacent strings, as in: database.exec(i"UPDATE %table SET key=%key, value=%{f}value " "WHERE index < %{d}index AND " "timestamp > %{D}lastTime"); I.e. the 'i' string comes first, and gets concatenated with any following string literals. This also enables using 'q' strings as interpolated strings: i"" q{a + b}
One thing to note is that if string interpolation returns a struct like Adam proposed, concatenation would be possible between interpolated strings.
Dec 14 2019
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/11/19 4:52 AM, Mike Parker wrote:
 This is the feedback thread for the first round of Community Review for 
 DIP 1027, "String Interpolation":
 
 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372
0bc/DIPs/DIP1027.md 
 
 
 All review-related feedback on and discussion of the DIP should occur in 
 this thread. The review period will end at 11:59 PM ET on December 25, 
 or when I make a post declaring it complete.
 
 At the end of Round 1, if further review is deemed necessary, the DIP 
 will be scheduled for another round of Community Review. Otherwise, it 
 will be queued for the Final Review and Formal Assessment.
 
 Anyone intending to post feedback in this thread is expected to be 
 familiar with the reviewer guidelines:
 
 https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md
 
 *Please stay on topic!*
 
 Thanks in advance to all who participate.
First, I like the concept. It fixes the issue of "which parameters are string literals and which are variables?" issue of the straight lower-to-tuple design. But there are a couple problems. This is very much focused on writef and printf. What about other functions that accept similar string + arg tuple, but don't use %s specifiers? Perfect example is SQL: query("select * from sometable where date < ?", someDate); With the interpolation string: query(i"select * from sometable where date < %someDate"); This translates to: query("select * from sometable where date < %s", someDate); which is not correct SQL syntax. This means I have to create a separate function that accepts interpolated strings (can't be the same name because it would be the same parameters for overloading!) and inside that function, I need to TRANSLATE the formatted string into something sql can understand. Not only that, but I have to do it at runtime, since query accepts a string as a runtime parameter. Not only that, but this doesn't provide a mechanism to hook compile-time format strings at all, even though the format string is known at compile-time. The other problem is that you are using % for the interpolated fields. This is quite puzzling, considering that the main target (printf and writef) uses % as the format specifier. Why not just change the specifier to $ or {} or \() or \{} or literally any of the other interpolation systems out there. Then you don't need the %%%% mentioned elsewhere to make one percentage sign. If we can think of a way to hook the string generation and have the parameters come afterwards, that would be ideal. For example, if you lowered (and I'm going to use a better format specifier here): i"I ate \({d}apples) and \(bananas) totaling \(apples + bananas) fruit." to InterpStr!("I ate ", FormatSpec!("d"), " and ", FormatSpec!(""), " totaling ", FormatSpec!(""), " fruit."), apples, bananas, apples + bananas Where InterpStr and FormatSpec were defined by the library to be whatever Druntime specified, then you could handle any cases, and provide the most . For example, writef could accept the type as the first parameter, and translate easily into a standard writef call, or avoid having to parse the format specifiers all together! This wouldn't work with printf. But I'm not so sure that's a huge problem. One could easily wrap printf in something D-ish. Again, like the concept, but it's too narrowly focused on printf and writef. -Steve
Dec 11 2019
next sibling parent reply Andrea Fontana <nospam example.org> writes:
On Wednesday, 11 December 2019 at 20:38:49 UTC, Steven 
Schveighoffer wrote:
 This is very much focused on writef and printf. What about 
 other functions that accept similar string + arg tuple, but 
 don't use %s specifiers? Perfect example is SQL:

 query("select * from sometable where date < ?", someDate);

 With the interpolation string:

 query(i"select * from sometable where date < %someDate");

 This translates to:

 query("select * from sometable where date < %s", someDate);

 
query(i"select * from sometable where date < %someDate".format);
Dec 11 2019
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/11/19 3:59 PM, Andrea Fontana wrote:
 On Wednesday, 11 December 2019 at 20:38:49 UTC, Steven Schveighoffer wrote:
 This is very much focused on writef and printf. What about other 
 functions that accept similar string + arg tuple, but don't use %s 
 specifiers? Perfect example is SQL:

 query("select * from sometable where date < ?", someDate);

 With the interpolation string:

 query(i"select * from sometable where date < %someDate");

 This translates to:

 query("select * from sometable where date < %s", someDate);
query(i"select * from sometable where date < %someDate".format);
https://en.wikipedia.org/wiki/SQL_injection Besides, this is bad for performance, you are translating a type to a string, just to send it to the server, to have it translate it back into the type. Sending the type directly is much more efficient. What I want is what I first typed, just in a nicer format. D has such great power at translating code, it should be able to do this. I don't see why we would settle for something that basically is a "nicer" writef or format when it could be used everywhere. -Steve
Dec 11 2019
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Dec 11, 2019 at 03:38:49PM -0500, Steven Schveighoffer via
Digitalmars-d wrote:
[...]
 But there are a couple problems.
 
 This is very much focused on writef and printf. What about other
 functions that accept similar string + arg tuple, but don't use %s
 specifiers? Perfect example is SQL:
 
 query("select * from sometable where date < ?", someDate);
 
 With the interpolation string:
 
 query(i"select * from sometable where date < %someDate");
 
 This translates to:
 
 query("select * from sometable where date < %s", someDate);
 
 which is not correct SQL syntax.
[...] Here's a potential 2-step fix: 1) Change the interpretation of `%({X}varname)` to mean "use `X` instead of %s as placeholder in output string", rather than "use `%X` ...". I.e.: i"%abc" == tuple("%s", abc); i"%({%x}abc)" == tuple("%x", abc); i"%({?}abc)" == tuple("?", abc); // bingo, SQL syntax! 2) Then, in light of the %%%% problem, and to fix the repeated % in "%{%x}abc", change the default metacharacter to something like $: i"$abc" == tuple("%s", abc); i"$({%d}abc)" == tuple("%d", abc); i"$({?}abc)" == tuple("?", abc); For convenient interop with printf/writefln, we can still default to "%s" as the default placeholder, but the {} syntax now no longer assumes printf syntax, making i"" literals MUCH more useful in many more places outside the purvey of printf/writefln. So you'd do SQL strings like this: string name; int serial; float cost; db.exec(i"INSERT INTO mytable VALUES (${?}name, ${?}serial, ${?}cost)"); which translates the last line to: db.exec("INSERT INTO mytable VALUES (?, ?, ?)", name, serial, cost); without the need for any intermediate format string parser. T -- VI = Visual Irritation
Dec 11 2019
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/11/19 5:37 PM, H. S. Teoh wrote:
 Here's a potential 2-step fix:
 
 1) Change the interpretation of `%({X}varname)` to mean "use `X` instead
 of %s as placeholder in output string", rather than "use `%X` ...".
 I.e.:
 
 	i"%abc"		== tuple("%s", abc);
 	i"%({%x}abc)"	== tuple("%x", abc);
 	i"%({?}abc)"	== tuple("?", abc); // bingo, SQL syntax!
 
 2) Then, in light of the %%%% problem, and to fix the repeated % in
 "%{%x}abc", change the default metacharacter to something like $:
 
 	i"$abc"		== tuple("%s", abc);
 	i"$({%d}abc)"	== tuple("%d", abc);
 	i"$({?}abc)"	== tuple("?", abc);
 
 For convenient interop with printf/writefln, we can still default to
 "%s" as the default placeholder, but the {} syntax now no longer assumes
 printf syntax, making i"" literals MUCH more useful in many more places
 outside the purvey of printf/writefln.
 
 So you'd do SQL strings like this:
 
 	string name;
 	int serial;
 	float cost;
 	db.exec(i"INSERT INTO mytable VALUES (${?}name, ${?}serial, ${?}cost)");
 
 which translates the last line to:
 
 	db.exec("INSERT INTO mytable VALUES (?, ?, ?)", name, serial, cost);
 
 without the need for any intermediate format string parser.
OK, this is definitely a winner, way better than my idea. Only thing better would be some way to set the default specifier to avoid all the verbosity. Please make this part of the DIP Walter! -Steve
Dec 11 2019
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/11/19 5:49 PM, Steven Schveighoffer wrote:

 OK, this is definitely a winner, way better than my idea. Only thing 
 better would be some way to set the default specifier to avoid all the 
 verbosity.
Hm... heredoc gives us a precedent that might be valuable here. e.g.: db.exec(i"{?}INSERT INTO mytable VALUES ($name, $serial, $cost)") printf(i"{%d}I ate $apples and $bananas totaling $(apples + bananas) fruit.\n"); -Steve
Dec 11 2019
parent reply =?iso-8859-1?Q?Robert_M._M=FCnch?= <robert.muench saphirion.com> writes:
On 2019-12-11 22:55:22 +0000, Steven Schveighoffer said:

 On 12/11/19 5:49 PM, Steven Schveighoffer wrote:
 
 OK, this is definitely a winner, way better than my idea. Only thing 
 better would be some way to set the default specifier to avoid all the 
 verbosity.
Hm... heredoc gives us a precedent that might be valuable here. e.g.: db.exec(i"{?}INSERT INTO mytable VALUES ($name, $serial, $cost)") printf(i"{%d}I ate $apples and $bananas totaling $(apples + bananas) fruit.\n"); -Steve
Yes, much better to reduce syntax-cluttering. Why not lean towards existing syntax from templates: i(?)"INSERT INTO mytable VALUES ($name, $serial, $cost)" or even make it more configurable to catch more cases: i($,?)"INSERT INTO mytable VALUES ($name, $serial, $cost)" By provding a standard case, where the printf relevant type is automatically deduced from the used variables, when no specification is given the syntax would be simple in a lot of cases: i"I ate $apples and $bananas totaling $(apples + bananas) fruit.\n" -- Robert M. Mnch http://www.saphirion.com smarter | better | faster
Dec 13 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/13/2019 1:17 AM, Robert M. Münch wrote:
 Yes, much better to reduce syntax-cluttering. Why not lean towards existing 
 syntax from templates:
 
 i(?)"INSERT INTO mytable VALUES ($name, $serial, $cost)"
 
 or even make it more configurable to catch more cases:
 
 i($,?)"INSERT INTO mytable VALUES ($name, $serial, $cost)"

 

Too complex for too little gain.
Dec 14 2019
prev sibling next sibling parent reply Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Wednesday, 11 December 2019 at 22:49:01 UTC, Steven 
Schveighoffer wrote:
 On 12/11/19 5:37 PM, H. S. Teoh wrote:
[…]
 	i"$abc"		== tuple("%s", abc);
 	i"$({%d}abc)"	== tuple("%d", abc);
 	i"$({?}abc)"	== tuple("?", abc);
 
 For convenient interop with printf/writefln, we can still 
 default to
 "%s" as the default placeholder, but the {} syntax now no 
 longer assumes
 printf syntax, making i"" literals MUCH more useful in many 
 more places
 outside the purvey of printf/writefln.
 
 So you'd do SQL strings like this:
 
 	string name;
 	int serial;
 	float cost;
 	db.exec(i"INSERT INTO mytable VALUES (${?}name, ${?}serial, 
 ${?}cost)");
 
 which translates the last line to:
 
 	db.exec("INSERT INTO mytable VALUES (?, ?, ?)", name, serial, 
 cost);
 
 without the need for any intermediate format string parser.
OK, this is definitely a winner, way better than my idea. Only thing better would be some way to set the default specifier to avoid all the verbosity. Please make this part of the DIP Walter!
Isn’t https://forum.dlang.org/post/vxzqttydlvzngrwrvipa forum.dlang.org better still? Streamlining template mixins could pay off in many more places, and is truly extendable and customisable. Bastiaan
Dec 11 2019
parent Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Wednesday, 11 December 2019 at 23:09:01 UTC, Bastiaan Veelo 
wrote:
 Isn’t 
 https://forum.dlang.org/post/vxzqttydlvzngrwrvipa forum.dlang.org better
still? Streamlining template mixins could pay off in many more places, and is
truly extendable and customisable.
Seems I’m mixing up template and string mixins.
Dec 11 2019
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 2:49 PM, Steven Schveighoffer wrote:
 Only thing better 
 would be some way to set the default specifier to avoid all the verbosity.
Since that would require some extra syntax for each i string literal, it's not worth it.
Dec 14 2019
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/14/19 3:56 AM, Walter Bright wrote:
 On 12/11/2019 2:49 PM, Steven Schveighoffer wrote:
 Only thing better would be some way to set the default specifier to 
 avoid all the verbosity.
Since that would require some extra syntax for each i string literal, it's not worth it.
It doesn't actually i"$apples and $bananas" would still work. The default specifier is optional, just like format specifier parameters e.g. %02x have an optional 02. The only time extra syntax would be required is if you start with a brace and want to keep the default. i`{"name" : $name}`.format; // JSON interpolated object. This would result in a confusion because of the initial brace. (I'm assuming here that we can use all the different quote types for convenience) BUT 1. You can just do i`{}{"name": $name}`.format; i` {"name": $name}`.format; // taking advantage of the JSON grammar. i`{%s}{"name": $name}`.format; // respecify default 2. Or if we have your proposal of allowing string concatenation (I'll respond to that separately), then (i"{}" `{"name": $name}`).format should work, and doesn't look terrible. Normally an interpolated string will not have any need for the default alteration, and you won't notice it. I have some SQL strings with 10 or more fields, which would be super-verbose to continually put {?} or to maybe forget one! If there is a better default specifier sequence that you would accept, that would be fine too. -Steve
Dec 14 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/14/2019 6:36 AM, Steven Schveighoffer wrote:
 [...]
It wouldn't be used enough to make it worthwhile. The extra syntax necessary also requires yet another means to distinguish it from the rest of the string.
Dec 14 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 2:37 PM, H. S. Teoh wrote:
 1) Change the interpretation of `%({X}varname)` to mean "use `X` instead
 of %s as placeholder in output string", rather than "use `%X` ...".
 I.e.:
 
 	i"%abc"		== tuple("%s", abc);
 	i"%({%x}abc)"	== tuple("%x", abc);
 	i"%({?}abc)"	== tuple("?", abc); // bingo, SQL syntax!
 
 2) Then, in light of the %%%% problem, and to fix the repeated % in
 "%{%x}abc", change the default metacharacter to something like $:
 
 	i"$abc"		== tuple("%s", abc);
 	i"$({%d}abc)"	== tuple("%d", abc);
 	i"$({?}abc)"	== tuple("?", abc);
I agree, except don't need the extra ( ).
Dec 14 2019
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 12:38 PM, Steven Schveighoffer wrote:
 This is very much focused on writef and printf. What about other functions
that 
 accept similar string + arg tuple, but don't use %s specifiers? Perfect
example 
 is SQL:
 
 query("select * from sometable where date < ?", someDate);
 
 With the interpolation string:
 
 query(i"select * from sometable where date < %someDate");
 
 This translates to:
 
 query("select * from sometable where date < %s", someDate);
 
 which is not correct SQL syntax.
It's a great point. I propose a modification: Change the `{FormatString}` from being a suffix to `%` to being the whole format string, i.e. instead of `%{d}` make it `%{%d}`. Then, your example becomes: query("select * from sometable where date < %{?}someDate"); which gets rewritten to: query("select * from sometable where date < ?", someDate); and voila, any format specifier can be used. Robert brought up an additional problem: printf("%.*s", length, ptr); as not being representable as an interpolated string. But this change will allow it to work: printf(i"%{%.*}length%{s}ptr"); The default format will remain `%s`, as I expect that will be the vast bulk of uses.
 The other problem is that you are using % for the interpolated fields. This is 
 quite puzzling, considering that the main target (printf and writef) uses % as 
 the format specifier. Why not just change the specifier to $ or {} or \() or
\{} 
 or literally any of the other interpolation systems out there.
I've decided to change it to $. That looks nice. The \ ones just look awful, and {} leaves open the problem of where to put the user-specified format.
 If we can think of a way to hook the string generation and have the parameters 
 come afterwards, that would be ideal.
Lowering it to a tuple is good enough. You can do whatever you wish with the resulting tuple (like pass it to a template).
Dec 14 2019
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/14/19 3:51 AM, Walter Bright wrote:

 It's a great point. I propose a modification:
 
 Change the `{FormatString}` from being a suffix to `%` to being the 
 whole format string, i.e. instead of `%{d}` make it `%{%d}`.
...
 
 I've decided to change it to $. That looks nice. The \ ones just look 
 awful, and  {} leaves open the problem of where to put the 
 user-specified format.
Thanks! That's much better -Steve
Dec 14 2019
prev sibling next sibling parent reply mipri <mipri minimaltype.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
Questions for the rationale: 1. Why % as a format character? I would guess "so that legacy strings won't accidentally trigger interpolation", but since this proposal already requires i"" syntax, legacy strings aren't a problem. Or "wanting to specify the formatting, as with %{d}bananas, meant I had to come up with something new anyway." But Nim, Zig, and Python all do this (the first two as normal library functionality rather than a language extension) with the {} syntax. import strformat let num = 123 Alternate syntax ({} interpolation): writefln(i"I ate {apples} and {bananas:d} totalling {apples + bananas} fruit."); 2. Why i"" syntax? It (presumably, not necessarily) conflicts with user string prefixes, and since this proposal already limits string interpolation to printf-style uses, and since the use of % format character already makes conflict with legacy strings already very unlikely, why not use regular string syntax but make writefln() and friends statically analyze the string they're given to see if it's an interpolating one or not? Alternate syntax (no i""; in(isTemplated!argstring)): writefln("I ate %apples and %{d}bananas totalling %(apples + bananas) fruit."); 3. Why rewrite to positional code? I would guess "because I don't want to add new GC-reliant features", but since this proposal already limits string interpolation to printf-style uses, the function accepting the string is an obvious owner. The positional rewrite has other problems: a. interpolated strings can't be mixed with conventional elements, a common and unremarkable thing for interpolation in other languages. b. functions that accept an interpolated string have to know that they do this, and have special handling for it, when in other languages the choice to interpolate is purely a decision of the caller's, and can be changed for readability or efficiency or taste. c. Speaking of efficiency: in other languages you can hoist a repeated use of an interpolated string above some loops that use it. With this proposal you'd have to rely on the optimizer to deal with this. 4. Seriously, why rewrite to positional code? This is going to function as something like an attractive nuisance for people that learn D. Newbie: "Hey, I want some interpolation here. Does D have that? Oh! It does!" Newbie: *uses interpolation, gets error* Newbie: "what?" Newbie: ... this D thing, it's filled with features with strange limitations. Features that don't work naturally together. Come on even a simple thing like string interpolation! That's convenient in every language that has it! Why is it so weird here? This is just like how the other day I tried to rewrite a trivial benchmark in -betterC and kept getting weird errors about TypeInfos. grumble grumble grumble. *** meanwhile, in a world without interpolation *** Newbie: "Hey, I want some interpolation here. Does D have that? ... looks like format() does what I want." Newbie: *uses format(), it works as expected, life moves on* -- Final "but since this proposal already" count: 3
Dec 11 2019
parent reply mipri <mipri minimaltype.com> writes:
On Wednesday, 11 December 2019 at 23:33:20 UTC, mipri wrote:
 This is going to function as something like an attractive
 nuisance for people that learn D.

 Newbie: "Hey, I want some interpolation here. Does D have that?
 Oh! It
 does!"

 Newbie: *uses interpolation, gets error*
I think there's a general rule here: A DIP that adds an innovative feature, or which enters poorly-explored design space, can be a conservative "80% solution" that has some caveats and limitations on its use, that people learning the language will need to learn to properly use the feature. But a DIP that adds a very well explored feature should provide a 100% solution that adds exactly what people will expect from "<feature name> in <any language>". It should do this precisely because people are so well-prepared in their expectations for any such feature. Suppose that D didn't have floating point numbers, and a DIP were released today to add them to the language, but instead of IEEE floating point, it implemented some novel thing. The details of the novel thing don't matter: it's not 100% what people want from "floating point", so it's an embarrassment. Think of how the documentation would have to read. dlang.org's own docs, to be useful, would have to explain the feature in terms of how it fails to meet the expectations of other languages. In code, this must all work: auto s1 = i"I ate %apples and %{d}bananas."; enum pears = "two"; enum s2 = i"I ate %pears."; immutable string s3 = i"%s1"; void takes_a_normal_string(string s) { } takes_a_normal_string(i"%one + %two = %(one + two)."); // not an error: writefln sees %d in the post-interpolation // string and works normally writefln(i"making %bread using %%d ingredients", 6); string x = qi"SPAM Hello %firstname %lastname! ... SPAM"; Although if i"" is definitely the syntax used, then the rest of the syntax is free to be something familiar like // resembles 14 languages from wikipedia examples i"$one + $two = ${one + two}" or // resembles 4 languages i"{one} + {two} = {one + two}" Finally, look at Swift's syntax: let apples = 4 print("I have \(apples) apples") How about that? Undefined escape sequences are an error, so new ones can be added without breaking the language or changing the meaning of old code. And this no longer requires an ugly 'i' prefix. If the "lower to printf-style arguments" is really what's wanted, then it could be an *option* with an alternate escape like \[apples], so people's expectations about string interpolation would still be met. A 100% solution + some extra features is a much easier sell.
Dec 11 2019
next sibling parent Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
On Thursday, 12 December 2019 at 07:30:19 UTC, mipri wrote:
 A DIP that adds an innovative feature, or which enters
 poorly-explored design space, can be a conservative "80%
 solution" that has some caveats and limitations on its use,
 that people learning the language will need to learn to
 properly use the feature.
Yes, the requirement should be that it has been implemented as a library mixin and has been popular in usage for a long time. Only then should new syntax be added for it.
Dec 12 2019
prev sibling next sibling parent aliak <something something.com> writes:
On Thursday, 12 December 2019 at 07:30:19 UTC, mipri wrote:

 How about that? Undefined escape sequences are an error, so
 new ones can be added without breaking the language or changing
 the meaning of old code. And this no longer requires an ugly
 'i' prefix.
That is a really good point! But, what about token strings? mixin(q{ auto ${functionName}() { return ${varName}; } });
Dec 12 2019
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 12 December 2019 at 07:30:19 UTC, mipri wrote:
 A DIP that adds an innovative feature
This could be an innovative feature. I see very little value in traditional string interpolation and I'd vote no on that. But these tuple ones are interesting and can do things unique to D... if we do it right.
 In code, this must all work:

   auto s1 = i"I ate %apples and %{d}bananas.";
If that works, you've lost my support. Note that with my proposal string s1 = i"I ate %apples and %{d}bananas."; could work though. auto and string are different - with string it can trigger `alias this`. but if it is just plain string given from the compiler, we've gained nothing of interest. Even javascript's interpolation has more metaprogramming potential than that. Do we want to lose to javascript? BTW the JS one is actually quite interesting. It calls a user-defined function, passing the arguments - similar to the D tuple thing.
Dec 12 2019
parent reply aliak <something something.com> writes:
On Thursday, 12 December 2019 at 13:36:38 UTC, Adam D. Ruppe 
wrote:
 BTW the JS one is actually quite interesting. It calls a 
 user-defined function, passing the arguments - similar to the D 
 tuple thing.
Except you can actually assign it to a string?
Dec 12 2019
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Dec 12, 2019 at 03:41:54PM +0000, aliak via Digitalmars-d wrote:
 On Thursday, 12 December 2019 at 13:36:38 UTC, Adam D. Ruppe wrote:
 BTW the JS one is actually quite interesting. It calls a
 user-defined function, passing the arguments - similar to the D
 tuple thing.
Except you can actually assign it to a string?
[...] As Adam already said, you can assign it to a string if the return type has alias this to string. T -- One reason that few people are aware there are programs running the internet is that they never crash in any significant way: the free software underlying the internet is reliable to the point of invisibility. -- Glyn Moody, from the article "Giving it all away"
Dec 12 2019
parent reply aliak <something something.com> writes:
On Thursday, 12 December 2019 at 16:46:06 UTC, H. S. Teoh wrote:
 On Thu, Dec 12, 2019 at 03:41:54PM +0000, aliak via 
 Digitalmars-d wrote:
 On Thursday, 12 December 2019 at 13:36:38 UTC, Adam D. Ruppe 
 wrote:
 BTW the JS one is actually quite interesting. It calls a 
 user-defined function, passing the arguments - similar to 
 the D tuple thing.
Except you can actually assign it to a string?
[...] As Adam already said, you can assign it to a string if the return type has alias this to string. T
So i"blah %var" would not return a tuple but a type that has alias this to string? Like: struct interolation_type { alias ?? this; }
Dec 12 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 12 December 2019 at 16:50:47 UTC, aliak wrote:
 So i"blah %var" would not return a tuple but a type that has 
 alias this to string? Like:
Yup that's my proposal: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html Walter's proposal isn't bad, though mine is better :) However I would tweak one thing about mine. Before I said "auto arg1 = 50; ". I'd actually change that now to `auto arg1 = () => 50;` for more compile time / runtime mixing compatibility. I might also steal the raw string thing from Javascript... and I actually kinda like the format string from Walter's proposal, though mine can actually do that too already by reading format stuff in CTFE right out of the string.
Dec 12 2019
next sibling parent reply Andrea Fontana <nospam example.com> writes:
On Thursday, 12 December 2019 at 17:05:32 UTC, Adam D. Ruppe 
wrote:
 On Thursday, 12 December 2019 at 16:50:47 UTC, aliak wrote:
 So i"blah %var" would not return a tuple but a type that has 
 alias this to string? Like:
Yup that's my proposal: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html
Quite better solution in my opinion. Andrea
Dec 13 2019
parent Ernesto Castellotti <erny.castell gmail.com> writes:
On Friday, 13 December 2019 at 09:19:53 UTC, Andrea Fontana wrote:
 On Thursday, 12 December 2019 at 17:05:32 UTC, Adam D. Ruppe 
 wrote:
 On Thursday, 12 December 2019 at 16:50:47 UTC, aliak wrote:
 So i"blah %var" would not return a tuple but a type that has 
 alias this to string? Like:
Yup that's my proposal: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html
Quite better solution in my opinion. Andrea
Yes, I would also like a dip with the Adam proposal
Dec 13 2019
prev sibling parent reply aliak <something something.com> writes:
On Thursday, 12 December 2019 at 17:05:32 UTC, Adam D. Ruppe 
wrote:
 On Thursday, 12 December 2019 at 16:50:47 UTC, aliak wrote:
 So i"blah %var" would not return a tuple but a type that has 
 alias this to string? Like:
Yup that's my proposal: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html Walter's proposal isn't bad, though mine is better :) However I would tweak one thing about mine. Before I said "auto arg1 = 50; ". I'd actually change that now to `auto arg1 = () => 50;` for more compile time / runtime mixing compatibility. I might also steal the raw string thing from Javascript... and I actually kinda like the format string from Walter's proposal, though mine can actually do that too already by reading format stuff in CTFE right out of the string.
Ah ok. Yeah that sounds pretty good! I'm starting to wonder now, what's the use case for returning tuples? Why not just a string?
Dec 16 2019
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Dec 16, 2019 at 11:00:34AM +0000, aliak via Digitalmars-d wrote:
[...]
 I'm starting to wonder now, what's the use case for returning tuples?
 Why not just a string?
For generating injection-proof SQL, for one thing. Probably others. T -- GEEK = Gatherer of Extremely Enlightening Knowledge
Dec 16 2019
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 12 December 2019 at 15:41:54 UTC, aliak wrote:
 Except you can actually assign it to a string?
The javascript version is allowed to return whatever it wants. The default one returns string but you can do other things with it too like return objects or functions or whatever. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals It passes the strings and the original elements, and you can actually even request the raw string to do custom escape sequences in it (really, the JS lexer treats it as a raw string, then there's a function on the object that can do default escape sequences for you). If you wanna talk about taking the best ideas from other languages, Javascript's template literals are actually really nice. They are so much more than a multi-line string or a way to concatenate things. This is why my proposal transforms the "interpolated string" into an object. Making it do the raw string with an escape method is a good idea to take too. Anyway, the object can `alias toString this` so you assign it to string and it just works like newbies expect. Templates don't trigger alias this but do often use toString so that just works. But then you can also recognize it specifically in functions/templates, store it in variables, etc for further processing. My interpolation object can be transformed into a ("%s", x) tuple. A plain tuple for calls like writeln. Or be passed to user functions. XmlElement e = xml!i" "; There's a lot of cool things we can do.
Dec 12 2019
next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Thursday, 12 December 2019 at 17:01:01 UTC, Adam D. Ruppe 
wrote:
 On Thursday, 12 December 2019 at 15:41:54 UTC, aliak wrote:
 [...]
The javascript version is allowed to return whatever it wants. The default one returns string but you can do other things with it too like return objects or functions or whatever. [...]
It'd be great if you could expand on this with a list of examples of what D could do.
Dec 12 2019
next sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Thursday, 12 December 2019 at 17:03:53 UTC, Atila Neves wrote:
 On Thursday, 12 December 2019 at 17:01:01 UTC, Adam D. Ruppe 
 wrote:
 On Thursday, 12 December 2019 at 15:41:54 UTC, aliak wrote:
 [...]
The javascript version is allowed to return whatever it wants. The default one returns string but you can do other things with it too like return objects or functions or whatever. [...]
It'd be great if you could expand on this with a list of examples of what D could do.
Tagged template literals are indeed quite nice in JS. Here's an example from the chalk npm package [1]: ```js // Plain template literals (a.k.a. built-in string interpolation): const str1 = ` CPU: ${chalk.red("90%")} RAM: ${chalk.green("40%")} DISK: ${chalk.yellow("70%")} `; // Same example but with tagged template literals - more DRY: const str2 = chalk` CPU: {red 90%} RAM: {green 40%} DISK: {yellow 70%} `; // Tagged template literals + interpolation of variables: const cpu = 90; const ram = 40; const disk = 70; const str3 = chalk` CPU: {red ${cpu}%} RAM: {green ${ram}%} DISK: {yellow ${disk}%} `; Here's another example, this case from the es2015-i18n-tag library [2] that applies translations, locale and currency formatting: const name = 'Steffen' const amount = 1250.33 console.log(i18n`Hello ${ name }, you have ${ amount }:c in your bank account.`) // Hallo Steffen, Sie haben US$ 1,250.33 auf Ihrem Bankkonto. ``` The D analog of a function that can be used as tagged template string literal would be: ```d string interpolate(Args...)(string[] parts, Args args) { import std.algorithm.iteration : joiner; import std.conv : text; import std.range : roundRobin; string[Args.length] stringifiedArgs; static foreach (idx, arg; args) stringifiedArgs[idx] = text(arg); return parts.roundRobin(stringifiedArgs[]).joiner.text; } static import term; // Assume some ANSI term coloring library const string res = i" CPU: ${term.red("90%")} RAM: ${term.green("40%")} DISK: ${term.yellow("70%")} ".interpolate; ``` [1]: https://github.com/chalk/chalk [2]: https://github.com/skolmer/es2015-i18n-tag
Dec 12 2019
parent reply mipri <mipri minimaltype.com> writes:
On Thursday, 12 December 2019 at 23:31:21 UTC, Petar Kirov 
[ZombineDev] wrote:
 On Thursday, 12 December 2019 at 17:03:53 UTC, Atila Neves
 wrote:
 It'd be great if you could expand on this with a list of
 examples of what D could do.
Tagged template literals are indeed quite nice in JS. Here's an example from the chalk npm package [1]: ```js // Plain template literals (a.k.a. built-in string interpolation): const str1 = ` CPU: ${chalk.red("90%")} RAM: ${chalk.green("40%")} DISK: ${chalk.yellow("70%")} `;
With no changes to DIP-1027: const str1 = format(i" CPU: %(chalk.red("90%")) RAM: %(chalk.green("40%")) DISK: %(chalk.yellow("70%")) "); which lowers to const str1 = format(" CPU: %s RAM: %s DISK: %s ", chalk.red("90%"), chalk.green("40%"), chalk.yellow("70%"));
 // Same example but with tagged template literals - more DRY:
 const str2 = chalk`
 CPU: {red 90%}
 RAM: {green 40%}
 DISK: {yellow 70%}
 `;
Likewise: with (chalk) { const str2 = format(i" CPU: %(90.percent.red) RAM: %(40.percent.green) DISK: %(70.percent.yellow) "); }
 // Tagged template literals + interpolation of variables:
 const cpu = 90;
 const ram = 40;
 const disk = 70;

 const str3 = chalk`
 CPU: {red ${cpu}%}
 RAM: {green ${ram}%}
 DISK: {yellow ${disk}%}
 `;
Likewise: with (chalk) { const str2 = format(i" CPU: %(cpu.red) RAM: %(ram.green) DISK: %(disk.yellow) "); }
 Here's another example, this case from the es2015-i18n-tag
 library [2] that applies translations, locale and currency
 formatting:

 const name = 'Steffen'
 const amount = 1250.33
 console.log(i18n`Hello ${ name }, you have ${ amount }:c in
 your bank account.`)
 // Hallo Steffen, Sie haben US$ 1,250.33 auf Ihrem Bankkonto.
 ```
Likewise: writeln(i18n(i"Hello %name, you have %{$}(amount) in your bank account.")); which lowers to: writeln(i18n("Hello %s, you have %$ in your bank account.", name, amount)); and normal function i18n can do the gettext() stuff, and handle %$ itself, or indeed it could do nothing special with %$ but leave it to custom format specifiers and `amount` being a monetary object: https://wiki.dlang.org/Defining_custom_print_format_specifiers So I must conclude: 1. This is all very cool, but 2. DIP-1027 can do all of it as currently specified. 3. Actually DIP-1027 is not as bad as I thought. In particular, instead of documenting the feature in terms of its failures vs. other languages, it can say "use format() if you mainly to build a string" and "here's some cool stuff that this design lets you do, that more traditional string interpolation could not do." So I respectfully withdraw my complaints and instead submit support for some kind of SQL generalization with ? placeholders.
Dec 12 2019
parent mipri <mipri minimaltype.com> writes:
On Friday, 13 December 2019 at 00:05:54 UTC, mipri wrote:
 3. Actually DIP-1027 is not as bad as I thought. In particular,
 instead of documenting the feature in terms of its failures vs.
 other languages, it can say "use format() if you mainly to
 build a string" and "here's some cool stuff that this design
 lets you do, that more traditional string interpolation could
 not do."
To be clear, some cool stuff is 1. Internationalization. Normally with string interpolation in languages, the interpolation happens before anything can see the string, so f.e. the Perl way to do internationalization is just printf(gettext("I scanned %g %s."), $dir_scan_count, $dir_scan_count == 1 ? gettext("directory") : gettext("directories"), ); https://metacpan.org/pod/Locale::Maketext::TPJ13 despite "I scanned $count $directory" being the more normal way to write that code in Perl. 2. SQL queries without SQL injection, if support for this is added. It's precisely due to the popularity of string interpolation that SQL injection even happens, and so again the Perl way to do database queries is my $contained_sql = <<""; SELECT id FROM city_buildings WHERE minLong >= ? AND maxLong <= ? AND minLat >= ? AND maxLat <= ? my $contained = $dbh->selectcol_arrayref($contained_sql,undef, $minLong, $maxLong, $minLat, $maxLat); https://metacpan.org/pod/DBD::SQLite Normally, string interpolation is a convenience that you can use most of the time but have to put aside when things get advanced. Here we have a proposed string interpolation that fits the most common case while still being useful in more advanced cases, which is instead a slightly less convenient in certain cases. The most common case: writeln("Hello, %s.".format(name)); // currently writefln(i"Hello, %name."); // DIP-1027 println("Hello, $name."); // Kotlin An advanced case: writeln(format(_("Hello, %s!"), name)); // currently (djtext) writeln(i"Hello, %name!".nu_gettext); // DIP-1027 // I can't find a Kotlin example. An inconvenient case: // currently string[] greetings = [ "Hello, %s".format(name), "Aloha, %s".format(name), "Hiya, %s".format(name), "Salutations, %s".format(name), ]; // DIP-1027 string[] greetings = [ i"Hello, %name".format, i"Aloha, %name".format, i"Hiya, %name".format, i"Salutations, %name".format, ]; // Kotlin val greetings = listOf( "Hello, $name", "Aloha, $name", "Hiya, $name", "Salutations, $name" ) Note the 'nu_gettext'. It can't be djtext's existing _() or getdtext() functions because you can't accept the i"" string without also accepting the parameters for the i"" string.
Dec 12 2019
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 12 December 2019 at 17:03:53 UTC, Atila Neves wrote:
 It'd be great if you could expand on this with a list of 
 examples of what D could do.
Of course, there's the examples of printf, writeln, sql query.. (One other addition I might make to my proposal is having the string version of what's in the thing too, but I digress). Those are the easy ones. Note btw that you can even do a format!"%s"(a) type thing. But it can get pretty interesting to look beyond function calls. What about some kind of object literal? int a; string b; JSONValue j = json!iq{ }; That specific syntax assumes interpolated token strings are a thing but it could just as well be JSONValue j = json!i" "; or %(a) or $a or whatever. I don't care. The implementation would look something like: JSONValue json(__d_interpolated_string s)() { JSONValue j; foreach(idx, member; s.tupleof) { static if(!(idx & 1)) { j.object[member.replace(",", "").strip] = JSONValue(member[idx + 1]()); } } return j; } you know plus more sanity but you get the idea. All the data is in an object which we can pass to a template to do compile time checking and return type processing etc. Of course, for json, you can do a built in AA and a constructor from it, just then the types have to be heterogeneous. Not a huge deal for json but it can get ugly nested. But we can do xml too, think react's jsx int foo; string bar = "<"; Element e = jsx!i` `; assert(e.tagName = "foo"); assert(e.attrs.value == foo); assert(e.innerHTML == "&lt;"); This is almost interchangeable with the mixin(foo!"string") thing... in fact you could implement it that way, just instead of having foo!xx return a code string the compiler helps a bit more.
Dec 12 2019
parent reply mipri <mipri minimaltype.com> writes:
On Friday, 13 December 2019 at 00:06:15 UTC, Adam D. Ruppe wrote:
 But it can get pretty interesting to look beyond function 
 calls. What about some kind of object literal?

 int a;
 string b;
 JSONValue j = json!iq{


 };
This doesn't work though: auto n = 4; [1,2,3].map!(format("a + %s", n)).each!writeln; // Error: variable n cannot be read at compile time It doesn't even work to pass that format() to void ignore(string s)() { } So I imagine i"" strings won't be useful in static arguments except with static parameters.
Dec 12 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 13 December 2019 at 01:19:32 UTC, mipri wrote:
 This doesn't work though:

   auto n = 4;
   [1,2,3].map!(format("a + %s", n)).each!writeln;
Indeed, but it does work to pass seq!(() => n). That's why I've amended my proposal to do that instead. Then it inherits the CT-ness of n while still being usable in a runtime context. It is similar to `lazy` parameters built into the language;
 So I imagine i"" strings won't be useful in static arguments
 except with static parameters.
auto interpolate(T...)() { import std.conv; string s; foreach(t; T) static if(is(typeof(t) == string)) s ~= t; else s ~= to!string(t()); return s; } void main() { int n; enum n2 = 56; // runtime variable works for runtime, but errors if `enum s;` string s = interpolate!("this works: ", () => n); // CT variable works in either cse enum e = interpolate!("this works too ", () => n2); import std.stdio; writeln(s); writeln(e); } In my original proposal I was just going to use a value, but the compiler-generated lambda is more flexible as seen here. So becomes __DInterpolatedString!("foo ", () => a); and you can do all kinds of magical things with that. (In my original proposal I rejected this hybrid library solution because of this very problem, but this little bit of magic allows it. The compiler simply rewrites the i"" string into a call to that template, then object.d can be responsible for doing the rest.) If you like I could actually go ahead and write up a library implementation and we pretend the syntax lowering is in place to evaluate it.
Dec 12 2019
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 13.12.19 02:30, Adam D. Ruppe wrote:
 On Friday, 13 December 2019 at 01:19:32 UTC, mipri wrote:
 This doesn't work though:

   auto n = 4;
   [1,2,3].map!(format("a + %s", n)).each!writeln;
Indeed, but it does work to pass seq!(() => n). That's why I've amended my proposal to do that instead. Then it inherits the CT-ness of n while still being usable in a runtime context. It is similar to `lazy` parameters built into the language;
I think that's a bit hacky, e.g.: int x=0; auto s=i"$(++x)"; writeln(s); // 1 writeln(s); // 2
Dec 12 2019
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 13 December 2019 at 02:10:04 UTC, Timon Gehr wrote:
 I think that's a bit hacky, e.g.:
yeah, can fix that with a lazily initialized cache. but if it is built into the compiler we can fix details like this there too.
Dec 12 2019
prev sibling next sibling parent Sebastiaan Koppe <mail skoppe.eu> writes:
On Thursday, 12 December 2019 at 17:01:01 UTC, Adam D. Ruppe 
wrote:
 On Thursday, 12 December 2019 at 15:41:54 UTC, aliak wrote:
 Except you can actually assign it to a string?
The javascript version is allowed to return whatever it wants. The default one returns string but you can do other things with it too like return objects or functions or whatever. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
That is a good observation. I forgot all about tagged template literals. We should totally steal some of that. From the page:
 Template literals are enclosed by the back-tick (` `)  (grave 
 accent) character instead of double or single quotes. Template 
 literals can contain placeholders. These are indicated by the 
 dollar sign and curly braces (${expression}). The expressions 
 in the placeholders and the text between the back-ticks (` `) 
 get passed to a function. The default function just 
 concatenates the parts into a single string. If there is an 
 expression preceding the template literal (tag here), this is 
 called a "tagged template". In that case, the tag expression 
 (usually a function) gets called with the template literal, 
 which you can then manipulate before outputting.
try this in your browser's console: val = 4; function sql(strings, ...keys) { return {sql: strings.join("?"), keys} }; sql`select * from table where a = ${val} and b = ${val}`; it will return: {"sql":"select * from table where a = ? and b = ?","keys":[4,4]}
 If you wanna talk about taking the best ideas from other 
 languages, Javascript's template literals are actually really 
 nice. They are so much more than a multi-line string or a way 
 to concatenate things.
yes.
Dec 12 2019
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
I find your proposal a little confusing. By turning the string into an object, 
it doesn't work with printf?

I'm also not sure it's a good idea to make this more powerful. As a simple 
"replace the string with a tuple" its very easy to understand.
Dec 14 2019
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2019-12-14 10:10, Walter Bright wrote:
 I find your proposal a little confusing. By turning the string into an 
 object, it doesn't work with printf?
One would need to explicitly call `toString` or add an `alias this` to the struct. -- /Jacob Carlborg
Dec 14 2019
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 14 December 2019 at 09:10:47 UTC, Walter Bright 
wrote:
 I find your proposal a little confusing. By turning the string 
 into an object, it doesn't work with printf?
Right, not directly. But then it is trivial to add a member of the object that transforms it into a tuple suitable for printf. So the end user's code now looks like: `printf(i"foo %bar".asFormatTuple);` BTW I am not opposed to your version either, since it can be transformed into something close to my version. My big concern is that your version (as well as Jonathan Marler's) loses information very easily. printf(i"%item"); // happens to work writefln(i"%item"); // also happens to work writeln(i"%item"); // oops! not going to do what you want format(); // works text(); // wrong And there's no compile error for incorrect usage. With an object, we get existing type checking safety and can guide it to the correct usage: printf(i""); // error cannot implicitly convert __d_interpolated_string to const char* writefln(i""); // static assert failed: "use i"".asFormatTuple instead writeln(i""); // happens to just work because it calls toString
 I'm also not sure it's a good idea to make this more powerful. 
 As a simple "replace the string with a tuple" its very easy to 
 understand.
Objects are easy to understand too. And easy to implement: on the compiler it is basically just `X!(your version)` instead of just plain `(your version)`.
Dec 14 2019
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/14/19 9:23 AM, Adam D. Ruppe wrote:
 On Saturday, 14 December 2019 at 09:10:47 UTC, Walter Bright wrote:
 I find your proposal a little confusing. By turning the string into an 
 object, it doesn't work with printf?
Right, not directly. But then it is trivial to add a member of the object that transforms it into a tuple suitable for printf. So the end user's code now looks like: `printf(i"foo %bar".asFormatTuple);` BTW I am not opposed to your version either, since it can be transformed into something close to my version. My big concern is that your version (as well as Jonathan Marler's) loses information very easily.
What information does it lose?
 printf(i"%item"); // happens to work
 writefln(i"%item"); // also happens to work
 
 writeln(i"%item"); // oops! not going to do what you want
But did what you asked? Coding is full of such dilemmas. I've actually done this many many times: writeln("Value is %s", value); I see the result, and fix it. This isn't difficult. One other suggestion I had was to make the resulting string literal generated by interpolation be a derivative of a string literal. That is, it's usable wherever a string literal is, but functions that wish to overload based on that type difference can do so. i.e. we could make the writeln call above work as expected.
 
 format(); // works
 text(); // wrong
 
 And there's no compile error for incorrect usage. With an object, we get 
 existing type checking safety and can guide it to the correct usage:
 
 printf(i""); // error cannot implicitly convert __d_interpolated_string 
 to const char*
Hm... I prefer it just working correctly.
 
 writefln(i""); // static assert failed: "use i"".asFormatTuple instead
Same. But why wouldn't writefln be overloaded on your object type to do the right thing?
 
 writeln(i""); // happens to just work because it calls toString
Sure, but if you are going through the trouble to deal with format specifiers, I don't know why you'd want to support writeln out of the box but not writefln. Not only that, but now you have to pull a lot of the library into druntime (std.format for example).
 I'm also not sure it's a good idea to make this more powerful. As a 
 simple "replace the string with a tuple" its very easy to understand.
Objects are easy to understand too. And easy to implement: on the compiler it is basically just `X!(your version)` instead of just plain `(your version)`.
What about the lifetime issues? An object is going to make a copy. Which may not be correct or possible. I do like two aspects of your proposal. First is that all the information is available for further compile-time manipulation. Second is that having a specialized type allows function overloading. -Steve
Dec 14 2019
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 14 December 2019 at 15:04:24 UTC, Steven 
Schveighoffer wrote:
 What information does it lose?
The grouping of the items in the string. Tuples auto-flatten and then the function cannot tell any more if they actually were together to begin with. The format string lets you reconstruct it though, assuming you know to check for a format string. This is why I can work with Walter's proposal, it would just be disappointing to lose the overloading aspect of it.
 One other suggestion I had was to make the resulting string 
 literal generated by interpolation be a derivative of a string 
 literal.
That's what an object with `alias toString this` is!
 Hm... I prefer it just working correctly.
We can do that with Phobos functions (and indeed anything written after we decide on the interface), but printf's interface is already locked down, so it is either just working there or having an object, can't do both.... and I think that'd be a pity since a compile error telling you to use ".asFormatString" is such an easy solution.
 Not only that, but now you have to pull a lot of the library 
 into druntime (std.format for example).
Solved problem: you'd make the method templated so it is only pulled if used. The ^^ operator in D works like this already. No need to actually bring it in to druntime, it will just reference phobos iff used.
 What about the lifetime issues? An object is going to make a 
 copy. Which may not be correct or possible.
So does a tuple passed to a function, there's no difference here anyway. Remember, all my thing really boils down to is the compiler inserting X!T instead of just T.
Dec 14 2019
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/14/2019 6:23 AM, Adam D. Ruppe wrote:
 On Saturday, 14 December 2019 at 09:10:47 UTC, Walter Bright wrote:
 I find your proposal a little confusing. By turning the string into an object, 
 it doesn't work with printf?
Right, not directly. But then it is trivial to add a member of the object that transforms it into a tuple suitable for printf. So the end user's code now looks like: `printf(i"foo %bar".asFormatTuple);`
I was afraid that would be it. The extra syntax kills it, along with the extra import required, along with not working with #betterC. You can still #thagomize it, or turn it into an object, etc., with: Object thagomize(string, ...); ... thagomize(i"foo%bar"); It's just not the default.
Dec 14 2019
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 15 December 2019 at 01:44:18 UTC, Walter Bright wrote:
 The extra syntax kills it
This is true, but ONLY for the printf case. It just works in all other cases.
 with the extra import required, along with not working with 
 #betterC.
No need for import - this is a definition in object.d, and it will work in betterC since this is a compile-time transformation (the `asFormatString` definition is essentially just `template asFormatString(T...) { alias asFormatString = T; }`. And my proposal also doesn't need an import to be assigned to a string whereas yours does. string a = i""; // mine would trigger the alias toString this and just work string a = format(i""); // must import std.format. also fails in betterC btw
 It's just not the default.
Which is usable (that's why I'm not opposed to your proposal) but means it is now impossible to catch accidental misuses at compile time. They type system no longer helps you. But what about a small compromise: what if JUST the format string was given a new type and the rest was still a tuple. The format string can implicitly convert to the same things a string literal can; it can go to `string` or to `const char*`, but then user-defined functions are also able to overload on it. So i"hi %test" becomes basically typedef string InterpolatedFormat; type_tuple(InterpolatedFormat("hi %s"), test) That'd still work in printf - it just implicitly converts back to char* - and gives just enough type information hints to cover my advanced use cases too.
Dec 14 2019
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/14/2019 5:52 PM, Adam D. Ruppe wrote:
 On Sunday, 15 December 2019 at 01:44:18 UTC, Walter Bright wrote:
 The extra syntax kills it
This is true, but ONLY for the printf case. It just works in all other cases.
printf is a very important case, and it kills it for scanf and every other function that takes a format string (dmd itself has many printf-like functions).
 with the extra import required, along with not working with #betterC.
No need for import - this is a definition in object.d,
object.d is getting more and more bloated over time. This is not a solution to imports, and is not a good trend.
 and it will work in 
 betterC since this is a compile-time transformation (the `asFormatString` 
 definition is essentially just `template asFormatString(T...) { alias 
 asFormatString = T; }`.
 
 And my proposal also doesn't need an import to be assigned to a string whereas 
 yours does.
 
 string a = i""; // mine would trigger the alias toString this and just work
 
 string a = format(i""); // must import std.format. also fails in betterC btw
betterC is for use without Phobos.
 It's just not the default.
Which is usable (that's why I'm not opposed to your proposal) but means it is now impossible to catch accidental misuses at compile time. They type system no longer helps you.
That's always been true with printf. Many C compilers have extensions to deal with this, but D never incorporated them (although it could).
 But what about a small compromise: what if JUST the format string was given a 
 new type and the rest was still a tuple. The format string can implicitly 
 convert to the same things a string literal can; it can go to `string` or to 
 `const char*`, but then user-defined functions are also able to overload on it.
 
 So
 
 i"hi %test"
 
 becomes basically
 
 typedef string InterpolatedFormat;
 
 type_tuple(InterpolatedFormat("hi %s"),  test)
 
 That'd still work in printf - it just implicitly converts back to char* - and 
 gives just enough type information hints to cover my advanced use cases too.
Adding a new basic type to the language just for this is not worth it. With the proposal, I can explain it in one slide, which is worth a great deal.
Dec 14 2019
next sibling parent reply Jab <jab_293 gmall.com> writes:
On Sunday, 15 December 2019 at 04:20:59 UTC, Walter Bright wrote:
 On 12/14/2019 5:52 PM, Adam D. Ruppe wrote:
 On Sunday, 15 December 2019 at 01:44:18 UTC, Walter Bright 
 wrote:
 The extra syntax kills it
This is true, but ONLY for the printf case. It just works in all other cases.
printf is a very important case, and it kills it for scanf and every other function that takes a format string (dmd itself has many printf-like functions).
IIRC you said dmd was just a direct translation from C and carries all that legacy debt. Is that really an example you want to be using to justify your point?
 It's just not the default.
Which is usable (that's why I'm not opposed to your proposal) but means it is now impossible to catch accidental misuses at compile time. They type system no longer helps you.
That's always been true with printf. Many C compilers have extensions to deal with this, but D never incorporated them (although it could).
You don't need to add an extra feature and warnings to the compiler. There's already a type system that can be used. Also that feature isn't that simple to implement. I see all the hacks to get around it in android's kernel source. They treat the warning as an error, even with the hacks in the source code. It still gives false positives and I end up disabling it or just deleting the logs that are causing the error. If it was important it would already have been implemented, but no one uses printf as there are better alternatives.
Dec 14 2019
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Sunday, 15 December 2019 at 05:34:48 UTC, Jab wrote:
 If it was important it would already have been implemented, but 
 no one uses printf as there are better alternatives.
That's wrong, we use printf snprint and sprintf a lot since we can't use D with its runtime (makes too much problems in a shared lib) and printf still is the gold standard for conversion of float to string.
Dec 15 2019
parent Jab <jab_293 gmall.com> writes:
On Sunday, 15 December 2019 at 18:29:10 UTC, Guillaume Piolat 
wrote:
 On Sunday, 15 December 2019 at 05:34:48 UTC, Jab wrote:
 If it was important it would already have been implemented, 
 but no one uses printf as there are better alternatives.
That's wrong, we use printf snprint and sprintf a lot since we can't use D with its runtime (makes too much problems in a shared lib) and
It was a figure of speech. You are most definitely in the minority. You can create a convenience wrapper around printf that is nogc so you don't have to use it directly.
 printf still is the gold standard for conversion of float to 
 string.
It's just the most accessible. There are better float to string implementations out there.
Dec 15 2019
prev sibling next sibling parent reply Aliak <something something.com> writes:
On Sunday, 15 December 2019 at 04:20:59 UTC, Walter Bright wrote:
 With the proposal, I can explain it in one slide, which is 
 worth a great deal.
To use it people will need to understand how to use d tuples as well. This seems like optimizing for betterC? Why not optimize for the D case? Do you know how many users even use betterC? People will write writeln(i”$var bananas”) and see it not work, and not understand why. The most basic case doesn’t work either with this proposal (assigning a what-you-intuitively-think is a string to a string).
Dec 15 2019
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/15/2019 2:17 AM, Aliak wrote:
 To use it people will need to understand how to use d tuples as well.
No, they don't.
Dec 15 2019
parent reply aliak <something something.com> writes:
On Monday, 16 December 2019 at 01:35:51 UTC, Walter Bright wrote:
 On 12/15/2019 2:17 AM, Aliak wrote:
 To use it people will need to understand how to use d tuples 
 as well.
No, they don't.
User: why can't I do this?/Why doesn't this work? string s = i"$var"; Answer?
Dec 16 2019
next sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 On Monday, 16 December 2019 at 01:35:51 UTC, Walter Bright 
 wrote:
 On 12/15/2019 2:17 AM, Aliak wrote:
 To use it people will need to understand how to use d tuples 
 as well.
No, they don't.
User: why can't I do this?/Why doesn't this work? string s = i"$var"; Answer?
because string s = ("%s",var); is a syntax error. Even a beginning programmer can understand that an interpolated string cannot be a pure simple string as it contains symbols and expressions that are language construct not part of the string literal, i.e. that the compiler has to perform some transformations to substitute these language symbols into a value. Interpolated strings, in any language, are not string literals. Each language resolves this fact in different manners and at different times. Interpreted languages do it at runtime (obviously), java like languages chose to do it at runtime. In a language like D, which prefers resolving what is resolvable at compile time, it would be loathed if it interpolation was resolved at runtime (remember how long people were bitching about runtime only format strings?) Resolving interpolation at compile time is imho incompatible with handling them as regular strings. The question is then do we want CT or RT interpolated strings. RT interpolated strings can still be provided by a library.
Dec 16 2019
next sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 16 December 2019 at 11:08:00 UTC, Patrick Schluter 
wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:

 Resolving interpolation at compile time is imho incompatible
with handling them as regular strings.
Maybe I'm wrong here, I haven't thought it through, but in first approach I think that's an essential point. As the string contains code, if evaluated at CT, the string must be split somehow in literal parts and code parts. Allowing the i-string to be handled as regular string implies that the splitting happens sometime between when it is declared and after it is used, which can happen after runtime. import fn; int b = 20; string inter = i"$(a+b)"; foreach(a; 1..10) fn(inter); --- module fn; void fn(string s) { writefln(s); } How would that work? In python or javascript there's no issue, a is a runtime symbol.
 The question is then do we want CT or RT interpolated strings. 
 RT interpolated strings can still be provided by a library.
Dec 16 2019
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On Monday, 16 December 2019 at 11:18:33 UTC, Patrick Schluter 
wrote:

 Maybe I'm wrong here, I haven't thought it through, but in 
 first approach I think that's an essential point. As the string 
 contains code, if evaluated at CT, the string must be split 
 somehow in literal parts and code parts. Allowing the i-string 
 to be handled as regular string implies that the splitting 
 happens sometime between when it is declared and after it is 
 used, which can happen after runtime.

 import fn;

 int b = 20;

 string inter = i"$(a+b)";

 foreach(a; 1..10)
   fn(inter);

 ---
 module fn;

 void fn(string s)
 {
   writefln(s);
 }

 How would that work?

 In python or javascript there's no issue, a is a runtime symbol.
Not sure how other languages do it but in Ruby the interpolation is performed where the string literal is declared. Not where the string is later used. So the above would fail because `a` is not available. -- /Jacob Carlborg
Dec 16 2019
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 16 December 2019 at 12:37:47 UTC, Jacob Carlborg wrote:
 On Monday, 16 December 2019 at 11:18:33 UTC, Patrick Schluter 
 wrote:

 Maybe I'm wrong here, I haven't thought it through, but in 
 first approach I think that's an essential point. As the 
 string contains code, if evaluated at CT, the string must be 
 split somehow in literal parts and code parts. Allowing the 
 i-string to be handled as regular string implies that the 
 splitting happens sometime between when it is declared and 
 after it is used, which can happen after runtime.

 import fn;

 int b = 20;

 string inter = i"$(a+b)";

 foreach(a; 1..10)
   fn(inter);

 ---
 module fn;

 void fn(string s)
 {
   writefln(s);
 }

 How would that work?

 In python or javascript there's no issue, a is a runtime 
 symbol.
Not sure how other languages do it but in Ruby the interpolation is performed where the string literal is declared. Not where the string is later used. So the above would fail because `a` is not available.
Yes, probably. The issue I had with the transformation as string is what should the code below print? import fn; int a, b = 20; string inter = i"$(a+b)"; for(a=0; a<10; a++) fn(inter); --- module fn; void fn(string s) { writef(s); } prints 202020202020202020 or 212223242526272829 and that's the difference between CT evaluation and RT evaluation.
Dec 16 2019
parent reply Jacob Carlborg <doob me.com> writes:
On Monday, 16 December 2019 at 12:55:17 UTC, Patrick Schluter 
wrote:

 Yes, probably. The issue I had with the transformation as 
 string is what should the code below print?

 import fn;

 int a, b = 20;

 string inter = i"$(a+b)";

 for(a=0; a<10; a++)
    fn(inter);

  ---
  module fn;

  void fn(string s)
  {
    writef(s);
  }

 prints
 202020202020202020

 or

 212223242526272829

 and that's the difference between CT evaluation and RT 
 evaluation.
It's difficult to say as your code doesn't compile. As it's written the code will fail to compile because you cannot have a for-loop at module scope. The line where `inter` is declared would fail to compile as well because `a` and `b` cannot be read at compile time. I don't see how that would be any different compared to this code: module foo; int a, b = 20; int c = a + b; // fails to compile as well If all of this code would be wrapped in a function, then it would successfully compile. `inter` would be evaluated to "20" and the code would print: 20202020202020202020 I don't see how it would behave any differently than if you replaced `string` with `int` and removed `i"$"`. For the result to be `212223242526272829` `i"$(a+b)"` would need to be a macro. -- /Jacob Carlborg
Dec 17 2019
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 17 December 2019 at 09:20:06 UTC, Jacob Carlborg 
wrote:
 On Monday, 16 December 2019 at 12:55:17 UTC, Patrick Schluter 
 wrote:

 Yes, probably. The issue I had with the transformation as 
 string is what should the code below print?

 import fn;

 int a, b = 20;

 string inter = i"$(a+b)";

 for(a=0; a<10; a++)
    fn(inter);

  ---
  module fn;

  void fn(string s)
  {
    writef(s);
  }

 prints
 202020202020202020

 or

 212223242526272829

 and that's the difference between CT evaluation and RT 
 evaluation.
It's difficult to say as your code doesn't compile. As it's written the code will fail to compile because you cannot have a for-loop at module scope. The line where `inter` is declared would fail to compile as well because `a` and `b` cannot be read at compile time. I don't see how that would be any different compared to this code: module foo; int a, b = 20; int c = a + b; // fails to compile as well If all of this code would be wrapped in a function, then it would successfully compile. `inter` would be evaluated to "20" and the code would print: 20202020202020202020 I don't see how it would behave any differently than if you replaced `string` with `int` and removed `i"$"`. For the result to be `212223242526272829` `i"$(a+b)"` would need to be a macro.
Yes, and that was the point of the exercice. Transforming the interpolated "string" into a string evaluates the values of the variables at the moment of that transformation. From then on, there is no interpolation possible as it a simple string. I suppose that what aliak leant in his comments was that the string then could still be used for interpolation. hypothetic scenario of what I interpreted what aliak wanted (and it won't compile, it's just for illustration) int apple; ... string my_is = i"apple=${apple}"; ... apple = 36; writeln(my_is); would print "apple=36" with this DIP, when you do this int apple; ... string my_is = i"apple=${apple}".format; ... apple = 36; writeln(my_is); will print "apple=0" because my_is will contain the string "apple=0" The basic thing here is what Walter said above: interpolated strings are not string literals, they can't be. They are code.
Dec 17 2019
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2019-12-17 11:14, Patrick Schluter wrote:

 Yes, and that was the point of the exercice. Transforming the 
 interpolated "string" into a string evaluates the values of the 
 variables at the moment of that transformation. From then on, there is 
 no interpolation possible as it a simple string.
 I suppose that what aliak leant in his comments was that the string then 
 could still be used for interpolation.
 
 hypothetic scenario of what I interpreted what aliak wanted (and it 
 won't compile, it's just for illustration)
 
 int apple;
 ...
    string my_is = i"apple=${apple}";
 
 ...
 
    apple = 36;
    writeln(my_is);
 
 would print "apple=36"
 
 with this DIP, when you do this
 
 int apple;
 ...
    string my_is = i"apple=${apple}".format;
 
 ...
 
    apple = 36;
    writeln(my_is);
 
 will print "apple=0" because my_is will contain the string "apple=0"
I don't see how lowering to a tuple will change anything. It's not possible to store expressions. If you have the expression `3 + 4` than that will be evaluated and `7` is what's left. Unless the expression is wrapped in a lambda.
 The basic thing here is what Walter said above:
 
 interpolated strings are not string literals, they can't be. They are code.
Of course they can. They can be whatever we decide them to be. -- /Jacob Carlborg
Dec 17 2019
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 17 December 2019 at 16:43:32 UTC, Jacob Carlborg 
wrote:
 On 2019-12-17 11:14, Patrick Schluter wrote:

 Yes, and that was the point of the exercice. Transforming the 
 interpolated "string" into a string evaluates the values of 
 the variables at the moment of that transformation. From then 
 on, there is no interpolation possible as it a simple string.
 I suppose that what aliak leant in his comments was that the 
 string then could still be used for interpolation.
 
 hypothetic scenario of what I interpreted what aliak wanted 
 (and it won't compile, it's just for illustration)
 
 int apple;
 ...
    string my_is = i"apple=${apple}";
 
 ...
 
    apple = 36;
    writeln(my_is);
 
 would print "apple=36"
 
 with this DIP, when you do this
 
 int apple;
 ...
    string my_is = i"apple=${apple}".format;
 
 ...
 
    apple = 36;
    writeln(my_is);
 
 will print "apple=0" because my_is will contain the string 
 "apple=0"
I don't see how lowering to a tuple will change anything. It's not possible to store expressions. If you have the expression `3 + 4` than that will be evaluated and `7` is what's left. Unless the expression is wrapped in a lambda.
Which was my point. An interpolated string cannot be stored in a simple string as some people requested in the thread before (not you). It is only feasible if the istring is evaluated at runtime with an interpreter who knows the current values of the variables used. Interpreted languages like python, perl, javascript etc. might get away with it but compiled languages have to transform it in its code representation.
 The basic thing here is what Walter said above:
 
 interpolated strings are not string literals, they can't be. 
 They are code.
Of course they can. They can be whatever we decide them to be.
Dec 17 2019
parent reply mipri <mipri minimaltype.com> writes:
On Tuesday, 17 December 2019 at 17:13:50 UTC, Patrick Schluter 
wrote:
 Which was my point. An interpolated string cannot be stored in 
 a simple string as some people requested in the thread before 
 (not you). It is only feasible if the istring is evaluated at 
 runtime with an interpreter who knows the current values of the 
 variables used. Interpreted languages like python, perl, 
 javascript etc. might get away with it but compiled languages 
 have to transform it in its code representation.
These languages also don't store "interpolated strings" in variables; they store strings in variables, and any string interpolation happens at the literal. Crystal (compiled language with a real type system, etc.): apple = 0 apple = 36 puts my_is Ruby (interpreted scripting language): apple = 0 apple = 36 puts my_is Both output "apple=0". I can't recall a case where you'd get "apple=36". You'd have to deliberately delay evaluation of the literal. But I don't think anyone's asked for any other behavior than this. What's wanted is for int apple; string my_is = i"apple=$apple"; apple = 36; writeln(my_is); to output "apple=36" rather than result in a compile-time error because i"..." doesn't evaluate to a string.
Dec 17 2019
parent mipri <mipri minimaltype.com> writes:
On Tuesday, 17 December 2019 at 17:31:20 UTC, mipri wrote:
 What's wanted is for

   int apple;
   string my_is = i"apple=$apple";
   apple = 36;
   writeln(my_is);

 to output "apple=36"
Of course this should read "apple=0". This is a mistake I wouldn't've made with a logical programming language :(
Dec 17 2019
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/17/19 5:14 AM, Patrick Schluter wrote:
 Yes, and that was the point of the exercice. Transforming the 
 interpolated "string" into a string evaluates the values of the 
 variables at the moment of that transformation. From then on, there is 
 no interpolation possible as it a simple string.
 I suppose that what aliak leant in his comments was that the string then 
 could still be used for interpolation.
 
 hypothetic scenario of what I interpreted what aliak wanted (and it 
 won't compile, it's just for illustration)
 
 int apple;
 ....
    string my_is = i"apple=${apple}";
 
 ....
 
    apple = 36;
    writeln(my_is);
 
 would print "apple=36"
 
 with this DIP, when you do this
 
 int apple;
 ....
    string my_is = i"apple=${apple}".format;
 
 ....
 
    apple = 36;
    writeln(my_is);
 
 will print "apple=0" because my_is will contain the string "apple=0"
 
 The basic thing here is what Walter said above:
 
 interpolated strings are not string literals, they can't be. They are code.
Wow, I don't think that the first item can be done with the DIP. But that would be really cool (I'm thinking of periodic logging features). I tried this, still prints 5 apples and 6 bananas: int apples = 5; int bananas = 6; auto as = AliasSeq!("%s apples and %s bananas", apples, bananas); // essentially what an interpolated string will evaluate to writefln(as); ++apples; ++bananas; writefln(as); It seems that AliasSeq doesn't store the alias (ironically), but the value of the expression at the time. Is there a way that this could work? I mean, aside from storing lambdas for everything? -Steve
Dec 17 2019
parent reply ag0aep6g <anonymous example.com> writes:
On 17.12.19 18:12, Steven Schveighoffer wrote:
 I tried this, still prints 5 apples and 6 bananas:
 
      int apples = 5;
      int bananas = 6;
      auto as = AliasSeq!("%s apples and %s bananas", apples, bananas); 
 // essentially what an interpolated string will evaluate to
      writefln(as);
      ++apples;
      ++bananas;
      writefln(as);
 
 It seems that AliasSeq doesn't store the alias (ironically), but the 
 value of the expression at the time.
 
 Is there a way that this could work? I mean, aside from storing lambdas 
 for everything?
alias as = AliasSeq!("%s apples and %s bananas", apples, bananas);
Dec 17 2019
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/17/19 12:19 PM, ag0aep6g wrote:
 On 17.12.19 18:12, Steven Schveighoffer wrote:
 Is there a way that this could work? I mean, aside from storing 
 lambdas for everything?
alias as = AliasSeq!("%s apples and %s bananas", apples, bananas);
:facepalm: Thanks! That is pretty cool. Coupled with a logging function: import std.experimental.logger; int apples = 5; int bananas = 6; //equivalent to: alias msg = i"$apples apples and $bananas bananas"; alias msg = AliasSeq!("%s apples and %s bananas", apples, bananas); logf(msg); ++apples; ++bananas; logf(msg); This works pretty well, shows the filename/line numbers, and reevaluates the log message each time. Another cool use case. -Steve
Dec 17 2019
parent reply Meta <jared771 gmail.com> writes:
On Tuesday, 17 December 2019 at 17:31:05 UTC, Steven 
Schveighoffer wrote:
 On 12/17/19 12:19 PM, ag0aep6g wrote:
 On 17.12.19 18:12, Steven Schveighoffer wrote:
 Is there a way that this could work? I mean, aside from 
 storing lambdas for everything?
alias as = AliasSeq!("%s apples and %s bananas", apples, bananas);
:facepalm: Thanks! That is pretty cool. Coupled with a logging function: import std.experimental.logger; int apples = 5; int bananas = 6; //equivalent to: alias msg = i"$apples apples and $bananas bananas"; alias msg = AliasSeq!("%s apples and %s bananas", apples, bananas); logf(msg); ++apples; ++bananas; logf(msg); This works pretty well, shows the filename/line numbers, and reevaluates the log message each time. Another cool use case. -Steve
This got me excited, but unfortunately it doesn't work with expressions (for obvious reasons): // Error: variable apples cannot be read at compile time alias msg = AliasSeq!("%s apples and %s bananas makes %s fruit", apples, bananas, apples + bananas);
Dec 17 2019
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/17/19 1:17 PM, Meta wrote:
 On Tuesday, 17 December 2019 at 17:31:05 UTC, Steven Schveighoffer wrote:
 This works pretty well, shows the filename/line numbers, and 
 reevaluates the log message each time.

 Another cool use case.
This got me excited, but unfortunately it doesn't work with expressions (for obvious reasons): // Error: variable apples cannot be read at compile time alias msg = AliasSeq!("%s apples and %s bananas makes %s fruit", apples, bananas, apples + bananas);
Right, the alias has to be a symbol or a constant. Though you could technically put in a lambda. I don't know if the log/writef would support that. This doesn't mean it's not useful if it can only be a symbol, I predict even without string interpolation, my printf debugging that I generally use is going to be enhanced with this idea. -Steve
Dec 17 2019
prev sibling parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Tuesday, 17 December 2019 at 18:17:30 UTC, Meta wrote:
 This got me excited, but unfortunately it doesn't work with 
 expressions (for obvious reasons):

 // Error: variable apples cannot be read at compile time
 alias msg = AliasSeq!("%s apples and %s bananas makes %s 
 fruit", apples, bananas, apples + bananas);
tuple of lazy args should work probably (i.e. pass through vararg function that has all args marked as lazy. Best regards, Alexandru.
Dec 17 2019
prev sibling parent reply aliak <something something.com> writes:
On Tuesday, 17 December 2019 at 10:14:35 UTC, Patrick Schluter 
wrote:
 On Tuesday, 17 December 2019 at 09:20:06 UTC, Jacob Carlborg 
 wrote:
[...]
Yes, and that was the point of the exercice. Transforming the interpolated "string" into a string evaluates the values of the variables at the moment of that transformation. From then on, there is no interpolation possible as it a simple string. I suppose that what aliak leant in his comments was that the string then could still be used for interpolation. [...]
I'm pretty sure I said that I expect interpolated strings to be assignable to strings and that this DIP doesn't enable that. And people will need to understand tuples to understand what's happening. I'm not sure how you interpreted all the rest?
Dec 17 2019
parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 17 December 2019 at 22:14:32 UTC, aliak wrote:
 On Tuesday, 17 December 2019 at 10:14:35 UTC, Patrick Schluter 
 wrote:
 On Tuesday, 17 December 2019 at 09:20:06 UTC, Jacob Carlborg 
 wrote:
[...]
Yes, and that was the point of the exercice. Transforming the interpolated "string" into a string evaluates the values of the variables at the moment of that transformation. From then on, there is no interpolation possible as it a simple string. I suppose that what aliak leant in his comments was that the string then could still be used for interpolation. [...]
I'm pretty sure I said that I expect interpolated strings to be assignable to strings and that this DIP doesn't enable that. And people will need to understand tuples to understand what's happening. I'm not sure how you interpreted all the rest?
The question is, what is that string supposed to contain. The resolved interpolation ("apple = 0") or the interpolation string ("apple = $(apple)").
Dec 18 2019
prev sibling parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Monday, 16 December 2019 at 11:18:33 UTC, Patrick Schluter 
wrote:
 On Monday, 16 December 2019 at 11:08:00 UTC, Patrick Schluter 
 wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:

 Resolving interpolation at compile time is imho incompatible
with handling them as regular strings.
Maybe I'm wrong here, I haven't thought it through, but in first approach I think that's an essential point. As the string contains code, if evaluated at CT, the string must be split somehow in literal parts and code parts. Allowing the i-string to be handled as regular string implies that the splitting happens sometime between when it is declared and after it is used, which can happen after runtime. import fn; int b = 20; string inter = i"$(a+b)"; foreach(a; 1..10) fn(inter); --- module fn; void fn(string s) { writefln(s); } How would that work? In python or javascript there's no issue, a is a runtime symbol.
 The question is then do we want CT or RT interpolated strings. 
 RT interpolated strings can still be provided by a library.
Well there is a issue in javascript, interpolated string are evaluated once met in code by interpreter and are not somehow delayed at later stage as in your example. Here is a test case: ``` var c = 40 var s = `${a + b} ${c}` var a = 10 var b = 20 console.log(s) ``` The result is: Nan 40 Best regards, Alexandru
Dec 17 2019
prev sibling parent reply aliak <something something.com> writes:
On Monday, 16 December 2019 at 11:08:00 UTC, Patrick Schluter 
wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 [...]
because string s = ("%s",var); is a syntax error.
Exactly. And then explain why. And what is that thing on the right. And why is string assignment not working on an interpolated _string_?
 Even a beginning programmer can understand that an interpolated 
 string cannot be a pure simple string as it contains symbols 
 and expressions that are language construct not part of the 
 string literal, i.e. that the compiler has to perform some 
 transformations to substitute these language symbols into a 
 value.
 Interpolated strings, in any language, are not string literals.
In any language, they can be assigned to strings.
 Each language resolves this fact in different manners and at 
 different times. Interpreted languages do it at runtime 
 (obviously), java like languages chose to do it at runtime. In 
 a language like D, which prefers resolving what is resolvable 
 at compile time, it would be loathed if it interpolation was 
 resolved at runtime (remember how long people were bitching 
 about runtime only format strings?)
 Resolving interpolation at compile time is imho incompatible 
 with handling them as regular strings.

 The question is then do we want CT or RT interpolated strings. 
 RT interpolated strings can still be provided by a library.
See Adam's previous posts on his approach.
Dec 16 2019
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 16 December 2019 at 11:38:34 UTC, aliak wrote:
 On Monday, 16 December 2019 at 11:08:00 UTC, Patrick Schluter 
 wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 [...]
because string s = ("%s",var); is a syntax error.
Exactly. And then explain why. And what is that thing on the right. And why is string assignment not working on an interpolated _string_?
 Even a beginning programmer can understand that an 
 interpolated string cannot be a pure simple string as it 
 contains symbols and expressions that are language construct 
 not part of the string literal, i.e. that the compiler has to 
 perform some transformations to substitute these language 
 symbols into a value.
 Interpolated strings, in any language, are not string literals.
In any language, they can be assigned to strings.
Not true for some languages I checked string is not a string and has to be converted with .toString which is equivalent in calling .format in D. - Rust and Java do not have interpolated strings - Swift I don't know. Looks powerful but in a whole different difficulty level. all others are interpreters python, perl, ruby, bash, tcl, VB, PHP etc. for whom it is much easier as there is no distinction between CT and RT.
 Each language resolves this fact in different manners and at 
 different times. Interpreted languages do it at runtime 
 (obviously), java like languages chose to do it at runtime. In 
 a language like D, which prefers resolving what is resolvable 
 at compile time, it would be loathed if it interpolation was 
 resolved at runtime (remember how long people were bitching 
 about runtime only format strings?)
 Resolving interpolation at compile time is imho incompatible 
 with handling them as regular strings.

 The question is then do we want CT or RT interpolated strings. 
 RT interpolated strings can still be provided by a library.
See Adam's previous posts on his approach.
// Use reduce to calculate the sum // of all squares in parallel. auto result = taskPool.reduce!"a+b"( 0.0, iota(100).map!"a*a"); writeln("Sum of squares: ", result);
Dec 16 2019
next sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 16 December 2019 at 12:43:04 UTC, Patrick Schluter 
wrote:

 // Use reduce to calculate the sum
     // of all squares in parallel.
     auto result = taskPool.reduce!"a+b"(
         0.0, iota(100).map!"a*a");
     writeln("Sum of squares: ", result);
Ignore that random crap at the end of my post. It was a copy paste accident.
Dec 16 2019
prev sibling parent aliak <something something.com> writes:
On Monday, 16 December 2019 at 12:43:04 UTC, Patrick Schluter 
wrote:
 On Monday, 16 December 2019 at 11:38:34 UTC, aliak wrote:
 On Monday, 16 December 2019 at 11:08:00 UTC, Patrick Schluter 
 wrote:
 [...]
Exactly. And then explain why. And what is that thing on the right. And why is string assignment not working on an interpolated _string_?
 [...]
In any language, they can be assigned to strings.
Not true for some languages I checked interpolated string is not a string and has to be converted with .toString which is equivalent in calling .format in D. - Rust and Java do not have interpolated strings - Swift I don't know. Looks powerful but in a whole different difficulty level.
You can assign strings to interpolated strings in all these languages you mentioned that have interpolated string support Kotlin: var x = 3 var s: String = "$x" + "$x" Swift: let x = 3 let y: String = "\(x)" string n = "hello"; string x = $"{n}";
Dec 16 2019
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 On Monday, 16 December 2019 at 01:35:51 UTC, Walter Bright 
 wrote:
 On 12/15/2019 2:17 AM, Aliak wrote:
 To use it people will need to understand how to use d tuples 
 as well.
No, they don't.
User: why can't I do this?/Why doesn't this work? string s = i"$var"; Answer?
import std.format: format; string s = format(i"$var");
Dec 16 2019
next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Monday, 16 December 2019 at 13:22:45 UTC, Atila Neves wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 User: why can't I do this?/Why doesn't this work?

 string s = i"$var";

 Answer?
import std.format: format; string s = format(i"$var");
That isn't an answer to the question, it's just a workaround. Interpolated strings could implicitly convert to strings, which is the most common use case in typical D code. That would not bloat code that doesn't need it, as Adam has shown by using an import inside a template. Interpolated strings should not be designed with low-level concerns as the priority motivator at the cost of high level usability and safety. D is supposed to be a type safe language, even std.format.format is not fully type safe because using string for a format string allows runtime errors. Any good D interpolation proposal would support compile time checked format strings, even when runtime arguments are passed. D is supposed to be the best language for compile time stuff!
Dec 16 2019
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/16/2019 6:00 AM, Nick Treleaven wrote:
 On Monday, 16 December 2019 at 13:22:45 UTC, Atila Neves wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 User: why can't I do this?/Why doesn't this work?

 string s = i"$var";

 Answer?
import std.format: format; string s = format(i"$var");
That isn't an answer to the question, it's just a workaround. Interpolated strings could implicitly convert to strings, which is the most common use case in typical D code. That would not bloat code that doesn't need it, as Adam has shown by using an import inside a template. Interpolated strings should not be designed with low-level concerns as the priority motivator at the cost of high level usability and safety. D is supposed to be a type safe language, even std.format.format is not fully type safe because using string for a format string allows runtime errors. Any good D interpolation proposal would support compile time checked format strings, even when runtime arguments are passed. D is supposed to be the best language for compile time stuff!
Having it go directly to a string has multiple problems: 1. Those who want the tuple in order to do something else with it will be unhappy and out of luck. 2. It will not work with betterC. 3. It will allocate GC memory. 4. It will be substantially slower because of the extra intermediate buffer. 5. I don't think it'll work with Steven Schweighoffer's SQL examples. 6. It will require the core language to depend on a rather large and complex Phobos routine. 7. It will not be any more typesafe than it would be generating a tuple. 8. The number of times I've wanted a formatted string as the end result, as opposed to wanting formatted insertion into something else, is about 1 in 100, if that.
Dec 16 2019
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On Monday, 16 December 2019 at 21:42:32 UTC, Walter Bright wrote:

 Having it go directly to a string has multiple problems:

 1. Those who want the tuple in order to do something else with 
 it will be unhappy and out of luck.

 2. It will not work with betterC.

 3. It will allocate GC memory.

 4. It will be substantially slower because of the extra 
 intermediate buffer.

 5. I don't think it'll work with Steven Schweighoffer's SQL 
 examples.

 6. It will require the core language to depend on a rather 
 large and complex Phobos routine.

 7. It will not be any more typesafe than it would be generating 
 a tuple.

 8. The number of times I've wanted a formatted string as the 
 end result, as opposed to wanting formatted insertion into 
 something else, is about 1 in 100, if that.
It doesn't need to go directly to a string. Just the end result needs to be a string. In Swift they achieve this by lowering the string interpolation to a set of method calls: "The time is \(time)." Is lowered to something like: var interpolation = MyString.StringInterpolation(literalCapacity: 13, interpolationCount: 1) interpolation.appendLiteral("The time is ") interpolation.appendInterpolation(time) interpolation.appendLiteral(".") MyString(stringInterpolation: interpolation) These methods are overridable to be able to customize the behavior. -- /Jacob Carlborg
Dec 17 2019
parent Jacob Carlborg <doob me.com> writes:
On Tuesday, 17 December 2019 at 08:55:36 UTC, Jacob Carlborg 
wrote:

 It doesn't need to go directly to a string. Just the end result 
 needs to be a string. In Swift they achieve this by lowering 
 the string interpolation to a set of method calls:

 "The time is \(time)."

 Is lowered to something like:

 var interpolation = 
 MyString.StringInterpolation(literalCapacity: 13,
                                                  
 interpolationCount: 1)

 interpolation.appendLiteral("The time is ")
 interpolation.appendInterpolation(time)
 interpolation.appendLiteral(".")

 MyString(stringInterpolation: interpolation)

 These methods are overridable to be able to customize the 
 behavior.
With this implementation SwiftUI supports internationalization of string literals with interpolation. -- /Jacob Carlborg
Dec 17 2019
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Monday, 16 December 2019 at 21:42:32 UTC, Walter Bright wrote:
 On 12/16/2019 6:00 AM, Nick Treleaven wrote:
 Interpolated strings could implicitly convert to strings, 
 which is the most common use case in typical D code. That 
 would not bloat code that doesn't need it, as Adam has shown 
 by using an import inside a template.
 
 Interpolated strings should not be designed with low-level 
 concerns as the priority motivator at the cost of high level 
 usability and safety.
 
 D is supposed to be a type safe language, even 
 std.format.format is not fully type safe because using string 
 for a format string allows runtime errors.
 
 Any good D interpolation proposal would support compile time 
 checked format strings, even when runtime arguments are 
 passed. D is supposed to be the best language for compile time 
 stuff!
Having it go directly to a string has multiple problems:
I said implicitly convert. If it lowers to a templated struct, it can still be used without converting to string - see below.
 1. Those who want the tuple in order to do something else with 
 it will be unhappy and out of luck.
struct FormatSeq(S...) { /// the sequence for e.g. printf S expand; alias get this; property string get()() // template, doesn't link Phobos unless needed { import std.format; return format(expand); } } unittest { int i = 5; string s = "hi"; //auto fs = i"$i, $s"; auto fs = FormatSeq!(string, int, string)("%s, %s", i, s); //lowering import std.stdio; writefln(fs.expand); // works as format string string s2 = fs; // works as string implicitly too s2.writeln; }
 2. It will not work with betterC.
 3. It will allocate GC memory.
 4. It will be substantially slower because of the extra 
 intermediate buffer.
None of these points are true, just use `.expand` and avoid the alias this.
 5. I don't think it'll work with Steven Schweighoffer's SQL 
 examples.
The above get method would do the wrong thing, yes. Perhaps if the format string is a struct template value parameter, the code can detect that custom specifiers have been used and statically disable the get method.
 6. It will require the core language to depend on a rather 
 large and complex Phobos routine.
Only if the alias this is actually used - it's a template. The precedent for lowering to Phobos is the ^^ operator which IIRC lowers to std.math.pow.
 7. It will not be any more typesafe than it would be generating 
 a tuple.
The common case for creating a string is seamless and can't be done wrong when using alias this, which is also the easiest way to use it. printf could be wrapped with a method, and the format string could be checked at compile-time when it's a literal.
 8. The number of times I've wanted a formatted string as the 
 end result, as opposed to wanting formatted insertion into 
 something else, is about 1 in 100, if that.
So just put .expand after the interpolated string. For *every* programming language I'm aware of, interpolated strings implicitly convert to a string. If it really is as commonly needed as you think, you can add wrapper methods to the struct so you even avoid importing core.stdc or std.stdio.
Dec 17 2019
prev sibling parent reply aliak <something something.com> writes:
On Monday, 16 December 2019 at 13:22:45 UTC, Atila Neves wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 On Monday, 16 December 2019 at 01:35:51 UTC, Walter Bright 
 wrote:
 On 12/15/2019 2:17 AM, Aliak wrote:
 To use it people will need to understand how to use d tuples 
 as well.
No, they don't.
User: why can't I do this?/Why doesn't this work? string s = i"$var"; Answer?
import std.format: format; string s = format(i"$var");
This is non obvious. And only explainable by mentioning tuples.
Dec 16 2019
next sibling parent aliak <something something.com> writes:
On Monday, 16 December 2019 at 14:02:17 UTC, aliak wrote:
 On Monday, 16 December 2019 at 13:22:45 UTC, Atila Neves wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 On Monday, 16 December 2019 at 01:35:51 UTC, Walter Bright 
 wrote:
 On 12/15/2019 2:17 AM, Aliak wrote:
 To use it people will need to understand how to use d 
 tuples as well.
No, they don't.
User: why can't I do this?/Why doesn't this work? string s = i"$var"; Answer?
import std.format: format; string s = format(i"$var");
This is non obvious. And only explainable by mentioning tuples.
In other words. You didn't answer anything. You just told the user what to do with no explanation as to why that has to be done.
Dec 16 2019
prev sibling parent mipri <mipri minimaltype.com> writes:
On Monday, 16 December 2019 at 14:02:17 UTC, aliak wrote:
 On Monday, 16 December 2019 at 13:22:45 UTC, Atila Neves wrote:
 On Monday, 16 December 2019 at 10:48:51 UTC, aliak wrote:
 On Monday, 16 December 2019 at 01:35:51 UTC, Walter Bright
 wrote:
 On 12/15/2019 2:17 AM, Aliak wrote:
 To use it people will need to understand how to use d
 tuples as well.
No, they don't.
User: why can't I do this?/Why doesn't this work? string s = i"$var"; Answer?
import std.format: format; string s = format(i"$var");
This is non obvious. And only explainable by mentioning tuples.
It's worse than non-obvious: it's contrary to expectation. It's something that docs are going to have to explain and justify. It's something that people are going to want the compiler to special case if only for a useful error message. And you get the same problem in void greet(string name) { writeln("Hello, ", name); } void main(string[] args) { string title = "Mr."; greet(i"$title $(args[1])"); } Error: function myfirstdprogram.greet(string name) is not callable using argument types (string, string, string) // But I'm never calling greet with three strings? Why is it // saying the error is on a line with only one string? It is, however, not that hard to explain and justify. That it works for assigning the parameters is a little weird. That it works for SQL is pretty cool. That it works for translation is, actually, a very worthwhile innovation and a good reason to keep the proposed behavior even if it's weird. And 'tuples' in this sense do come up in other languages: https://stackoverflow.com/questions/2322355/proper-name-for-python-operator In terms of "reasons people get confused or doubtful and wander away from D" I don't think it'll come anywhere close to someone trying to make std.range and std.algorithm work while not having a great understanding of how they're implemented or why. Still, some way to at least auto-import and auto-use format() would be nice (if adding to -betterC caveats). If functions accepting a printf-style string just had a different type, extern(C) snprintf(scope char* s, size_t n, scope const ichar* format, ...); then format() could be auto-invoked in string-typed i"" and you get the benefits without the immediate blow to new users. Of course then you have to justify all the different char types, including combinations, whether idchar vs. dichar is the valid one. It's gross, so I can understand why it's already been mentioned and discarded as an option in the thread, but it just seems inevitable that if DIP 1027 is added without some kind of hack like this, that one will get added on later anyway, after people keep complaining that D's interpolation is wrong or weird.
Dec 16 2019
prev sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Sunday, 15 December 2019 at 04:20:59 UTC, Walter Bright wrote:
 object.d is getting more and more bloated over time. This is 
 not a solution to imports, and is not a good trend.
A bit other topic, but this can be fixed by splitting object.d in multiple modules in same package, and auto import that package, just like how it is done in java with java.lang package. For example, object.d could be split into several modules under d.lang package. This will also clean existing bloatware, since we could move typeinfo, object definition and other stuff into separated modules. Best regards, Alexandru.
Dec 15 2019
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 15/12/2019 11:33 PM, Alexandru Ermicioi wrote:
 On Sunday, 15 December 2019 at 04:20:59 UTC, Walter Bright wrote:
 object.d is getting more and more bloated over time. This is not a 
 solution to imports, and is not a good trend.
A bit other topic, but this can be fixed by splitting object.d in multiple modules in same package, and auto import that package, just like how it is done in java with java.lang package. For example, object.d could be split into several modules under d.lang package. This will also clean existing bloatware, since we could move typeinfo, object definition and other stuff into separated modules. Best regards, Alexandru.
Yes please.
Dec 15 2019
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/15/2019 2:33 AM, Alexandru Ermicioi wrote:
 On Sunday, 15 December 2019 at 04:20:59 UTC, Walter Bright wrote:
 object.d is getting more and more bloated over time. This is not a solution to 
 imports, and is not a good trend.
A bit other topic, but this can be fixed by splitting object.d in multiple modules in same package, and auto import that package, just like how it is done in java with java.lang package. For example, object.d could be split into several modules under d.lang package. This will also clean existing bloatware, since we could move typeinfo, object definition and other stuff into separated modules.
The reality is that compilation time is more proportional to the number of files than the size of the files. Splitting up object.d into multiple modules that must still be loaded will make things slower. Also, splitting it up into multiple modules does not eliminate the complexity of it.
Dec 16 2019
parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Monday, 16 December 2019 at 09:34:00 UTC, Walter Bright wrote:
 On 12/15/2019 2:33 AM, Alexandru Ermicioi wrote:
 On Sunday, 15 December 2019 at 04:20:59 UTC, Walter Bright 
 wrote:
 object.d is getting more and more bloated over time. This is 
 not a solution to imports, and is not a good trend.
A bit other topic, but this can be fixed by splitting object.d in multiple modules in same package, and auto import that package, just like how it is done in java with java.lang package. For example, object.d could be split into several modules under d.lang package. This will also clean existing bloatware, since we could move typeinfo, object definition and other stuff into separated modules.
The reality is that compilation time is more proportional to the number of files than the size of the files. Splitting up object.d into multiple modules that must still be loaded will make things slower.
I doubt someone will complain, about splitting object module into smaller packages based on performance reasons, and certainly splitting object.d won't trigger tens of files now. Though as said before it will increase readability. I personally can live with few more miliseconds for compilation time if readability is increased in druntime/phobos. Best regards, Alexandru.
Dec 17 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/17/2019 6:19 AM, Alexandru Ermicioi wrote:
 I doubt someone will complain, about splitting object module into smaller 
 packages based on performance reasons, and certainly splitting object.d won't 
 trigger tens of files now. Though as said before it will increase readability.
I 
 personally can live with few more miliseconds for compilation time if 
 readability is increased in druntime/phobos.
People often complain as DMD's compile speed steadily deteriorates. A few more milliseconds at a time add up.
Dec 20 2019
prev sibling parent reply Andre Pany <andre s-e-a-p.de> writes:
On Sunday, 15 December 2019 at 01:52:20 UTC, Adam D. Ruppe wrote:

 string a = i"";
This is for me the most important thing for string interpolation. A convenient string assignment. If this is not convenient, it destroys the great feature of string interpolation. Walter, could you please make it happen? Kind regards Andre
Dec 15 2019
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Sunday, 15 December 2019 at 09:30:45 UTC, Andre Pany wrote:
 string a = i"";
This is for me the most important thing for string interpolation. A convenient string assignment. If this is not convenient, it destroys the great feature of string interpolation. Walter, could you please make it happen? Kind regards Andre
Careful that if that happens, then it may be another feature that can't be used without a runtime. As it stands, it is usable with snprintf nogc and that's pretty cool in my book.
Dec 15 2019
parent reply Jab <jab_293 gmall.com> writes:
On Sunday, 15 December 2019 at 15:36:09 UTC, Guillaume Piolat 
wrote:
 On Sunday, 15 December 2019 at 09:30:45 UTC, Andre Pany wrote:
 string a = i"";
This is for me the most important thing for string interpolation. A convenient string assignment. If this is not convenient, it destroys the great feature of string interpolation. Walter, could you please make it happen? Kind regards Andre
Careful that if that happens, then it may be another feature that can't be used without a runtime. As it stands, it is usable with snprintf nogc and that's pretty cool in my book.
There's no reason it can't be implicitly converted to a string. You could also easily write a nogc wrapper if it outputs a tuple. It being usable with snprintf() means it outputs something that pretty much no other function uses. The only thing I know of that implements printf-style formatting is printf (or uses sprintf to implement it). All other use cases (the more common ones) this becomes a useless feature. Ultimately this DIP is trying to push a library specific detail (from another language) into D. That's just a bad idea.
Dec 15 2019
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 15 December 2019 at 17:26:57 UTC, Jab wrote:
 It being usable with snprintf() means it outputs something that 
 pretty much no other function uses.
D's writef uses it too, as well as std.format. Do do the vibe logging functions. It is a common format. (though D's writef is supposed to replace C's printf... for great part because of type safety.))
Dec 15 2019
next sibling parent reply mipri <mipri minimaltype.com> writes:
On Sunday, 15 December 2019 at 17:38:29 UTC, Adam D. Ruppe wrote:
 On Sunday, 15 December 2019 at 17:26:57 UTC, Jab wrote:
 It being usable with snprintf() means it outputs something 
 that pretty much no other function uses.
D's writef uses it too, as well as std.format. Do do the vibe logging functions. It is a common format.
Which brings this to mind: import std.stdio; void main() { int n, m; write("input: "); readf(i"$n - $m"); writeln(n + m); } As used: $ ./test input: 2 - 8 10 When's the last time you saw string interpolation that resulted in the variables getting set to new values?
Dec 15 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 15 December 2019 at 17:50:56 UTC, mipri wrote:
 When's the last time you saw string interpolation
 that resulted in the variables getting set to new
 values?
I actually think that is a cool feature of the proposal. (though i hate readf, the general idea of populating placeholders is a nice one)
Dec 15 2019
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/15/2019 10:03 AM, Adam D. Ruppe wrote:
 I actually think that is a cool feature of the proposal. (though i hate readf, 
 the general idea of populating placeholders is a nice one)
It works with scanf, too, though I never use scanf.
Dec 15 2019
prev sibling parent reply Jab <jab_293 gmall.com> writes:
On Sunday, 15 December 2019 at 17:38:29 UTC, Adam D. Ruppe wrote:
 On Sunday, 15 December 2019 at 17:26:57 UTC, Jab wrote:
 It being usable with snprintf() means it outputs something 
 that pretty much no other function uses.
D's writef uses it too, as well as std.format. Do do the vibe logging functions. It is a common format. (though D's writef is supposed to replace C's printf... for great part because of type safety.))
Literally the next sentence:
 The only thing I know of that implements printf-style 
 formatting is printf (or uses sprintf to implement it).
This is going to add a feature to the language that is dependent on a library feature. Even though the compiler creates and verifies the format strings, it's going to have to re-parse the format string at runtime anyways. Implementing string interpolation will just grow the dependency on printf/sprintf. Cause like I said, no other function really actually implements that formatting scheme themselves. This limits and over-complicates the code around it.
Dec 15 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 15 December 2019 at 20:07:23 UTC, Jab wrote:
 Literally the next sentence:
writef is neither printf nor does it use sprintf to implement it (except for floating point types... much to the chagrin of would-be CTFE users). D embraced printf's format and re-implemented it a long time ago.
Dec 15 2019
parent Jab <jab_293 gmall.com> writes:
On Sunday, 15 December 2019 at 20:15:38 UTC, Adam D. Ruppe wrote:
 for floating point types
Exactly.
Dec 15 2019
prev sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
On Sunday, 15 December 2019 at 17:26:57 UTC, Jab wrote:
 On Sunday, 15 December 2019 at 15:36:09 UTC, Guillaume Piolat

 There's no reason it can't be implicitly converted to a string.
Okay. Let's say this would compile: int stuff = 4; string s = i"my interpolated %stuff string"; Where should the result of i"my interpolated %stuff string" be allocated? If you answer "with the GC", then this feature requires the runtime...
Dec 15 2019
next sibling parent Jab <jab_293 gmall.com> writes:
On Sunday, 15 December 2019 at 18:25:40 UTC, Guillaume Piolat 
wrote:
 On Sunday, 15 December 2019 at 17:26:57 UTC, Jab wrote:
 On Sunday, 15 December 2019 at 15:36:09 UTC, Guillaume Piolat

 There's no reason it can't be implicitly converted to a string.
Okay. Let's say this would compile: int stuff = 4; string s = i"my interpolated %stuff string"; Where should the result of i"my interpolated %stuff string" be allocated? If you answer "with the GC", then this feature requires the runtime...
"Implicitly converted" meaning it exists as something else and can be converted to it. If you don't want the GC then don't use a string. nogc: int stuff = 4; auto t = i"my interpolated %stuff string"; string s = mallocString(t); // no different than having to call malloc() + snprintf()
Dec 15 2019
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 15 December 2019 at 18:25:40 UTC, Guillaume Piolat 
wrote:
 If you answer "with the GC", then this feature requires the 
 runtime...
That's exactly what mine would do. But at the same time, with mine, you could *also* do snprintf(buffer.ptr, buffer.length, i"foo %bar".c.tupleof); Check out a draft hacky 100% library implementation here: http://arsdnet.net/inter.d the compiler can do a slightly better job avoiding the copying of values (the library can too... but not if you also want all three: RT+CT compat, C function compat, and expressions in the interpolated string. It is a kinda pick any two. Unless I'm missing a cool trick. But the compiler can express more than the library.)
Dec 15 2019
parent Guillaume Piolat <first.last gmail.com> writes:
On Sunday, 15 December 2019 at 20:32:38 UTC, Adam D. Ruppe wrote:
 On Sunday, 15 December 2019 at 18:25:40 UTC, Guillaume Piolat 
 wrote:
 If you answer "with the GC", then this feature requires the 
 runtime...
That's exactly what mine would do.
On second thought, it's true interpolated string are most wanted _when generating website pages_ and it's not like we would miss it that much in -betterC / or with disabled runtime.
Dec 15 2019
prev sibling parent Seb <seb wilzba.ch> writes:
On Sunday, 15 December 2019 at 01:44:18 UTC, Walter Bright wrote:
 On 12/14/2019 6:23 AM, Adam D. Ruppe wrote:
 On Saturday, 14 December 2019 at 09:10:47 UTC, Walter Bright 
 wrote:
 I find your proposal a little confusing. By turning the 
 string into an object, it doesn't work with printf?
Right, not directly. But then it is trivial to add a member of the object that transforms it into a tuple suitable for printf. So the end user's code now looks like: `printf(i"foo %bar".asFormatTuple);`
I was afraid that would be it. The extra syntax kills it,
I highly doubt that modern D applications use printf enough that we should cater so much for it. Anyhow, I don't see why we couldn't add an overload even for printf in druntime if the .toString or .asFormatTuple is too much syntax.
 along with the extra import required,
It's a member of the struct. No import required.
 along with not working with #betterC.
Why? I don't see an argument for this. The interpolated struct is templated, so the compiler would generate a new instance properly. In fact, even a potential printf overload in druntime would still work with #worseD as long as its templated.
Dec 15 2019
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 11:30 PM, mipri wrote:
    void takes_a_normal_string(string s) { }
 
    takes_a_normal_string(i"%one + %two = %(one + two).");
I'm not sure what you expect that to do?
Dec 13 2019
parent mipri <mipri minimaltype.com> writes:
On Friday, 13 December 2019 at 08:54:08 UTC, Walter Bright wrote:
 On 12/11/2019 11:30 PM, mipri wrote:
    void takes_a_normal_string(string s) { }
 
    takes_a_normal_string(i"%one + %two = %(one + two).");
I'm not sure what you expect that to do?
Complete example: import std.stdio; void takes_a_normal_string(string s) { writeln(s); } void main() { immutable one = 1, two = 2; takes_a_normal_string(i"%one + %two = %(one + two)."); } Output: 1 + 2 = 3 But, this works with DIP 1027, so I think it's fine: import std.format; ... takes_a_normal_string(i"%one + %two = %(one + two).".format);
Dec 13 2019
prev sibling next sibling parent aliak <something something.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 All review-related feedback on and discussion of the DIP should 
 occur in this thread. The review period will end at 11:59 PM ET 
 on December 25, or when I make a post declaring it complete.

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of Community 
 Review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment.

 Anyone intending to post feedback in this thread is expected to 
 be familiar with the reviewer guidelines:

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

 *Please stay on topic!*

 Thanks in advance to all who participate.
1. The DIP fails to mention why this has been chosen as better over the other alternatives out there. 2. Why %? a) it clashes with format specifiers, sounds like a bad idea. b) it's more common in text than other alternatives (e.g. $) which means it increases making the user escape text. 3. How does this work with normal strings? And token strings? One use-case I've been looking forward to is generative programming with token strings and interpolated strings. This doesn't seem to help there? If not, why a half solution? If it does, then maybe an example? 4. How is this handled? auto d = 7; writefln(i"I ate %apples and %{d}bananas totalling %(apples + bananas) fruit."); // bug? silent failure? compiler error? Does it do what the user expects? 5. I believe you can do everything this DIP does with a better syntax -> "$itemPrice%.2f" where $ is the identifier and after the % is the formatting. And you don't have to deal with that * runtime error 6. What's the rationale behind allowing anything other than %s? The type of variable can be inferred? Cheers, - Ali
Dec 11 2019
prev sibling next sibling parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 All review-related feedback on and discussion of the DIP should 
 occur in this thread. The review period will end at 11:59 PM ET 
 on December 25, or when I make a post declaring it complete.

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of Community 
 Review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment.

 Anyone intending to post feedback in this thread is expected to 
 be familiar with the reviewer guidelines:

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

 *Please stay on topic!*

 Thanks in advance to all who participate.
Lowering interpolated strings to a format string and a tuple of values rather than just a tuple is less versatile than other solutions that have previously been proposed. This DIP pigeon-holes interpolated strings for one use case. Interpolated strings can be used for more than just creating strings. They are just a pretty syntax to interleave string literals and expressions. This solution is assuming the user will only use this for string formatting, but that's not necessarily the case. My original proposal lowered it directly to a tuple of string literals and expressions (https://github.com/dlang/dmd/pull/7988) and Adam Ruppe's proposal (http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html) lowered it to a custom type where the same tuple could be accessed via a field. These solutions provide more versatility and are just as easy to print and format into strings with a single function call. Adam Ruppe's proposal was more complex than my own but improved versatility (i.e. added a method to convert it to a string without importing a module, allowed functions to overload on interpoated strings, provided access to the original raw un-interpolated string, etc). The problem with this DIP is that it's both more complex than my original proposal and less versatile. The other problem with this DIP is how it handles consecutive interpolated strings. Consider a case where you'd like to write a message with consecutive interpolated strings (see real life example here https://github.com/dlang/dmd/pull/7988/files#diff-685230fdddcb87fcbb4a344b264a2fb6L736): // using this DIP writefln(i" ... %a ... ", i" ... %b ... "); // becomes writefln(" ... %s ... ", a, " ... %s ... ", b); // that doesn't work, so you'd have to do this writeln(i" ... $(a) ... ".format, i" ... $(b) ... ".format); // by lowering to a tuple, you would get this writeln(i" ... %a ... ", i" ... %b ... "); // becomes writeln(" ... ", a, " ... ", " ... ", b, " .. "); I also don't see any mention of my proposal in the DIP in "Prior Work" or how this DIP compares to my proposal or Adam's.
Dec 11 2019
next sibling parent Martin Tschierschke <mt smartdolphin.de> writes:
On Thursday, 12 December 2019 at 05:07:44 UTC, Jonathan Marler 
wrote:
[...]
 I also don't see any mention of my proposal in the DIP in 
 "Prior Work" or how this DIP compares to my proposal or Adam's.
I think this is really important, because ignoring their work in the DIP is not encouraging. We all try to get the best solution and in speaking in general the DIP is taking care of a really useful feature I am missing. When I saw the first examples in vibe.d templates using ruby like
Dec 12 2019
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/12/19 12:07 AM, Jonathan Marler wrote:
 
 Lowering interpolated strings to a format string and a tuple of values 
 rather than just a tuple is less versatile than other solutions that 
 have previously been proposed.  This DIP pigeon-holes interpolated 
 strings for one use case.  Interpolated strings can be used for more 
 than just creating strings.  They are just a pretty syntax to interleave 
 string literals and expressions. This solution is assuming the user will 
 only use this for string formatting, but that's not necessarily the case.
Indeed, one can potentially have more use cases than format string plus tuple. That is one thing I don't like about it. But any technique we use to forward tuples and string formatting to a function is going to require adjustment in some cases, and work as-is in others. We did have problems with the straight tuple lowering (i.e. how do you tell which part was string literal and which parts were parameters). the new proposal handles that quite well in fact. Not to say that this isn't solvable, but I do like that aspect of the new DIP -- the string literal parts are clearly defined. It definitely needs changing from its current mechanism (the requirement of % for placeholder is too limiting IMO). One thing that might make things more useful -- if the compiler could define a new type istring, which is a derivative of string literal, and one could accept that as a parameter type for purposes of overloads if needed.
 My original proposal lowered it directly to a tuple of string literals 
 and expressions (https://github.com/dlang/dmd/pull/7988) and Adam 
 Ruppe's proposal 
 (http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html) lowered 
 it to a custom type where the same tuple could be accessed via a field.  
 These solutions provide more versatility and are just as easy to print 
 and format into strings with a single function call. Adam Ruppe's 
 proposal was more complex than my own but improved versatility (i.e. 
 added a method to convert it to a string without importing a module, 
 allowed functions to overload on interpoated strings, provided access to 
 the original raw un-interpolated string, etc).  The problem with this 
 DIP is that it's both more complex than my original proposal and less 
 versatile.
I think all of them are somewhat equally versatile. With a mechanism to specify how to generate the format string, such as H. S. Toeh suggested, I think Walter's proposal is just as useful as yours or Adam's. All of them provide somewhat similar transformations, just the ordering of the string parts and the non-string parts are different. Unfortunately, I don't know if there's a way to forward the "tuple-ness" of the result by wrapping it if you needed to convert something. Even though Adam's proposal allows one to translate between what the compiler generates and what is needed, it copies the tuple into a type, which may not be what you want (e.g. Walter's example for apples, apples is an lvalue, but in Adam's it would always be an rvalue). There are limitations in yours as well, I like the ability to specify the formatting of the individual items, which would be difficult if not clunky in your proposal.
 
 The other problem with this DIP is how it handles consecutive 
 interpolated strings.  Consider a case where you'd like to write a 
 message with consecutive interpolated strings (see real life example 
 here 
 https://github.com/dlang/dmd/pull/7988/files#diff-685230fdddcb87fcbb
a344b264a2fb6L736): 
 
 
 // using this DIP
 writefln(i" ... %a ... ", i" ... %b ... ");
 // becomes
 writefln(" ... %s ... ", a, " ... %s ... ", b);
 // that doesn't work, so you'd have to do this
 writeln(i" ... $(a) ... ".format, i" ... $(b) ... ".format);
that does pose a slight problem, but one could potentially handle that with concatenation (i.e. concatenation of two interpolated strings results in the same thing as if you concatenated the two string literals and slapped i on the front).
 
 I also don't see any mention of my proposal in the DIP in "Prior Work" 
 or how this DIP compares to my proposal or Adam's.
 
This should be rectified. -Steve
Dec 12 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2019 9:07 PM, Jonathan Marler wrote:
 I also don't see any mention of my proposal in the DIP in "Prior Work"
Indeed that is my fault and I'll fix that.
Dec 14 2019
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":
In my opinion, the semantics of string interpolation need to support: * The type of an interpolated string should be the same as a regular string. That means that the following should work: auto foo = 3; auto b = i"%foo"; static assert(is(typeof(b) == string)); * It should support both interpolating expressions and, with a shorter syntax, symbols, example: auto foo = 3; auto bar = 4; auto a = i"%foo" // interpolation of symbol auto b = i"%(foo + bar)" // interpolation of expression * It should not be tied to specific functions, like `printf` or `writef` * It needs to be possible to identify which part is a literal string and which part is an interpolation * A way to customize how the interpolation is performed. This I'm not sure how to do best. There are a couple of alternatives. In Swift string interpolation is lower to method calls [1]: "The time is \(time)." Is lowered to something like: var interpolation = MyString.StringInterpolation(literalCapacity: 13, interpolationCount: 1) interpolation.appendLiteral("The time is ") interpolation.appendInterpolation(time) interpolation.appendLiteral(".") MyString(stringInterpolation: interpolation) When it comes to the syntax. I think the existing suggestion to use `%` is bad, it's just going to cause conflicts with format specifiers for functions like `printf`. I would prefer to use the dollar sign, i.e. `$foo` and `$(a + b)`. [1] https://developer.apple.com/documentation/swift/stringinterpolationprotocol -- /Jacob Carlborg
Dec 13 2019
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/13/2019 5:11 AM, Jacob Carlborg wrote:
 * The type of an interpolated string should be the same as a regular string. 
 That means that the following should work:
 
 auto foo = 3;
 auto b = i"%foo";
 static assert(is(typeof(b) == string));
That doesn't work because semantic analysis will convert it into a tuple.
 * It should support both interpolating expressions and, with a shorter syntax, 
 symbols, example:
 
 auto foo = 3;
 auto bar = 4;
 auto a = i"%foo" // interpolation of symbol
 auto b = i"%(foo + bar)" // interpolation of expression
It only makes sense if foo is an expression.
 * It should not be tied to specific functions, like `printf` or `writef`
It works with anything that accepts a tuple.
 * It needs to be possible to identify which part is a literal string and which 
 part is an interpolation
I agree that is the whole point, and the proposal does that.
 * A way to customize how the interpolation is performed. This I'm not sure how 
 to do best. There are a couple of alternatives. In Swift string interpolation
is 
 lower to method calls [1]:
 
 "The time is \(time)."
 
 Is lowered to something like:
 
 var interpolation = MyString.StringInterpolation(literalCapacity: 13,
 interpolationCount: 1)
 
 interpolation.appendLiteral("The time is ")
 interpolation.appendInterpolation(time)
 interpolation.appendLiteral(".")
 
 MyString(stringInterpolation: interpolation)
The interpolation just creates a tuple. What the user does with the tuple is up to him.
Dec 14 2019
parent Jacob Carlborg <doob me.com> writes:
On 2019-12-14 10:21, Walter Bright wrote:

 That doesn't work because semantic analysis will convert it into a tuple.
Yes, I understand that. I don't think it's a good idea. I wrote how I think it should work instead -- /Jacob Carlborg
Dec 14 2019
prev sibling next sibling parent Tim <tim.dlang t-online.de> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
If a special type is used for the format string after lowering, it can work with printf and other functions can use the format string at compile time: struct __Interpolate { immutable char *fmt; alias fmt this; } struct __InterpolateT(string fmt_) { enum fmt = fmt_; enum __Interpolate interpolate = __Interpolate(fmt_); alias interpolate this; } void main() { // printf can be used, because __InterpolateT converts to immutable(char)*: import core.stdc.stdio; printf(__InterpolateT!"test printf %d\n"(), 123); // Functions can detect an interpolated string using an overload: void writef(T...)(__Interpolate fmt, T params) { printf(fmt.fmt, params); } writef(__InterpolateT!"test writef %d\n"(), 123); // Functions can interpret the format string at compile time: void writefct(string fmt, T...)(__InterpolateT!fmt interpolate, T params) { pragma(msg, "format string at compile time ", fmt); printf(fmt, params); } writefct(__InterpolateT!"test writefct %d\n"(), 123); }
Dec 14 2019
prev sibling next sibling parent Guillaume Piolat <first.last gmail.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
I like this proposal. It sounds like a no-brainer YES.
Dec 15 2019
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
Some hashtags to get things started:

#dip1027
#stringInterpolation
Dec 16 2019
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/11/19 4:52 AM, Mike Parker wrote:
 This is the feedback thread for the first round of Community Review for 
 DIP 1027, "String Interpolation":
 
 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372
0bc/DIPs/DIP1027.md 
 
 
 All review-related feedback on and discussion of the DIP should occur in 
 this thread. The review period will end at 11:59 PM ET on December 25, 
 or when I make a post declaring it complete.
 
 At the end of Round 1, if further review is deemed necessary, the DIP 
 will be scheduled for another round of Community Review. Otherwise, it 
 will be queued for the Final Review and Formal Assessment.
 
 Anyone intending to post feedback in this thread is expected to be 
 familiar with the reviewer guidelines:
 
 https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md
 
 *Please stay on topic!*
 
 Thanks in advance to all who participate.
Might I suggest we come up with a new name for this technique? I see there is going to be a lot of users who want true string interpolation, e.g.: string str = i"My name is $name"; and be very confused that D string interpolation isn't like https://en.wikipedia.org/wiki/String_interpolation Maybe something like "format tuple expansion" or "formatted interpolation"? -Steve
Dec 16 2019
parent reply mipri <mipri minimaltype.com> writes:
On Monday, 16 December 2019 at 22:02:05 UTC, Steven Schveighoffer 
wrote:
 Might I suggest we come up with a new name for this technique?
 I see there is going to be a lot of users who want true string
 interpolation, e.g.:

 string str = i"My name is $name";

 and be very confused that D string interpolation isn't like
 https://en.wikipedia.org/wiki/String_interpolation

 Maybe something like "format tuple expansion" or "formatted
 interpolation"?

 -Steve
Programming language terminology is so random already that this isn't going to help. Perl has 'hashes' and Python has 'dicts' and other languages have 'maps', but when I read about AAs in D I just said "oh, hash tables" and mentally translated all references from then on. People are going to do exactly the same thing to "tuple expansion strings" and still complain that "string interpolation in D" doesn't work as they expect. But if it's called "tuple expansion strings", they'll *also* complain about the weird name. There might be some satisfaction in saying "you *should* have expected something different because of the different name", or in giving an explanation of the different name, but this would all be a distraction from explaining why D's string interpolation is different.
Dec 16 2019
next sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 16 December 2019 at 22:12:37 UTC, mipri wrote:
 On Monday, 16 December 2019 at 22:02:05 UTC, Steven 
 Schveighoffer wrote:
 Might I suggest we come up with a new name for this technique?
 I see there is going to be a lot of users who want true string
 interpolation, e.g.:

 string str = i"My name is $name";

 and be very confused that D string interpolation isn't like
 https://en.wikipedia.org/wiki/String_interpolation

 Maybe something like "format tuple expansion" or "formatted
 interpolation"?

 -Steve
Programming language terminology is so random already that this isn't going to help. Perl has 'hashes' and Python has 'dicts' and other languages have 'maps', but when I read about AAs in D I just said "oh, hash tables" and mentally translated all references from then on. People are going to do exactly the same thing to "tuple expansion strings" and still complain that "string interpolation in D" doesn't work as they expect. But if it's called "tuple expansion strings", they'll *also* complain about the weird name. There might be some satisfaction in saying "you *should* have expected something different because of the different name", or in giving an explanation of the different name, but this would all be a distraction from explaining why D's string interpolation is different.
The issue with user expectations should not be holding up on what to define for D. I checked today what other languages do and at consistent of what interpolated strings are. In rust it is even more than a joke as they call interpolated normal C style format string. So imo we should try to implement what fits the best the language and CT tuples is as D-ish as it gets.
Dec 16 2019
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 16 December 2019 at 22:33:57 UTC, Patrick Schluter 
wrote:
 what to define for D. I checked today what other languages do 

 nothing consistent of what interpolated strings are.
Not sure what you mean by this, I find popular languages to be remarkably consistent. Python: f"Three = {1 +2 }" $"Three = {1+2}" TypeScript: `Three = ${1 + 2}` Swift: "Three = \(1+2)"
Dec 16 2019
prev sibling next sibling parent reply mipri <mipri minimaltype.com> writes:
On Monday, 16 December 2019 at 22:12:37 UTC, mipri wrote:
 but this
 would all be a distraction from explaining why D's string
 interpolation is different.
Here's some prose that I'd expect in a FAQ or tutorial. --- * What do you mean, "it doesn't build strings"!? i"$a $b $c" is translated to an argument list "%s %s %s", a, b, c So it has no meaning outside of argument-passing. * Why do that? No other language does that! Those other languages also have some severe problems owing to how they do string interpolation: 1. a universe of SQL injection and similar exploits, as it's easy and convenient to build strings with interpolation even though the underlying database APIs can accept arguments separately and safely, with no need for ad-hoc 'sanitization'. Well-written database code in these languages is therefore written as if string interpolation is not a feature of the language: $db->query("INSERT INTO names VALUES (?)", "Bob"); 2. internationalization is defeated, as the structure of the string that variables are interpolated into is lost. Invariably as programs get international their developers have to comb through the code base and remove uses of string interpolation: print("Hello, $name!"); printf(gettext("Hello, %s!"), name); where gettext() might look up "Hello, %s" in a translator-maintained table of greetings, to substitute "Bonjour, %s". In D, string interpolation is convenient for the simplest tasks, and D is unusual in that string interpolation *remains* convenient as tasks get more serious. This comes at the small cost of having to pass an interpolated string to a string-building function, like std.format's format, if that's what you want. string s1 = i"Hello, $name!"; // error string s2 = i"Hello, $name!".format; // this is fine string s3 = format("Hello, %s!", name); // without i"" --- Even if the intended purpose is working with C-style printf() functions, I'd highlight this use of i"" in a C interface or BetterC section.
Dec 16 2019
next sibling parent reply Jab <jab_293 gmall.com> writes:
On Monday, 16 December 2019 at 22:48:30 UTC, mipri wrote:
 Those other languages also have some severe problems owing to
 how they do string interpolation:

 1. a universe of SQL injection and similar exploits, as it's
 easy and convenient to build strings with interpolation even
 though the underlying database APIs can accept arguments
 separately and safely, with no need for ad-hoc 'sanitization'.

 Well-written database code in these languages is therefore
 written as if string interpolation is not a feature of the
 language:

   $db->query("INSERT INTO names VALUES (?)", "Bob");
This would push the complexity onto the query implementation. As now it has to be able to parse the string.
 2. internationalization is defeated, as the structure of the
 string that variables are interpolated into is lost. Invariably
 as programs get international their developers have to comb
 through the code base and remove uses of string interpolation:

   print("Hello, $name!");



   printf(gettext("Hello, %s!"), name);
This would usually be a warning/error in C/C++ compilers as you aren't using a constant string for the format. It's a runtime variable and can't be checked by the compiler or at runtime so it's a security risk. D can do better due to varidic templates, but you are using printf and D doesn't have as robust warning/errors as some C/C++ compilers. Ultimately this doesn't really help with localization either. What if you need to change the order? Languages have different ways of formatting. Maybe not the best example, but say you have "$year-$month-$day", but in a different location it is more common to do "$month-$day-$year". The gettext() can't do anything about that, cause it'll always have to be "%d-%d-%d", it can't rearrange the order.
 where gettext() might look up "Hello, %s" in a
 translator-maintained table of greetings, to substitute
 "Bonjour, %s".

 In D, string interpolation is convenient for the simplest
 tasks, and D is unusual in that string interpolation *remains*
 convenient as tasks get more serious.

 This comes at the small cost of having to pass an interpolated
 string to a string-building function, like std.format's format,
 if that's what you want.

   string s1 = i"Hello, $name!"; // error

   string s2 = i"Hello, $name!".format; // this is fine

   string s3 = format("Hello, %s!", name); // without i""
 ---

 Even if the intended purpose is working with C-style printf()
 functions, I'd highlight this use of i"" in a C interface or
 BetterC section.
What happens if you want to implement your own type and pass it in? The DIP doesn't mention it at all. If you do what to do that it won't work with printf anymore. Unless you forcibly require some .toString() method for types that aren't supported. But even then that information about what type it was is then lost. It could have been passed with the type information and the caller could decide what to do with the extra information. Rather than requiring it to be forced into a string and potentially losing relevant information if it was otherwise passed to the function as a tuple.
Dec 16 2019
next sibling parent reply mipri <mipri minimaltype.com> writes:
On Tuesday, 17 December 2019 at 05:37:53 UTC, Jab wrote:
 On Monday, 16 December 2019 at 22:48:30 UTC, mipri wrote:
 Well-written database code in these languages is therefore
 written as if string interpolation is not a feature of the
 language:

   $db->query("INSERT INTO names VALUES (?)", "Bob");
This would push the complexity onto the query implementation. As now it has to be able to parse the string.
What? This is how query implementations work right now. Yes, the DBMS needs to be able to parse SQL. Have you spoken to a database without an ORM before?
   printf(gettext("Hello, %s!"), name);
This would usually be a warning/error in C/C++ compilers as you aren't using a constant string for the format.
https://www.gnu.org/software/libc/manual/html_node/Translation-with-gettext.html
 Ultimately this doesn't really help with localization either.
 What if you need to change the order? Languages have different
 ways of formatting. Maybe not the best example, but say you
 have "$year-$month-$day", but in a different location it is
 more common to do "$month-$day-$year". The gettext() can't do
 anything about that, cause it'll always have to be "%d-%d-%d",
 it can't rearrange the order.
"This doesn't help." is not supported by "I can think of a specific objection that internationalization libraries definitely have specific support for." OK, what about all the other cases? What if you format a date using a locale-aware formatter and then just make that one of the inputs to your format string, rather than the individual components of the date? It's still a better localization story than normal string interpolation, which just has to be ripped out. You can't fix normal string interpolation by using a locale-aware date formatter, because the resulting string is still not something you can look up in a translation database. Therefore, it helps despite this objection. Have you used gettext before?
 What happens if you want to implement your own type and pass it
 in? The DIP doesn't mention it at all.
If you're passing the i"" string to a D routine like format() or writef(), then you get all the custom formatting that you want, as normal. If you're passing it to a C routine or something else, obviously you have to provide types that the C routine can understand. Have you printed a custom type in D before?
Dec 16 2019
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/16/2019 10:15 PM, mipri wrote:
 Have you printed a custom type in D before?
Your response is well-written with good arguments, but please leave off the snark.
Dec 17 2019
parent mipri <mipri minimaltype.com> writes:
On Tuesday, 17 December 2019 at 09:00:53 UTC, Walter Bright wrote:
 On 12/16/2019 10:15 PM, mipri wrote:
 Have you printed a custom type in D before?
Your response is well-written with good arguments, but please leave off the snark.
Sure. I thought that was too much, as well.
Dec 17 2019
prev sibling parent Jab <jab_293 gmall.com> writes:
On Tuesday, 17 December 2019 at 06:15:03 UTC, mipri wrote:
 On Tuesday, 17 December 2019 at 05:37:53 UTC, Jab wrote:
 On Monday, 16 December 2019 at 22:48:30 UTC, mipri wrote:
 Well-written database code in these languages is therefore
 written as if string interpolation is not a feature of the
 language:

   $db->query("INSERT INTO names VALUES (?)", "Bob");
This would push the complexity onto the query implementation. As now it has to be able to parse the string.
What? This is how query implementations work right now. Yes, the DBMS needs to be able to parse SQL. Have you spoken to a database without an ORM before?
Sorry I forgot to go back and edit this after I changed it. It be more complicated as instead of just using "?" it would have to be able to know about and parse printf-style formatting.
   printf(gettext("Hello, %s!"), name);
This would usually be a warning/error in C/C++ compilers as you aren't using a constant string for the format.
https://www.gnu.org/software/libc/manual/html_node/Translation-with-gettext.html
Ok? I've literally never seen this function used in any software. Probably for a good reason.
 Ultimately this doesn't really help with localization either.
 What if you need to change the order? Languages have different
 ways of formatting. Maybe not the best example, but say you
 have "$year-$month-$day", but in a different location it is
 more common to do "$month-$day-$year". The gettext() can't do
 anything about that, cause it'll always have to be "%d-%d-%d",
 it can't rearrange the order.
"This doesn't help." is not supported by "I can think of a specific objection that internationalization libraries definitely have specific support for." OK, what about all the other cases? What if you format a date using a locale-aware formatter and then just make that one of the inputs to your format string, rather than the individual components of the date? It's still a better localization story than normal string interpolation, which just has to be ripped out. You can't fix normal string interpolation by using a locale-aware date formatter, because the resulting string is still not something you can look up in a translation database.
The date was just illustrating the problem. Sentence structures in languages change, the order isn't the same in every language. If your using printf, localization probably doesn't matter. Your going to have more problems with localization using printf. If localization matters, there's better methods for achieving it than using printf and something like gettext().
 What happens if you want to implement your own type and pass it
 in? The DIP doesn't mention it at all.
If you're passing the i"" string to a D routine like format() or writef(), then you get all the custom formatting that you want, as normal. If you're passing it to a C routine or something else, obviously you have to provide types that the C routine can understand.
That's the problem. This is intended to be used for printf() as well, but to do that you have to do something like this then: printf(i"blah blah ${myType.toString.toStringz}"); It becomes useless here. You are going to have to use something else anyways because it starts to fall apart when you try and support an old method like printf.
Dec 17 2019
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Dec 17, 2019 at 05:37:53AM +0000, Jab via Digitalmars-d wrote:
 On Monday, 16 December 2019 at 22:48:30 UTC, mipri wrote:
[...]
   $db->query("INSERT INTO names VALUES (?)", "Bob");
This would push the complexity onto the query implementation. As now it has to be able to parse the string.
[...] The database engine *already* does this. It's standard SQL syntax, and you don't have to write a single bit of code to make this work, just hand it off to the database backend and your job is done. T -- "640K ought to be enough" -- Bill G. (allegedly), 1984. "The Internet is not a primary goal for PC usage" -- Bill G., 1995. "Linux has no impact on Microsoft's strategy" -- Bill G., 1999.
Dec 17 2019
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/16/2019 2:48 PM, mipri wrote:
 Here's some prose that I'd expect in a FAQ or tutorial.
 [...]
Thank you, this is good stuff!
Dec 17 2019
prev sibling parent Jacob Carlborg <doob me.com> writes:
On Monday, 16 December 2019 at 22:12:37 UTC, mipri wrote:

 Programming language terminology is so random already that
 this isn't going to help. Perl has 'hashes' and Python has
 'dicts' and other languages have 'maps', but when I read about
 AAs in D I just said "oh, hash tables" and mentally translated
 all references from then on. People are going to do exactly the
 same thing to "tuple expansion strings" and still complain that
 "string interpolation in D" doesn't work as they expect.
I think the name "associative array" is pretty good because I think it's the most generic name. "hash" or "hash table" has the indication that the implementation uses hashes. Funny thing, in Ruby it's called "hashes" as well, the class is even called "Hash". Prior to Ruby 1.9 it was implement has an actual hash table. In Ruby 1.9 they change the implementation to guarantee the order of the keys. That means that it cannot be implement as a hash table anymore. It still uses the name "Hash" though. -- /Jacob Carlborg
Dec 17 2019
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/11/19 4:52 AM, Mike Parker wrote:
 This is the feedback thread for the first round of Community Review for 
 DIP 1027, "String Interpolation":
 
 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372
0bc/DIPs/DIP1027.md 
 
 
 All review-related feedback on and discussion of the DIP should occur in 
 this thread. The review period will end at 11:59 PM ET on December 25, 
 or when I make a post declaring it complete.
 
 At the end of Round 1, if further review is deemed necessary, the DIP 
 will be scheduled for another round of Community Review. Otherwise, it 
 will be queued for the Final Review and Formal Assessment.
 
 Anyone intending to post feedback in this thread is expected to be 
 familiar with the reviewer guidelines:
 
 https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md
 
 *Please stay on topic!*
 
 Thanks in advance to all who participate.
BTW, people have been talking about usage like: auto str = i"I have $apples apples".format; And it got me thinking, does this actually work? I mean, can multiple parameters be used for UFCS? Answer: yes. auto str = AliasSeq!("I have %s apples", apples).format; // OK pretty cool. I had no idea. -Steve
Dec 17 2019
next sibling parent Atila Neves <atila.neves gmail.com> writes:
On Wednesday, 18 December 2019 at 01:20:33 UTC, Steven 
Schveighoffer wrote:
 On 12/11/19 4:52 AM, Mike Parker wrote:
 [...]
BTW, people have been talking about usage like: auto str = i"I have $apples apples".format; And it got me thinking, does this actually work? I mean, can multiple parameters be used for UFCS? Answer: yes. auto str = AliasSeq!("I have %s apples", apples).format; // OK pretty cool. I had no idea.
Huh. I wrote my example without UFCS precisely because I didn't know if that would work. Nice!
 -Steve
Dec 18 2019
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 18 December 2019 at 01:20:33 UTC, Steven 
Schveighoffer wrote:
 [snip]

 BTW, people have been talking about usage like:

 auto str = i"I have $apples apples".format;

 And it got me thinking, does this actually work? I mean, can 
 multiple parameters be used for UFCS?

 Answer: yes.

 auto str = AliasSeq!("I have %s apples", apples).format; // OK

 pretty cool. I had no idea.

 -Steve
I think it works because format takes a variadic template as an input. Given the connection between variadic templates and AliasSeq, the input is basically an AliasSeq in the first place. Shouldn't be an issue having AliasSeq's with length>1. I don't know if I would describe it as multiple parameters. I would call UFCS with multiple parameters as describing when you have foo(x, y, z), you can call x.foo(y, z). In this case, something like auto str = AliasSeq!("I have %s apples").format(apples); also compiles without error and would be more comparable.
Dec 18 2019
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/18/19 9:18 AM, jmh530 wrote:
 On Wednesday, 18 December 2019 at 01:20:33 UTC, Steven Schveighoffer wrote:
 [snip]

 BTW, people have been talking about usage like:

 auto str = i"I have $apples apples".format;

 And it got me thinking, does this actually work? I mean, can multiple 
 parameters be used for UFCS?

 Answer: yes.

 auto str = AliasSeq!("I have %s apples", apples).format; // OK

 pretty cool. I had no idea.
I think it works because format takes a variadic template as an input. Given the connection between variadic templates and AliasSeq, the input is basically an AliasSeq in the first place. Shouldn't be an issue having AliasSeq's with length>1. I don't know if I would describe it as multiple parameters. I would call UFCS with multiple parameters as describing when you have foo(x, y, z), you can call x.foo(y, z). In this case, something like auto str = AliasSeq!("I have %s apples").format(apples); also compiles without error and would be more comparable.
Nope. Not just variadic templates: assert(AliasSeq!(2, 2).pow == 4); Not even templates in general: int foo(int x, int y) { return x + y; } assert(AliasSeq!(1, 2).foo == 3); -Steve
Dec 18 2019
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 18 December 2019 at 17:41:42 UTC, Steven 
Schveighoffer wrote:
 [snip]

 Nope. Not just variadic templates:

 assert(AliasSeq!(2, 2).pow == 4);

 Not even templates in general:

 int foo(int x, int y) { return x + y; }

 assert(AliasSeq!(1, 2).foo == 3);

 -Steve
Interesting.
Dec 18 2019
parent reply Mike Parker <aldacron gmail.com> writes:
On Wednesday, 18 December 2019 at 22:02:59 UTC, jmh530 wrote:
 On Wednesday, 18 December 2019 at 17:41:42 UTC, Steven 
 Schveighoffer wrote:
 [snip]

 Nope. Not just variadic templates:

 assert(AliasSeq!(2, 2).pow == 4);

 Not even templates in general:

 int foo(int x, int y) { return x + y; }

 assert(AliasSeq!(1, 2).foo == 3);

 -Steve
Interesting.
Please keep comments in this thread focused on the DIP. I've got to read through the whole thread for the summary. OT posts don't help. I'm going to start deleting OT posts from this point forward. Thanks!
Dec 18 2019
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/18/19 5:24 PM, Mike Parker wrote:
 
 Please keep comments in this thread focused on the DIP. I've got to read 
 through the whole thread for the summary. OT posts don't help. I'm going 
 to start deleting OT posts from this point forward.
 
 Thanks!
It's somewhat relevant because the usage case for tagging interpolated strings with .format requires this "feature", which I'm pretty sure was not intended. In fact, when I first thought of it, I came here to post that we may need a language change, only to find out it works fine! But sorry for the diversion. -Steve
Dec 18 2019
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 18 December 2019 at 22:24:05 UTC, Mike Parker wrote:
 Please keep comments in this thread focused on the DIP. I've 
 got to read through the whole thread for the summary. OT posts 
 don't help. I'm going to start deleting OT posts from this 
 point forward.
So here is a general response: 1. There is no unity on what to expect from interpolated strings in the thread. That suggests that a library solution should be established first using D meta programming capabilities. Only when there is unity behind a library solution (and it is being used in practice) should it be considered as a candidate for syntactic sugar in the compiler. 2. What is missing in terms of metaprogramming capabilities to do this well as a library solution. That ought to be addressed before making any extension to the compiler. 3. How does adding non-critical features to the compiler impact the ability to move forward with critical features such as improved non-gc memory management. What should the priority of this feature be related to other more imporant features? 4. How does this feature impact the learnability of the language. Currently it seams that newbies become confused by language features (not only in D, but also in Rust and C++), so how can D improve on that situation? And how can the design of this feature contribute positively in that regard?
Dec 20 2019
prev sibling parent Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Wednesday, 18 December 2019 at 17:41:42 UTC, Steven 
Schveighoffer wrote:
 On 12/18/19 9:18 AM, jmh530 wrote:
 [...]
Nope. Not just variadic templates: assert(AliasSeq!(2, 2).pow == 4); Not even templates in general: int foo(int x, int y) { return x + y; } assert(AliasSeq!(1, 2).foo == 3); -Steve
I introduce you to a D library I was working on a couple of years back: https://gist.github.com/PetarKirov/a808c94857de84858accfb094c19bf77 ;)
Dec 18 2019
prev sibling next sibling parent mipri <mipri minimaltype.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md
How are the following strings handled? i"hello $$name" // double $ i"hello $ name" // no following identifier i"hello $" // no following string i"hello \$name" // escaped $ i"hello $+name" // invalid following character (with the % -> $ change from a while back in the thread)
Dec 19 2019
prev sibling parent reply aberba <karabutaworld gmail.com> writes:
On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker wrote:
 This is the feedback thread for the first round of Community 
 Review for DIP 1027, "String Interpolation":

 https://github.com/dlang/DIPs/blob/148001a963f5d6e090bb6beef5caf9854372d0bc/DIPs/DIP1027.md

 All review-related feedback on and discussion of the DIP should 
 occur in this thread. The review period will end at 11:59 PM ET 
 on December 25, or when I make a post declaring it complete.

 At the end of Round 1, if further review is deemed necessary, 
 the DIP will be scheduled for another round of Community 
 Review. Otherwise, it will be queued for the Final Review and 
 Formal Assessment.

 Anyone intending to post feedback in this thread is expected to 
 be familiar with the reviewer guidelines:

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

 *Please stay on topic!*

 Thanks in advance to all who participate.
 . It also makes interpolated strings agnostic about what the 
 format specifications are, as long as they start with %.
Is there a reason it's not $ instead of %? String interpolation is most commonly use languages works like "my name is ${name}". Wouldn't it be easier if we target something users may already be familiar with?
Dec 26 2019
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Thursday, 26 December 2019 at 09:33:24 UTC, aberba wrote:
 On Wednesday, 11 December 2019 at 09:52:21 UTC, Mike Parker 
 wrote:
 [...]
 [...]
Is there a reason it's not $ instead of %? String interpolation is most commonly use languages works like "my name is ${name}". Wouldn't it be easier if we target something users may already be familiar with?
If you read in the thread, Walter accepted the change to $ because od %% problem I noticed in the beginning of the thread. I suppose he will amebd the document after that review cycle.
Dec 26 2019
parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 26 December 2019 at 10:20:06 UTC, Patrick Schluter 
wrote:
 If you read in the thread, Walter accepted the change to $ 
 because od %% problem I noticed in the beginning of the thread.
 I suppose he will amebd the document after that review cycle.
He updated it last week: https://github.com/dlang/DIPs/commit/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc
Dec 26 2019
parent reply Jab <jab_293 gmall.com> writes:
On Thursday, 26 December 2019 at 15:23:07 UTC, Mike Parker wrote:
 On Thursday, 26 December 2019 at 10:20:06 UTC, Patrick Schluter 
 wrote:
 If you read in the thread, Walter accepted the change to $ 
 because od %% problem I noticed in the beginning of the thread.
 I suppose he will amebd the document after that review cycle.
He updated it last week: https://github.com/dlang/DIPs/commit/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc
 No attempt is made to diagnose format specification errors, 
 such as attempting to format
an integer as a floating point value. The meaning of the format specifications is unknown to the core language. Why is this? If the language is going to embed the library feature of printf into the language spec, then it should know about and check formatting.
 string tool = "hammer";
 writefln(i"hammering %s with $tool", "nails");
 ```
 will produce:
 ```
 string tool = "hammer";
 writefln("hammering %s with %s", tool, "nails");
 ```
There's an obvious problem, even with the given example. This will print: hammering hammer with nails Instead of the expected: hammering nails with hammer
Dec 26 2019
parent Mike Parker <aldacron gmail.com> writes:
On Thursday, 26 December 2019 at 16:35:43 UTC, Jab wrote:

 Why is this? If the language is going to embed the library 
 feature of printf into the language spec, then it should know 
 about and check formatting.
Please save further feedback for the next review round. This round is finished. I still need to work through the thread to summarize the feedback, so anything past this post will be ignored. Thanks!
Dec 26 2019