www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - String interpolation, after a healthy debate on discord

reply WebFreak001 <d.forum webfreak.org> writes:
We had an argument on the discord about the 
[YAIDIP](https://github.com/John-Colvin/YAIDIP) proposal and a 
simpler syntax form `identifier""` based on Ola Fosheim Grøstad's 
proposal, and similar to JavaScript's template string syntax.

We came to the conclusion that the simpler syntax would just be 
that - a simpler syntax - and still require the YAIDIP, but with 
that give nice improvement opportunities.

The simpler syntax would be an additional special function 
calling syntax (only valid for functions accepting the 
interpolated strings with the header as suggested by YAIDIP)

Example:
```d
string text(T...)(T args) if (isInterpolatedString!T) { ... }

// could then be called:

text"Hello $name!";

// translates to:
text(i"Hello $name!");

// translates to:
text(InterpolationHeader!("Hello ", "name", "!"), "Hello ", name, 
"!");
```

For any new user the `text(i"Hello $name!")` or `i"Hello 
$name!".text` syntax could be daunting for regular use, possibly 
even hindering the adaption of interpolated strings for regular 
string usage.

Like the `str.to!int` syntax has proven an advantage over 
`str.to!(int)` and how `foo.filter!isNumber.map!...` has proven 
advantages over `foo.filter!isNumber().map!...()`, these 
interpolated string functions would be useful in everyday 
application by GC users, with phobos functions like `text` or 
`format`, or by any other users with custom functions, and drive 
adoption of the YAIDIP interpolated string suggestion in user 
code.

advantages of the simple syntax:
- very easy syntax on the common GC-use of just creating a string 
from an interpolated string by a user: `setContent(text"Hello 
$name!", text"Welcome on your profile, $name.")`
- familiar to JS developers having used their [template 
strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)
- the return types of the handling functions can be regular 
structs (non-templated) and be used with functions accepting them 
to ensure type-safety and also allow exporting the functions in 
DLLs / static compiled libraries

disadvantages:
- not usable in template arguments with type arguments (like 
`foo!i"$bar $int"`) - need to use the `i` strings there
- could clash with existing `i""`/`r""`/`q""` string types - 
these would need to be excluded as special cases

Example how it could look using postgresql (dpq2) dub package:

before:

```d
double d = -1234.56789012345;
string text = "first line\nsecond line";
Nullable!string nullString;
int[][] arrs = [[1, 2, 3], [4, 5, 6]];

QueryParams p;
p.sqlCommand = "SELECT "~
     "$1::double precision as double_field, "~
     "$2::text, "~
     "$3::text as null_field, "~
     "array['first', 'second', NULL]::text[] as array_field, "~
     "$4::integer[] as multi_array, "~
     `'{"float_value": 123.456,"text_str": "text string"}'::json 
as json_value`;

p.argsVariadic(
     d,
     text,
     nullString,
     arrs
);

auto r = conn.execParams(p);
```

after YAIDIP:

```d
double d = -1234.56789012345;
string text = "first line\nsecond line";
Nullable!string nullString;
int[][] arrs = [[1, 2, 3], [4, 5, 6]];

QueryParams sql(T...)(T interpolatedString) { /* process the 
fields here, create string with incrementing variables, calling 
argsVariadic on the QueryParams object and returning it */ }

QueryParams p = sql(i`SELECT
         $d::double precision as double_field,
         $text::text,
         $nullString::text as null_field,
         array['first', 'second', NULL]::text[] as array_field,
         $arrs::integer[] as multi_array,
         '{"float_value": 123.456,"text_str": "text 
string"}'::json as json_value`);

auto r = conn.execParams(p);
```

using the simple syntax would allow you then writing `` sql`...` 
`` instead of ``sql(i`...`)``

Some code-bases (internal usage in packages/programs or in 
company code-bases) could opt for a really tiny name like `alias 
T = std.conv.text; string s = T"Hello $name!"`.

The formal definition for this short syntax could either be

```
InterpolatedStringCall:
     Identifier " DoubleQuotedCharacters_opt " StringPostfix_opt
     Identifier ` WysiwygCharacters_opt ` StringPostfix_opt
```

allowing only simple identifiers

or

```
InterpolatedStringCall:
     Expression " DoubleQuotedCharacters_opt " StringPostfix_opt
     Expression ` WysiwygCharacters_opt ` StringPostfix_opt
```

allowing any arbitrary expressions, immediately followed by a 
string like `(foo("hello")) " world"` which is then interpreted 
like an interpolated string.

What do you think? Would this be essential for interpolated 
string adoption in user code or be useless?
Dec 09 2021
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 9 December 2021 at 21:06:11 UTC, WebFreak001 wrote:
 We had an argument on the discord about the 
 [YAIDIP](https://github.com/John-Colvin/YAIDIP) proposal and a 
 simpler syntax form `identifier""` based on Ola Fosheim 
 Grøstad's proposal, and similar to JavaScript's template string 
 syntax.
It is nice to see that you are thinking of ways to make this more user (newbie) friendly. What you propose isn't what I suggested though, but that is fine. (I suggested something more generic which would be similar to what you would do to support user-provided literals like ```100kg```, ```3.14rad```, ```100USD``` and where you would validate syntax and extract parameters in a customized way (think regexp), but there are many ways to Rome. :-)
Dec 09 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 9 December 2021 at 21:39:57 UTC, Ola Fosheim Grøstad 
wrote:
  but there are many ways to Rome. :-)
Many ROADS… (sigh)
Dec 09 2021
prev sibling next sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 9 December 2021 at 21:06:11 UTC, WebFreak001 wrote:
 What do you think? Would this be essential for interpolated 
 string adoption in user code or be useless?
I'd be happier if interpolated strings were removed completely. The idea that they are more readable and convenient, is entirely subjective. IMO .. they are a completely unnecessary, additional cognitive load - as now you have to deal with the possibility of code having both composite AND interpolated strings. Interpolated strings..be gone!
Dec 09 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 9 December 2021 at 22:17:14 UTC, forkit wrote:
 IMO .. they are a completely unnecessary, additional cognitive 
 load - as now you have to deal with the possibility of code 
 having both composite AND interpolated strings.
I understand your viewpoint, but imagine if you actually had a formal grammar describing all legal strings for a particular interpolated string type. That would allow you to get high quality IDE support where you would get autocompletion, suggestions and early identification of spelling errors. Such tooling is reducing cognitive load and saving time.
Dec 09 2021
parent reply forkit <forkit gmail.com> writes:
On Thursday, 9 December 2021 at 22:39:13 UTC, Ola Fosheim Grøstad 
wrote:
 That would allow you to get high quality IDE support where you 
 would get autocompletion, suggestions and early identification 
 of spelling errors. Such tooling is reducing cognitive load and 
 saving time.
My experience with such tooling, is that they create extra cognitive load, to the point where I can no longer use them (mostly cause I can no longer work out how to disable all the crap that comes with them). Instead of focusing on my keystrokes, I end up seeing all kinds of things popping up, all over the place, all the f$HV time .. in all kinds of different colors!!
Dec 09 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Friday, 10 December 2021 at 04:08:44 UTC, forkit wrote:
 Instead of focusing on my keystrokes, I end up seeing all kinds 
 of things popping up, all over the place, all the f$HV time .. 
 in all kinds of different colors!!
So you turn it off and request help by hitting ctrl-space instead? Anyway, a key advantage you get, when having appropriately typed strings, is that you can add string validation to the semantic server that adds language support for the IDE. This can save a lot of time for many programmers. That alone is a good reason to prefer sql"" over i"".
Dec 10 2021
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
On Thursday, 9 December 2021 at 21:06:11 UTC, WebFreak001 wrote:
 The simpler syntax would be an additional special function 
 calling syntax (only valid for functions accepting the 
 interpolated strings with the header as suggested by YAIDIP)

 Example:
 ```d
 string text(T...)(T args) if (isInterpolatedString!T) { ... }

 // could then be called:

 text"Hello $name!";

 // translates to:
 text(i"Hello $name!");

 // translates to:
 text(InterpolationHeader!("Hello ", "name", "!"), "Hello ", 
 name, "!");
 ```
This is much better. You'll note that the `i""` doesn't need to be backed in the language anymore with that construct and can be written as a library, if you define the rewrites the other way around.
Dec 10 2021
prev sibling next sibling parent reply Ogi <ogion.art gmail.com> writes:
On Thursday, 9 December 2021 at 21:06:11 UTC, WebFreak001 wrote:
 For any new user the `text(i"Hello $name!")` or `i"Hello 
 $name!".text` syntax could be daunting for regular use, 
 possibly even hindering the adaption of interpolated strings 
 for regular string usage.
Not only that, you’ll have to import `std.cov` or `std.format` whenever you want to get a string out of an istring. Kinda defeats the purpose of string interpolation as a language feature.
Dec 10 2021
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Friday, 10 December 2021 at 13:51:16 UTC, Ogi wrote:
 Not only that, you’ll have to import `std.cov` or `std.format` 
 whenever you want to get a string out of an istring.
This syntax proposal doesn't change that. And it is trivial to make this convenient anyway.
Dec 10 2021
prev sibling parent reply WebFreak001 <d.forum webfreak.org> writes:
On Friday, 10 December 2021 at 13:51:16 UTC, Ogi wrote:
 On Thursday, 9 December 2021 at 21:06:11 UTC, WebFreak001 wrote:
 For any new user the `text(i"Hello $name!")` or `i"Hello 
 $name!".text` syntax could be daunting for regular use, 
 possibly even hindering the adaption of interpolated strings 
 for regular string usage.
Not only that, you’ll have to import `std.cov` or `std.format` whenever you want to get a string out of an istring. Kinda defeats the purpose of string interpolation as a language feature.
if that's your pain point, check out this proposal here: https://forum.dlang.org/thread/kivjspiezjvqxjkhiugj forum.dlang.org :)
Dec 10 2021
parent reply Ogi <ogion.art gmail.com> writes:
On Friday, 10 December 2021 at 18:39:32 UTC, WebFreak001 wrote:
 if that's your pain point, check out this proposal here: 
 https://forum.dlang.org/thread/kivjspiezjvqxjkhiugj forum.dlang.org :)
It’s not just my pain point though. We need to convert stuff to strings all the time. For example, every time we want a meaningful message in an assertion or an exception. Many Phobos modules have to import `std.format` or `std.conv` just for that. To my understanding, this proposal already requires moving `text` functionality into compiler (if it’s not there already, I don’t know). So why not just make one more step forward and allow converting istrings to strings? If implicit conversion is too much to ask for, it could be an explicit cast to string, or some property. Maybe `stringof` should do exactly that?
Dec 14 2021
parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 14 December 2021 at 09:10:07 UTC, Ogi wrote:
 On Friday, 10 December 2021 at 18:39:32 UTC, WebFreak001 wrote:
 if that's your pain point, check out this proposal here: 
 https://forum.dlang.org/thread/kivjspiezjvqxjkhiugj forum.dlang.org :)
It’s not just my pain point though. We need to convert stuff to strings all the time. For example, every time we want a meaningful message in an assertion or an exception. Many Phobos modules have to import `std.format` or `std.conv` just for that. To my understanding, this proposal already requires moving `text` functionality into compiler (if it’s not there already, I don’t know). So why not just make one more step forward and allow converting istrings to strings? If implicit conversion is too much to ask for, it could be an explicit cast to string, or some property. Maybe `stringof` should do exactly that?
no this proposal does not suggest moving any functionality into the compiler. It suggests to add the istrings (tuples with header) as described in the YAIDIP and have special function calling syntax (`functionName"istring contents"`) that will call any function, that accepts an istring as only argument. The `text` function from `std.conv` would implement an overload accepting an istring, which can then be called `text"istring contents"` (same as `text(i"istring contents")`) and be the idiomatic string building function using the GC. Then with the other linked proposal you could add `std.conv` (or a custom wrapper that only imports `std.conv:text`, maybe aliased) as default-import to all files in your project, so you can just type `text"istring contents"` to make strings without needing to import std.conv anywhere.
Dec 14 2021
next sibling parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 14 December 2021 at 09:35:27 UTC, WebFreak001 wrote:
 On Tuesday, 14 December 2021 at 09:10:07 UTC, Ogi wrote:
 On Friday, 10 December 2021 at 18:39:32 UTC, WebFreak001 wrote:
 if that's your pain point, check out this proposal here: 
 https://forum.dlang.org/thread/kivjspiezjvqxjkhiugj forum.dlang.org :)
It’s not just my pain point though. We need to convert stuff to strings all the time. For example, every time we want a meaningful message in an assertion or an exception. Many Phobos modules have to import `std.format` or `std.conv` just for that. To my understanding, this proposal already requires moving `text` functionality into compiler (if it’s not there already, I don’t know). So why not just make one more step forward and allow converting istrings to strings? If implicit conversion is too much to ask for, it could be an explicit cast to string, or some property. Maybe `stringof` should do exactly that?
no this proposal does not suggest moving any functionality into the compiler. It suggests to add the istrings (tuples with header) as described in the YAIDIP and have special function calling syntax (`functionName"istring contents"`) that will call any function, that accepts an istring as only argument. The `text` function from `std.conv` would implement an overload accepting an istring, which can then be called `text"istring contents"` (same as `text(i"istring contents")`) and be the idiomatic string building function using the GC. Then with the other linked proposal you could add `std.conv` (or a custom wrapper that only imports `std.conv:text`, maybe aliased) as default-import to all files in your project, so you can just type `text"istring contents"` to make strings without needing to import std.conv anywhere.
While I completely understand the proposal then I think it's the wrong approach as it adds an infinite amount of complexity for something that barely solves any issues that exist today. Arguably while it solves some problems it's definitely going to introduce new issues with it. Has D forgotten Scott's talk, along with the common saying that sometimes less is more? D has so many concepts that it's almost impossible to wrap your head around D idioms and be an expert at D since there are so many edge-cases for each feature, so many issues that each feature tries to solve. Every feature D gets added is always added in the most complex way possible to solve as many problems as possible, instead of just solving a handful of problems that are mostly relevant then D tries to solve ALL problems, relevant or not. It's ultimately D's downfall that features are too complex.
Dec 14 2021
next sibling parent WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 14 December 2021 at 09:50:15 UTC, bauss wrote:
 On Tuesday, 14 December 2021 at 09:35:27 UTC, WebFreak001 wrote:
 [...]
While I completely understand the proposal then I think it's the wrong approach as it adds an infinite amount of complexity for something that barely solves any issues that exist today.
I think the complexity for the syntax and the language itself is quite little - and it's basically the same thing as JS template string literals too, but with the special ignore cases for letters i/r/q. It's not going to solve any issues if nobody implements it. It's completely just an extension to the language, but then is going to be a big help to making both more pretty code with `text` The implementation of these functions is going to be a little complex.
 Arguably while it solves some problems it's definitely going to 
 introduce new issues with it.
I can see that the new istring calling syntax could introduce issues if we want to add more string types through prefixes in the future, but I think that would be worth it for a quite versatile feature. The feature in other languages (like JS) has shown great use-cases, an example: https://github.com/kay-is/awesome-tagged-templates ^ that link contains lots of cool examples we could have in D like that too. Some type-safe data structure creation helper, some string / template language processors with nicer syntax, some useful every-day utilities. I think overall it will solve more issues than introducing new ones.
 Has D forgotten Scott's talk, along with the common saying that 
 sometimes less is more?

 D has so many concepts that it's almost impossible to wrap your 
 head around D idioms and be an expert at D since there are so 
 many edge-cases for each feature, so many issues that each 
 feature tries to solve.

 Every feature D gets added is always added in the most complex 
 way possible to solve as many problems as possible, instead of 
 just solving a handful of problems that are mostly relevant 
 then D tries to solve ALL problems, relevant or not.

 It's ultimately D's downfall that features are too complex.
it's a complex feature. However you don't really care about its implementation or complexity unless you want to implement a function for it yourself. All the average user might even want to think about is `text"..."`, which you could look at like it's special language syntax. It's something library authors can use and document to make more readable, better library functions. Overall I think there is more benefit in adding this than not adding this.
Dec 14 2021
prev sibling next sibling parent reply zjh <fqbqrr 163.com> writes:
On Tuesday, 14 December 2021 at 09:50:15 UTC, bauss wrote:

 It's ultimately D's downfall that features are too complex.
Is d as complex as `C++`?
Dec 14 2021
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 14 December 2021 at 11:14:03 UTC, zjh wrote:
 On Tuesday, 14 December 2021 at 09:50:15 UTC, bauss wrote:

 It's ultimately D's downfall that features are too complex.
Is d as complex as `C++`?
Depends on what you want to do. You can write simpler code in D, often the syntax can be more compact in D. However, C++ is adding features that make more convoluted C++-constructs unnecessary, but as a programmer you have to figure out what to not use since almost nothing is removed from C++. So it is hard for beginners to figure out what not to do, and what to do. D is also increasing in complexity over time, often times I think that is because shortcuts are taken in the design and implementation. The evolution of C++ is driven by the spec and not the implementation, so some features makes it into C++ that greatly improves the language even though some compilers have to be changed quite a bit. But evolution in C++ moves in many directions, because it is designed by working-groups of different people. So it does not present a homogeneous "philosophy". It would be much easier for D to work towards a homogeneous whole, but it has to be a conscious strategy because one can easily be tempted to fan out in all kinds of directions (by demands and DIPs etc).
Dec 14 2021
parent zjh <fqbqrr 163.com> writes:
On Tuesday, 14 December 2021 at 11:40:46 UTC, Ola Fosheim Grøstad 
wrote:

I'm always using `/std:latest` in `C++`.
and `2.098` in `d`.
Dec 14 2021
prev sibling next sibling parent reply rumbu <rumbu rumbu.ro> writes:
On Tuesday, 14 December 2021 at 11:14:03 UTC, zjh wrote:
 On Tuesday, 14 December 2021 at 09:50:15 UTC, bauss wrote:

 It's ultimately D's downfall that features are too complex.
Is d as complex as `C++`?
There are around 90 keywords in C++ 20, from which 11 are alternative names for operators. There are rare cases when a keyword in C++ can have a different meaning depending of the context. We have 100 keywords in D and many of them have multiple meanings (scope, static, if, is, in, out, const, do, enum, return) C++ is not necessary a complex language, STL usage and associated idioms makes it complex. If you look at some C++ code before Stepanov stepped in, it looks really nice and comprehensible :)
Dec 14 2021
next sibling parent bachmeier <no spam.net> writes:
On Tuesday, 14 December 2021 at 12:29:57 UTC, rumbu wrote:
 On Tuesday, 14 December 2021 at 11:14:03 UTC, zjh wrote:
 On Tuesday, 14 December 2021 at 09:50:15 UTC, bauss wrote:

 It's ultimately D's downfall that features are too complex.
