December 17, 2019
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!");
>
>   # is corrected to:
>
>   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.



December 17, 2019
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?

December 17, 2019
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
December 17, 2019
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!
December 17, 2019
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


December 17, 2019
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.

December 17, 2019
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
December 17, 2019
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.
December 17, 2019
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.

December 17, 2019
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