String Interpolation

jmh530 john.michael.hall at gmail.com
Thu Oct 26 17:10:46 UTC 2023


On Thursday, 26 October 2023 at 16:42:23 UTC, Arafel wrote:
> On 26/10/23 18:14, bachmeier wrote:
>> I'd agree if the only thing I cared about is good language 
>> design and didn't care at all about usability. Why not this?
>> 
>> |import std.format; string s = $"Hello, ${world}"; |
>> 
>> Anyone that wants what's currently on offer could still do 
>> this if they want:
>> 
>> |string s = i"Hello, ${world}".format; |
> Also, not allowing this would result confusing to new users for 
> no good reason: you'll have to explain to them why 
> `write(i"....");` works, but `string s = i"....";` doesn't, and 
> how `i"..." isn't like `r"..." or `q"[...]"`.
>
> And then, if I have to do `i"Hello, ${world}".format`, I can 
> already just as well do `mixin(i!"Hello, ${world}")`. This 
> doesn't require any change to the language and has the 
> advantage (as a user) that it's a library solution and I can 
> pick the one that best suits my needs.
>
> But back to usability: that is the basic objective of the 
> feature. Usability for the end user, not for the library writer.
>
> String interpolation is meant to be high level syntax sugar to 
> make things easy and straightforward, not some advanced topic 
> where you need to understand how internal compiler tuples work 
> to be able to know when you can use it.
>
> So what will 90% of the users want and expect?
>
> Just something that can act as a drop-in replacement for 
> strings for basic usage, nothing fancy, don't care about 
> performance. I use this all the time for scripting (bash, perl) 
> and it's really convenient.
>
> In D I'd like to do:
>
> ```d
> // Read config
> string basePath = readConfig("basePath");
> string inputFolder = readConfig("inputFolder");
> string outputFoler = readConfig("outputFolder");
> Item[] items = readConfig("itemList");
>
> // Process items
> foreach(item; items) {
> 	string inputFile = 
> i"${basePath}/${inputFolder}/${item.name}.in";
> 	string outputFile = 
> i"${basePath}/${outputFolder}/${item.name}.out";
> 	log(i"Going to process input file ${inputFile}. Output will be 
> written to ${outputFile}").
> 	processItem(item, inputFile, outputFile);
> }
> ```
>
> I write this kind of code all the time... in languages that 
> support it. I would in D as well, if I had the feature. And 
> yes, adding `.text` or `.format` would kill it just as adding 
> `mixin(...)` does already.
>
> Before somebody says I should just adapt `processItem`: in most 
> cases I don't have control over it, and the creator of that 
> library isn't likely in the mood to deal with templates and 
> tuples, especially with two arguments. Why should he? He just 
> wants two file names... and it could even be a C library.

I would guess that std.logger would get support for i-strings. In 
that case, you would only need to call .text if you don't want to 
re-write processItem.

```d
// Read config
string basePath = readConfig("basePath");
string inputFolder = readConfig("inputFolder");
string outputFoler = readConfig("outputFolder");
Item[] items = readConfig("itemList");

// Process items
foreach(item; items) {
     auto inputFile = i"$basePath/$inputFolder/$(item.name).in";
     auto outputFile = i"$basePath/$outputFolder/$(item.name).out";
     log(i"Going to process input file $inputFile. Output will be 
written to $outputFile").
     processItem(item, inputFile.text, outputFile.text);
}
```


More information about the Digitalmars-d mailing list