Is d as complex as `C++`?
There are around 90 keywords in C++ 20, from which 11 are alternative names for operators. There are rare cases when a keyword in C++ can have a different meaning depending of the context. We have 100 keywords in D and many of them have multiple meanings (scope, static, if, is, in, out, const, do, enum, return) C++ is not necessary a complex language, STL usage and associated idioms makes it complex. If you look at some C++ code before Stepanov stepped in, it looks really nice and comprehensible :)
The saying about C++ has always been that it's a nice language if you stick to a subset of its features. The problem is that everyone needs a different subset. I personally don't have a problem with D's complexity since it's easy to ignore most of the language. The other problem I had with C++ was the need to be a language lawyer. You really have to understand the complete specification of the features you're using to avoid having it blow up on you. You can't easily program in C++ without a shelf full of Scott Myers books. I don't feel that way with D.
Dec 14 2021
prev sibling next sibling parent zjh <fqbqrr 163.com> writes:
On Tuesday, 14 December 2021 at 12:29:57 UTC, rumbu wrote:

 C++ is not necessary a complex language, STL usage and 
 associated idioms makes it complex. If you look at some C++ 
 code before Stepanov stepped in, it looks really nice and 
 comprehensible :)
`C++` has the baggage of the past(`Strengths/weaknesses`), so is D. If `d` strengthen the `binding` with C++ and port the C++ `popular` library, it must be very good.
Dec 14 2021
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Tuesday, 14 December 2021 at 12:29:57 UTC, rumbu wrote:
 We have 100 keywords in D and many of them have multiple 
 meanings (scope, static, if, is, in, out, const, do, enum, 
 return)
