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

Steven Schveighoffer schveiguy at gmail.com
Wed Feb 3 16:38:15 UTC 2021


On 2/3/21 10:54 AM, Dukc wrote:
> On Friday, 29 January 2021 at 19:10:55 UTC, Steven Schveighoffer wrote:
>> On 1/29/21 7:58 AM, Dukc wrote:
>>> I was mainly thinking that I'd have easier time differentiating 
>>> between an `int` in interpolated string and `int` passed before/after 
>>> the interpolated string.
>>
>> We debated whether one should be able to figure out the original 
>> interpolation string from the parameters. I don't think it's 
>> necessary, and adds unnecessary complexity.
>>
>> Just passing the expression data directly makes things easy to deal 
>> with instead of adding an extra type to deal with.
>>
>> If you can come up with a reasonable use case for differentiating, we 
>> can discuss.
> 
> Okay, finally did this:
> 
> ```
> void writeAtPositions(T...)(char[] wArea, T args)
> {  import std;
>     char[] outp = wArea;
>     foreach(arg; args)
>     static if(is(typeof(arg) : size_t) && !is(typeof(arg) : char))
>     {  outp = wArea[arg .. $];
>     }  else
>     {  auto argStr= arg.text;
>        outp[0 .. argStr.length] = argStr[];
>        outp = outp.drop(argStr.length);
>     }
> }
> 
> void main()
> {  import std.stdio;
>     char[] text = "x=000,y=000,z=000".dup;
>     text.writeAtPositions(2, '2', "55", 16, "6");
>     text.writeln;
> }
> ```
> 
> Consider passing ints in interpolated strings to `writeAtPositions`. 
> Only change needed to work with my suggestion would be adding 
> `!__traits(isSame, TemplateOf(typeof(arg), interp))` to the `static if`, 
> (I assume interp!int would have `alias value this`). If the interpolated 
> string `int`s are passed like any `int`s, one would probably have to 
> manually cast the `int`s among interpolated strings to strings, to work 
> with this function.

So the idea here is to use string interpolations to represent the string 
parts of the parameters.

To reimagine what you are thinking, something like:

int val = 255;

int otherval = 6;

text.writeAtPositions(2, i"${val}", 16, i"${otherval}");

So the parameters are going to be:

text, 2, interp!""(), val, interp!""(), 16, interp!""(), otherval, 
interp!""())

First, I'd suggest instrumenting the positions instead of the data, 
since that's the exceptional case:

struct Pos { size_t p; }
auto pos(size_t x) { return Pos(x); }

text.writeAtPositions(2.pos, i${val}", 16.pos, i"${otherval}");

And then you have a general mechanism that doesn't even need 
interpolation strings:

text.writeAtPositions(2.pos, val, 16.pos, otherval)

And now, you can use interpolation strings as the "things to write" 
without ambiguity. You can even use a single interpolation string (with 
the positions being interpolation parameters). I would say the 
non-interpolation form is better for when you are just passing in 
parameters, and the interpolation form is great when you want, well, 
interpolations.

I get the thrust of what you are saying. But technically, if you are 
having to reengineer the function to deal with interpolation strings, 
you should rethink how the API works.

FYI, something I have considered recently, because I don't *love* the 
mechanism for overloading is to put a non-template parameter first and 
last in the sequence. Which then makes it possible to discover where the 
sequences begin and end.

So instead of having to use template constraints for overloading:

void foo(T...)(T args) if (is(T[0] : interp!S, S))

you just use standard overloading:

void foo(T...)(__iStart, T args)

And as a bonus, you can discern interpolation parameters from regular 
ones (if desired).

-Steve


More information about the Digitalmars-d mailing list