String interpolation, after a healthy debate on discord
WebFreak001
d.forum at webfreak.org
Thu Dec 9 21:06:11 UTC 2021
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?
More information about the Digitalmars-d
mailing list