static mostly comes from C++. The only one of those D added that isn't natural and consistent is enum for manifest constant. I grant you some leeway for the unary `is` type check, but it still seems a natural extension from the binary form. (It is easy to read and understand).
 C++ is not necessary a complex language, STL usage and 
 associated idioms makes it complex.
If you compare the spec for the subset of D which C++ can implement, I think you will find it is more complex than the spec for D. References and lambdas for example. When designing a language, minimizing the set of keywords is not necessarily a good goal, the opposite is often true. You want code to look obvious. There are often tricks to reuse keywords, I'm glad D generally doesn't do that.
Dec 14 2021
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 14 December 2021 at 11:14:03 UTC, zjh wrote:
 On Tuesday, 14 December 2021 at 09:50:15 UTC, bauss wrote:

 It's ultimately D's downfall that features are too complex.
Is d as complex as `C++`?
If we are honest, it probably similar at this point.
Dec 14 2021
parent zjh <fqbqrr 163.com> writes:
On Tuesday, 14 December 2021 at 13:40:02 UTC, deadalnix wrote:

 If we are honest, it probably similar at this point.
`Learn` from each other and `copy` from each other.
Dec 14 2021
prev sibling parent bachmeier <no spam.net> writes:
On Tuesday, 14 December 2021 at 09:50:15 UTC, bauss wrote:

 While I completely understand the proposal then I think it's 
 the wrong approach as it adds an infinite amount of complexity 
 for something that barely solves any issues that exist today.
