October 26
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);
}
```
October 26
On 26/10/23 18:25, Adam D Ruppe wrote:
> On Thursday, 26 October 2023 at 16:14:08 UTC, bachmeier wrote:
>> Why not this?
> 
> https://en.wikipedia.org/wiki/String_interpolation#Security_issues
> 

That's a weak argument. First, it's not specific to string interpolation:

> String interpolation, like string concatenation, may lead to security problems. If user input data is improperly escaped or filtered
Should we also restrict string concatenation? Of course you'll get SQL injection if you don't sanitize strings!

What a security-conscious SQL function could do is not to accept normal strings, only the raw tuples returned by the lowering.

But this doesn't mean you need to restrict other valid usages where that's not a concern.
October 26

On Thursday, 26 October 2023 at 15:45:48 UTC, jmh530 wrote:

>

On Thursday, 26 October 2023 at 10:40:34 UTC, Imperatorn wrote:

>

On Thursday, 26 October 2023 at 10:12:49 UTC, Imperatorn wrote:

>

[...]

Any DIP that doesn't provide a way to get a string from an interpolated string is almost useless to the users. And the language exists for the users. It doesn't exists for library writers.

For reference, both Adam and Walter's versions show how it is possible with .text or .format.

I know.

https://github.com/dlang/dmd/pull/15722#issuecomment-1774153328

>

https://github.com/adamdruppe/interpolation-examples/blob/e275f110898758dbbbfaa5427a72c9a18387d065/01-basics.d#L13C25-L13C78

I'm sympathetic to not putting that functionality in the compiler.

And the users are not. That's all I'm saying.

October 26

On Thursday, 26 October 2023 at 17:09:31 UTC, bachmeier wrote:

>

Forbidding the convenient approach in the name of security should wait until pointers have been removed.

OK, that was done back in... i think 2011 when @safe came out.

So I guess we're due for something else!

October 26
On Thursday, 26 October 2023 at 17:29:16 UTC, Arafel wrote:
> Should we also restrict string concatenation?

String concatenation is inconvenient, so it is less appealing for casual use, but, yes, it is also generally problematic.

One of interpolation's benefits is to make concatenation less common. It would be nice to transition people to something that is both easier AND more correct.

I'm through with this thread btw.
October 26

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.

I'm replying to you here Arafel, but it's meant as a general comment.

As someone who has been developing for many years in both small companies and large, using everything from C, C++,(Visual) Basic, Erlang, Nim, Python, C#, Julia, PHP and Perl, I and many others know what works and what doesn't.

It's quite simple.

Keep it simple for the user. Have ergonomic syntax. Show that you care about the users feedback. Be reasonably performance, stable and safe.

The language exists for the users.

Nothing will change that fact, no matter what sequence of letters you put together.

And the users are saying, that if we should implement SI, there should exist an ergonomic way to get a string from the expression.

The users are not saying that that must be the only way, just that a way should exist that does not break the common interface. Many users are not in the forums at all btw.

Now, you can choose to ignore this, but in the end the same thing always happens. The users choose another language that is closer to the familiar interface.

The users don't care at all about what's good or bad under the hood.

They just care about how they use something.

And having to do an extra step in one language but not all the other breaks the common interface.

It's nothing more than that. So simple.

It might turn out that string interpolation is not worth it in D. Ok, then that's a decision that could be made.

But that decision should be made after you understand the consequences.

Also saying that it's the users loss if they move to another language, I must ask, are you sure about that?

October 26

On Thursday, 26 October 2023 at 16:42:23 UTC, Arafel wrote:

>

[...]
In D I'd like to do:

// 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";
[...]

I write this kind of code all the time...

Why? D has buildPath and setExtension [1]

   string inputFile = buildPath (basePath, inputFolder, item)
      .setExtension ("in");

Okay, when item or inputFolder have leading path separators the result might surprise...

[1] https://dlang.org/phobos/std_path.html

October 27

On Thursday, 26 October 2023 at 16:25:26 UTC, Adam D Ruppe wrote:

>

On Thursday, 26 October 2023 at 16:14:08 UTC, bachmeier wrote:

>

Why not this?

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

Unfortunately, this is about injection attacks, not auto-rendering, which are unrelated to whether or not the string is auto-rendered from it's tuples form. In both cases the formatter would have to take care of the escaping and filtering before it is rendered into a string.

Consider that the DIP currently allows auto-decoding on a string parameter of a method. What is the functional difference?

Furthermore, consider the following example:


class Test {
    public string a;
    public @property string b(string value) { return a = value; }
}

Test.a = $"...{x}..."; //Compiler error
Test.b = $"...{x}..."; //No compiler error

This is one of those vexatious compiler errors that make no sense when you read the code, but makes sense to the compiler. And it doesn't actually solve anything, because the problem is with what's passed into the string tuples, not the fact of rendering or not.

There is a debate to be had about the foot-gun nature of all forms of string interpolation/templating, but disabling rendering on assignment has nothing to do with it.

October 27
On Thursday, 26 October 2023 at 10:40:34 UTC, Imperatorn wrote:
>
> Any DIP that doesn't provide a way to get a string from an interpolated string is almost useless to the users. And the language exists for the users. It doesn't exists for library writers.

I've not been following the string interpolation debate because I'm not a big user of string interpolation but this made me wake up. Are you seriously proposing a design that cannot convert a string interpolated string into a regular string?

> There's a clear difference between languages that exist for the users and languages that just exist for the language creators and library writers. The latter category fades into oblivion very quickly.

This is a trap that many compiler engineers fall into, not only D but I have also observed the same among other languages. These are usually "hobbyist" languages and not languages that big companies are involved with.

The compiler engineers at some point forget that computer languages are made to make it easier for humans and not to make it easier for the computer or the language developer. I've seen several motivations like "that will make things so difficult" or "it will mess up my beautiful compiler code".

Examples of this is, not supporting early returns because program flow analysis of early returns is "difficult".
Another example is D with not supporting this() constructor for structs. A workaround in order to add it into the syntax is obviously not allowed.

D started out really well by departing from the horrible C++ syntax in order to make more readable, these days D seem to have abandon this heritage.
October 27
On Friday, 27 October 2023 at 09:30:46 UTC, IGotD- wrote:
> On Thursday, 26 October 2023 at 10:40:34 UTC, Imperatorn wrote:
>>
> I've not been following the string interpolation debate because I'm not a big user of string interpolation but this made me wake up. Are you seriously proposing a design that cannot convert a string interpolated string into a regular string?

Yes, neither proposal gives you a string by default. I am trying to argue that most users would find that unergonomic and unintuitive. Most languages I have checked give you a string by default since it follows the principle of least astonishment.