Feedback Thread: DIP 1036--String Interpolation Tuple Literals--Community Review Round 2

Steven Schveighoffer schveiguy at
Fri Jan 29 16:13:38 UTC 2021

On 1/29/21 3:26 AM, Walter Bright wrote:
>  > in DIP1027, formatting was a central component of interpolation. What 
> became clear as the prior version was reviewed was that the complexity 
> of specifying format while transforming into a parameter sequence was 
> not worth adding to the language.
> Not clear to me that ${?} is that complex, and the language itself did 
> not need to know what the format was, it just had to fit inside the ${ }.

${?}(expr) is more complex than ${expr}. If that is not clear, I'm not 
sure how else to describe it.

There are two opportunities for complexity here. The complexity of 
implementation and the complexity of usage.

In fact, DIP1027 has a higher level of both usage complexity and 
implementation complexity. And it loads at least one chamber of the 
footgun at all times.

For DIP1027, a SQL library author can possibly accept $(expr) for 
parameters. What this means is that a `%s` will be added to the SQL 
string. It is possible that the library author can ADD the complexity of 
parsing and detecting %s inside the SQL string, replacing them with ? 
tokens. This is a huge added complexity that is not necessary for just a 
10 minute implementation of concatenating literal strings with ? tokens 
(which can be done at compile-time by the way).

Not only that, but the user is allowed to use whatever they want in the 
{}. This means that a user can write ${bbbb}(param) in the string and it 
will compile. The library can't *possibly* figure this out. It can 
complain at runtime of an error in format, reimplementing the entire SQL 
language parsing client side, or potentially just use the SQL server to 
do it. But it also may result in incorrect *successful* calls. There is 
just no way to form an API that guards against user error at compile 
time or runtime with DIP1027.

And on the user side, there is the ever-present guess if the SQL library 
is going to have special handling for the %s. They can add defensive 
format specifiers for everything, but again, this results in added 
complexity that is not necessary in DIP1036. In fact, DIP1036 provides 
the *opportunity* for malformed SQL statements to be rejected at 
*compile time*, something that is not available in DIP1027.

Finally, DIP1036 provides a straightforward path for formatting that is 
simply not possible with DIP1027. This is because no parsing of 
specifiers is necessary at runtime. The mechanism of "parse this string 
to see what to do" is a relic of languages that do not provide 
compile-time metaprogramming capabilities, and should be avoided in a 
feature designed for one.

>  > and the end result was something that seemed focused solely on writef 
> and printf functions.
> Much more accurately, it was optimized for all functions that use either 
> printf-style formatting strings or writef-style formatting functions. 
> This is because those style functions are overwhelmingly used in D 
> programs and are everywhere in C code.

It was not optimized for anything but writef and format. Yes, I 
purposely omitted printf, since it's not optimized for that. You must 
provide format specifiers for everything but the rare-in-D const char * 
parameter type. For example, if you have `string name;`, how would you 
use printf to format that? With an actual printf call, it's:

printf("hello, %.*s\n", cast(int)name.length, name.ptr);

With DIP1027 it's possible to do, but you wouldn't EVER do this:

printf("hello, ${%.*}(cast(int)name.length)${s}(name.ptr)\n");

With DIP1036 and a 15-minute wrapper that I wrote it's:

printf("hello, ${name}\n");

For all other use cases, one must inject format specifiers for all 
parameters, or have a function that compiles but always does the wrong 
thing. One must know the format specifiers for that specific domain, and 
therefore places the burden of the API writing on the user at all times.

Furthermore, there is NO POSSIBLE WAY for DIP1027 to allow a library 
author to help. Even if a library wants to provide a mechanism to allow 
unformatted string interpolation usage, he cannot do so.

> In another post I compared #DIP1027 and #DIP1036 side-by-side for printf 
> and writeln. (DIP1036 also requires an overload of writefln to work with 
> anything other than %s formatting.)

DIP1027 does not work with writef unless you call it in a very specific 
way. DIP1027 cannot work with writeln, even with an overload. DIP1036 
will work with writeln out of the box, and with an overload can provide 
an actual universally usable mechanism for formatted strings with 
interpolation strings.

DIP1027 is basically a user rewrite of parameters that happens to work 
with a select few functions when called in a select few ways.

> Let's compare mysql:
> DIP1036:
> mysql_query(i"select * from foo where id = ${} and val > ${minval}");
> DIP1027:
> mysql_query(i"select * from foo where id = ${?}( and val > 
> ${?}minval");
> The DIP1027 could be shorter or longer, depending on if the ( ) were 
> needed or not. DIP1036 also requires a user-written overload for 
> mysql_query(), DIP1027 does not. DIP1036 is not a clear winner for mysql.

DIP1027 will always be longer: ${?} is 4 characters. ${} is 3.

DIP1036 ALLOWS an overload that works exactly as the user expects

DIP1027 PREVENTS an overload that works as the user expects.

DIP1036 can reject malformed parameters at compile time. DIP1027 is 
basically a rewrite of user parameters, and puts an immense burden on 
them that is not necessary with DIP1036. It takes all the power away 
from a library writer in helping the user use their library properly.

DIP1036 is a clear winner for mysql.


More information about the Digitalmars-d mailing list