+1 I tuned out the whole discussion when I saw where it was going. It'd be nice to introduce features that improve the language without worrying about covering every possible edge case that could come up. Syntax, simplicity, and convenience are valuable.
Dec 14 2021
prev sibling parent reply Ogi <ogion.art gmail.com> writes:
On Tuesday, 14 December 2021 at 09:35:27 UTC, WebFreak001 wrote:
 no this proposal does not suggest moving any functionality into 
 the compiler. It suggests to add the istrings (tuples with 
 header) as described in the YAIDIP and have special function 
 calling syntax (`functionName"istring contents"`) that will 
 call any function, that accepts an istring as only argument.
I was referring to YAIDIP. According to it, istring should be allowed in `mixin`, `pragma(msg)` and `assert` (missed this one). This requires reimplementing `text` in the compiler.
Dec 14 2021
parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 14 December 2021 at 11:02:58 UTC, Ogi wrote:
 On Tuesday, 14 December 2021 at 09:35:27 UTC, WebFreak001 wrote:
 no this proposal does not suggest moving any functionality 
 into the compiler. It suggests to add the istrings (tuples 
 with header) as described in the YAIDIP and have special 
 function calling syntax (`functionName"istring contents"`) 
 that will call any function, that accepts an istring as only 
 argument.
I was referring to YAIDIP. According to it, istring should be allowed in `mixin`, `pragma(msg)` and `assert` (missed this one). This requires reimplementing `text` in the compiler.
ah right you mean for the built-in istring usage in the compiler it needs to be implemented. I don't think it's such a big problem though, as the phobos implementation would also just be: (a little simplified) ```d auto text(istring...)(istring s) if (isIString!istring) { return text(s[1 .. $]); // removes special __header, just concatenate rest } ```
Dec 14 2021
next sibling parent reply Ogi <ogion.art gmail.com> writes:
On Tuesday, 14 December 2021 at 11:15:02 UTC, WebFreak001 wrote:
 ah right you mean for the built-in istring usage in the 
 compiler it needs to be implemented.

 I don't think it's such a big problem though, as the phobos 
 implementation would also just be: (a little simplified)

 ```d
 auto text(istring...)(istring s) if (isIString!istring)
 {
     return text(s[1 .. $]); // removes special __header, just 
 concatenate rest
 }
 ```
