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

Q. Schroll qs.il.paperinik at gmail.com
Wed Feb 3 17:47:19 UTC 2021


On Wednesday, 27 January 2021 at 10:33:53 UTC, Mike Parker wrote:
> * All posts must be a direct reply to the DIP manager's initial 
> post, with only two exceptions:

A problem I see is that i"..." becomes an interp sequence too 
easily.
D's templates have a low entrance barrier and passing an 
interpolated string to a variadic function template is something 
not too outlandish to do. Then, the by the current form of the 
proposal, the interpolated becomes an `interp` sequence. This may 
be completely unexpected as most variadic function templates 
won't be written with an interp sequence in mind at all.

Imagine someone (especially a newcommer from e.g. C#) naively 
using
     auto tup = tuple(1, i"I'm ${name}.", 2.3)
expecting Tuple!(int, string, double). First, tup.length != 3 and 
its content are wild.
Basically, an interpolated string should be a string, except in 
very specific circumstances; variadic templates aren't even close 
to being a very specific circumstance.

The typing is better done akin to slices vs static arrays.
As a reminder, to a newcomer,
     auto xs = [ 1, 2, 3 ];
looks like it would infer int[3] as the type of xs. It is 
obviously the most descriptive type for that literal. Why would 
it infer int[] forgetting its compile-time known length and even 
do an allocation? That seems so much worse. At least, for 
consistency, typeof([1,2,3]) is int[], too, and not int[3]. We 
know why D does it the way it does, and why it uses int[3] with 
no allocation only when requested explicitly. You can do that 
with a template with a flexible length like this:
     void takesStaticArray(T, size_t n)(T[n] staticArray);
Here, `T` and `n` can usually be inferred from the argument:
     takesStaticArray([1, 2, 3]);
won't allocate.

Interpolated strings should behave similarly:
1. typeof(i"...") is `string`.
2. auto str = i"..." infers string (cf. typeof) and gc-allocates 
if necessary.
3. i"..." has a secondary type akin to [1,2,3] having int[3] as a 
secondary type. (The secondary type is a sequence, but that's a 
detail.)

If an interpolated string is bound to a parameter of that 
secondary type (`interp` in the DIP) it uses its secondary type 
(cf. calling takesStaticArray with [1,2,3]). In any other case, 
e.g. `auto` or otherwise generic template parameters will infer 
string.

My suggestion is that one cannot do this:
     ResultSeq mysql_query(Args...)(Args args) if (Args.length > 0 
&& isInstanceOf!(interp, Args[0])) { ... }
because Args... is too unspecific to force i"..." to become an 
interp sequence. Therefore
     auto rseq = mysql_query(i"...");
results in mysql_query!string and then fails the constraint. You 
have to request an interp sequence explicitly like this
    ResultSeq mysql_query(string first, Args...)(interp!first arg, 
Args args)
to force the secondary type. This is akin to 
takesStaticArray(size_t n, T)(T[n]). Since it cannot bind an int[]

However, if you already have an interp!"..." object in hand, of 
course passing it to a template will use its static type 
interp!"..." (and not string), like an int[3] variable will, too.
This is fine, because at this point, you know what you're dealing 
with and that it is not a string.

Akin to `staticArray`, Phobos can (should) supply a template 
`asInterp` that forces a i"..." literal to be statically typed as 
a tuple around the respective `interp` sequence.

     auto asInterp(string str, Args...)(interp!str first, Args 
rest)
     {
         import std.typecons : tuple;
         return tuple(first, rest);
     }

Function templates handling interpolated strings can either 
provide an overload taking a tuple containing an interp!"..." as 
its first entry (likely result of asInterp) or require the user 
to use `expand` on the tuple.
Example: https://run.dlang.io/is/h5LgF4

Getting a string is probably what most users expect most of the 
time, even in templates. Handling the secondary type must be 
explicit. It is almost an implementation detail that shouldn't be 
exposed to the user too easily.


More information about the Digitalmars-d mailing list