We had an argument on the discord about the 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:
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
- 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 thei
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:
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:
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?