My point is, if the compiler has to implement istring processor anyway, why not make it a language feature: ```D //look ma no imports int bottleCount = 99; string str = i"$(bottleCount) bottles on the wall".stringof; assert(str == "99 bottles on the wall");
Dec 14 2021
parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 14 December 2021 at 12:41:27 UTC, Ogi wrote:
 On Tuesday, 14 December 2021 at 11:15:02 UTC, WebFreak001 wrote:
 ah right you mean for the built-in istring usage in the 
 compiler it needs to be implemented.

 I don't think it's such a big problem though, as the phobos 
 implementation would also just be: (a little simplified)

 ```d
 auto text(istring...)(istring s) if (isIString!istring)
 {
     return text(s[1 .. $]); // removes special __header, just 
 concatenate rest
 }
 ```
[...] ```D //look ma no imports int bottleCount = 99; string str = i"$(bottleCount) bottles on the wall".stringof; assert(str == "99 bottles on the wall");
ah yeah I could see that work. I think it would only work at compile time though if you use .stringof (otherwise you need a runtime function - like text - that allocates the memory somehow, which is none of the compiler's business)
 My point is, if the compiler has to implement istring processor 
 anyway, why not make it a language feature:
Having the `text"..."` syntax IS a language feature, you just need an implementation, which phobos provides and is bundled with every distribution of D. (have it in std.conv or add it to object if you aren't interested in the other proposal to have default imports specified as compiler flags)
Dec 14 2021
parent Ogi <ogion.art gmail.com> writes:
On Tuesday, 14 December 2021 at 12:55:30 UTC, WebFreak001 wrote:

 I think it would only work at compile time though if you use 
 .stringof
Ouch, you’re right, we can’t reuse `stringof` for this. Some other name then, like `str` or something.
 otherwise you need a runtime function - like text - that 
 allocates the memory somehow, which is none of the compiler's 
 business
YAIDIP requires istring processing both at compile-time (`mixin` and `static assert`) and runtime (regular `assert` and `pragma(msg)`).
Dec 14 2021
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/14/21 6:15 AM, WebFreak001 wrote:
 On Tuesday, 14 December 2021 at 11:02:58 UTC, Ogi wrote:
 On Tuesday, 14 December 2021 at 09:35:27 UTC, WebFreak001 wrote:
 no this proposal does not suggest moving any functionality into the 
 compiler. It suggests to add the istrings (tuples with header) as 
 described in the YAIDIP and have special function calling syntax 
 (`functionName"istring contents"`) that will call any function, that 
 accepts an istring as only argument.
I was referring to YAIDIP. According to it, istring should be allowed in `mixin`, `pragma(msg)` and `assert` (missed this one). This requires reimplementing `text` in the compiler.
pramga(msg) and mixin do not need implementations of `std.conv.text`. `pragma(msg, "x = ", x);` already works, just need it to ignore the header. `mixin("int y = ", x + 5, ";")` already works, just need it to ignore the header. assert would need some implementation of runtime output. But it's already in the library with `-checkaction=context`. It just needs to be exposed.
 
 ah right you mean for the built-in istring usage in the compiler it 
 needs to be implemented.
 
 I don't think it's such a big problem though, as the phobos 
 implementation would also just be: (a little simplified)
 
 ```d
 auto text(istring...)(istring s) if (isIString!istring)
 {
      return text(s[1 .. $]); // removes special __header, just 
 concatenate rest
 }
 ```
The DIP is designed specifically to work with `text` as-is. You don't need a special overload (because the header has a `toString` that returns ""). This was inherited from our DIP. As for the specialized call syntax, I don't think we need it. As for implementing some `text`-like thing in druntime, we already have some of it, I think it would be reasonable to include something in object.d that does a straightforward conversion when you don't want to use std.format. The only complex one is floating point. This all can be done AFTER the DIP is accepted anyway. -Steve
Dec 14 2021
prev sibling next sibling parent ManKey <mensikovk817 gmail.com> writes:
On Thursday, 9 December 2021 at 21:06:11 UTC, WebFreak001 wrote:
 We had an argument on the discord about the
IMHO, this can be done through string mixins. But mixins have a large syntax (This is very strange for a language in which closures can be written as `{code}`.). If it was possible to write instead of `mixin(i!"2 + 3 = ${2 + 3}")` something like this `#i!"2 + 3 = ${2 + 3}"`, then this DIP would not be needed. Then it would be possible not only to do string interpolation, for example: ```d JSON j = #jsonlit!q{ "any" ~ "d_expr": 5 + 6, "key": data.map!(func).array, }; ```
Dec 10 2021
prev sibling next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 10/12/2021 10:06 AM, WebFreak001 wrote:
 What do you think? Would this be essential for interpolated string 
 adoption in user code or be useless?
I am against it. Due to it marrying a memory management+formatting strategy to the language. One way to do this is to support ``Identifier Token`` UFCS pattern which would allow this to "just work" except generically. So if you want to get data from your database? auto data = dbcon.sql`SELECT * FROM table where field = "%value$arg"`; That could pass it in as an interpolated string. However, that could be extremely confusing to the user as this is a function call, which takes a string... yet its actually something very different. Like why doesn't adding the brackets allow for that to work? ext. ext. One reason I would like this pattern even though I don't think we should ever have it is so that I can have hex strings back. Super useful during code generation and table generation for large data sets (now days I've found that std.base64 does an excellent job at this, even with a little bit of fluff). ubyte[] data = hex"AABBCC"; // ok
Dec 14 2021
parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 14 December 2021 at 14:01:56 UTC, rikki cattermole 
wrote:
 On 10/12/2021 10:06 AM, WebFreak001 wrote:
 What do you think? Would this be essential for interpolated 
 string adoption in user code or be useless?
I am against it. Due to it marrying a memory management+formatting strategy to the language. One way to do this is to support ``Identifier Token`` UFCS pattern which would allow this to "just work" except generically.
what do you mean with this? Memory management isn't part of the language or the proposal here (you need to use std.conv : `text`) and the syntax you propose here is the exact syntax proposed in the post. I don't quite get where you disagree or why you are against it from this paragraph at least.
 So if you want to get data from your database?

     auto data = dbcon.sql`SELECT * FROM table where field = 
 "%value$arg"`;

 That could pass it in as an interpolated string.

 However, that could be extremely confusing to the user as this 
 is a function call, which takes a string... yet its actually 
 something very different. Like why doesn't adding the brackets 
 allow for that to work? ext. ext.
this is the same as JS template literal syntax - it's another way of calling a function. Given how different it looks from regular function calls, I don't think you would be very confused. The compiler would also tell you that you are trying to pass a string to a function that checks for an istring. Just like currently `a.ufcsFun(b)` works but `&a.ufcsFun` to take its address doesn't, even though `a.memberFun(b)` works and `&a.memberFun` takes its address - I don't think anyone is confused about it, or at least it's easy to learn why the UFCS one doesn't work, just as it will with this proposal.
 One reason I would like this pattern even though I don't think 
 we should ever have it is so that I can have hex strings back. 
 Super useful during code generation and table generation for 
 large data sets (now days I've found that std.base64 does an 
 excellent job at this, even with a little bit of fluff).

 ubyte[] data = hex"AABBCC"; // ok
I was thinking about this as well - it would work but would run at runtime. I'm not a fan of using it just for static data and think `hexString!"..."` is better for that.
Dec 14 2021
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 14 December 2021 at 15:58:21 UTC, WebFreak001 wrote:
 I was thinking about this as well - it would work but would run 
 at runtime.
Not necessarily - the string literal portions ARE available at compile time and the function could just choose to return those as a ctfe calculation. That's one of the deeper layers of good about this dip.
Dec 14 2021
prev sibling parent reply Daniel N <no public.email> writes:
On Tuesday, 14 December 2021 at 15:58:21 UTC, WebFreak001 wrote:
 ubyte[] data = hex"AABBCC"; // ok
I was thinking about this as well - it would work but would run at runtime. I'm not a fan of using it just for static data and think `hexString!"..."` is better for that.
Then why isn't text!i"..." ok? Why do we need multiple i"..." f"..." ?
Dec 14 2021
parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 14 December 2021 at 16:04:58 UTC, Daniel N wrote:
 On Tuesday, 14 December 2021 at 15:58:21 UTC, WebFreak001 wrote:
 ubyte[] data = hex"AABBCC"; // ok
I was thinking about this as well - it would work but would run at runtime. I'm not a fan of using it just for static data and think `hexString!"..."` is better for that.
Then why isn't text!i"..." ok? Why do we need multiple i"..." f"..." ?
```d string name = readln(); auto greeting = text!i"hello $name!"; ``` expands to ```d string name = readln(); auto greeting = text!(__header!..., "hello ", name, "!"); ``` that wouldn't work because name is a runtime variable and you are trying to use it as a template parameter here. You would need to do `text(i!"hello $name!")` or `i"hello $name!".text` for the YAIDIP to work or as this post suggested a new calling syntax that extends to that: `text"hello $name!"`
Dec 14 2021
parent reply Daniel N <no public.email> writes:
On Tuesday, 14 December 2021 at 16:15:28 UTC, WebFreak001 wrote:
 ```d
 string name = readln();
 auto greeting = text!(__header!..., "hello ", name, "!");
 ```

 that wouldn't work because name is a runtime variable and you 
 are trying to use it as a template parameter here.
I assumed it works with alias/variadic params...? ```d import std; int sum(Vs...)() { int sum = 0; foreach(v ; Vs) sum += v; return sum; } void main() { int a = to!int(readln()); sum!a.writeln; } ```
Dec 14 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 14 December 2021 at 20:07:43 UTC, Daniel N wrote:
 On Tuesday, 14 December 2021 at 16:15:28 UTC, WebFreak001 wrote:
 ```d
 string name = readln();
 auto greeting = text!(__header!..., "hello ", name, "!");
 ```

 that wouldn't work because name is a runtime variable and you 
 are trying to use it as a template parameter here.
I assumed it works with alias/variadic params...? ```d import std; int sum(Vs...)() { int sum = 0; foreach(v ; Vs) sum += v; return sum; } void main() { int a = to!int(readln()); sum!a.writeln; } ```
It works for variables, but not arbitrary expressions. For example, if you wrote ```d sum!(a, a+1).writeln; ``` ...then you would get an error: ``` Error: variable `a` cannot be read at compile time ```
Dec 14 2021
parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 14 December 2021 at 21:06:19 UTC, Paul Backus wrote:
 On Tuesday, 14 December 2021 at 20:07:43 UTC, Daniel N wrote:
 On Tuesday, 14 December 2021 at 16:15:28 UTC, WebFreak001 
 wrote:
 ```d
 string name = readln();
 auto greeting = text!(__header!..., "hello ", name, "!");
 ```

 that wouldn't work because name is a runtime variable and you 
 are trying to use it as a template parameter here.
I assumed it works with alias/variadic params...? ```d import std; int sum(Vs...)() { int sum = 0; foreach(v ; Vs) sum += v; return sum; } void main() { int a = to!int(readln()); sum!a.writeln; } ```
It works for variables, but not arbitrary expressions. For example, if you wrote ```d sum!(a, a+1).writeln; ``` ...then you would get an error: ``` Error: variable `a` cannot be read at compile time ```
So passing a raw a should work (it's an alias parameter). Passing a+1 obviously doesn't as it is not a value that can be computed at compile time. Which lead me to think, can't we generate some kind of struct on the fly for the "${}" syntax? That would solve the problem and the end result would be supperior to the i solution (in fact, it would allow to implement the i solution as a library).
Dec 16 2021
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 16 December 2021 at 13:19:16 UTC, deadalnix wrote:
 So passing a raw a should work (it's an alias parameter).
yeah
 Which lead me to think, can't we generate some kind of struct 
 on the fly for the "${}" syntax?
I wrote about that back in 2019, indeed, at that point, it was my preference: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html#my-string-interpolation-proposal But it brings its own problems: this forces at least partial evaluation early which makes trouble with non-copyable types, breaks ref and aliases, and might be trouble tracking lifetime. It is a solidly decent plan but not quite full D potential. But like I've said before, all this stuff has been discussed to death. Some of us have been debating all this for years.
Dec 16 2021
parent bauss <jj_1337 live.dk> writes:
On Thursday, 16 December 2021 at 13:31:07 UTC, Adam D Ruppe wrote:
 On Thursday, 16 December 2021 at 13:19:16 UTC, deadalnix wrote:
 So passing a raw a should work (it's an alias parameter).
yeah
 Which lead me to think, can't we generate some kind of struct 
 on the fly for the "${}" syntax?
I wrote about that back in 2019, indeed, at that point, it was my preference: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html#my-string-interpolation-proposal But it brings its own problems: this forces at least partial evaluation early which makes trouble with non-copyable types, breaks ref and aliases, and might be trouble tracking lifetime. It is a solidly decent plan but not quite full D potential. But like I've said before, all this stuff has been discussed to death. Some of us have been debating all this for years.
And nobody will ever agree, so we just have to somehow stick with one implementation or it'll never happen.
Dec 16 2021
prev sibling parent Abdulhaq <alynch4047 gmail.com> writes:
On Thursday, 9 December 2021 at 21:06:11 UTC, WebFreak001 wrote:
 We had an argument on the discord about the 
 [YAIDIP](https://github.com/John-Colvin/YAIDIP) proposal and a
To a give another POV, from a polyglot background, I'd say there is a statement in the YAIDIP which is incorrect and somewhat skews the rest of the argument: ```The simplest use case of interpolated strings, and the most likely to be encountered in practice, is as argument to functions such as writeln, text, writefln, or format:``` Surely the simplest use case, and most likely to be encountered, is simply to build a well formatted string from a blend of string literals and local variables: ``` int x = 42; auto s = i"Let's interpolate $x!" ``` where s would be of string type. I use interpolated strings in numerous languages and I do so to present a clear expression to the reading developer of the intended format of the final string, and to keep the code tidy. In fact, I code like above specifically to avoid passing messy expressions as arguments to a following function call. I can see the power and attraction of the proposed design, but it has to be weighed against a syntax that satisfies the principle of least astonishment, as also identified in the same DIP. I'm also thinking that if tuples were more fully integrated and rationalised in the language then the benefits offered by this DIP regarding passing argument lists to string handling functions could be achieved in some other way using syntactically convenient unpacking of tuples into argument lists, but it's been a long time now since I used D in anger so if this part of my argument is just noise then... ignore it :-)
Dec 14 2021