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

Q. Schroll qs.il.paperinik at gmail.com
Wed Feb 3 21:00:27 UTC 2021


On Wednesday, 3 February 2021 at 17:40:40 UTC, Steven 
Schveighoffer wrote:
> On 2/3/21 11:52 AM, Q. Schroll wrote:
>> On Friday, 29 January 2021 at 12:58:32 UTC, Dukc wrote:
>>> On Thursday, 28 January 2021 at 14:58:36 UTC, Steven 
>>> Schveighoffer at the feedback theard wrote:
>>>> On 1/28/21 3:35 AM, Dukc wrote:
>>>>> The DIP states that foo(i"a:${a}, ${b}.") is rewritten as 
>>>>> `foo(Interp!"a:", a, Interp!", ", b, Interp!".")`. It think 
>>>>> it's better to rewrite it as `foo(Interp!"a:", 
>>>>> Interp!typeof(a)(a), Interp!", ", Interp!typeof(b)(b), 
>>>>> Interp!".")`. That way, `foo` has easier time introspecting 
>>>>> which came from the interpolated string.
>>>>
>>>> First, I don't think it's critical for overloading, and will 
>>>> simply add to the template bloat. What are you going to do 
>>>> differently with `a` than you would with 
>>>> `Interp!(typeof(a))(a)`?
>>>
>>> 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. And I have 
>>> a type that will implicitly convert to string if I want to do 
>>> that - no need to call `to!string(a)` or 
>>> `a.Interp!(typeof(a))` first.
>>>
>>>> The parameters are guaranteed to start and end with an 
>>>> InterpolationLiteral, so one can assume that non-literal 
>>>> arguments are interspersed inside the literal.
>>>
>>> It can be done, but it sounds more complex for the 
>>> introspecting function. I'm not strict about this though, 
>>> what the DIP now proposes be worth it to be able to pass 
>>> `ref` parameters in interpolated strings.
>>>
>>>>
>>>>> The type of interpolated string literal is very special 
>>>>> cased. [snip]
>>>>
>>>> I was fully aware that this would be the most controversial 
>>>> part. I feel like it will not be full of corner cases, but 
>>>> I'm not sure. Can you specify any?
>>>>
>>>> Consider a normal string literal can be used as a string, 
>>>> immutable(char)*, wstring, or dstring. I find it very 
>>>> similar to this feature, and I don't feel like there are a 
>>>> lot of corner cases there.
>>>
>>> A string literal is a string that is implicitly assignable to 
>>> the other alternatives via value range propagation mechanics, 
>>> or that's how I understand it at least.
>>>
>>> The compromise that the interpolated string would be an 
>>> expanded tuple, that would be implicitly assignable to string 
>>> via value range propagation mechanics, sounds acceptable. But 
>>> it needs to be clear IMO what the primary type of an 
>>> interpolated string is. If it is not an expanded tuple, what 
>>> it is then? I mean that this must be guaranteed to pass IMO:
>> 
>> Sorry, I'm late to the game here. This reminds me of 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 the literal. Why would 
>> it infer int[] forgetting its compile-time known length and 
>> even do an allocation? That seems so much worse. Even 
>> typeof([1,2,3]) is int[] and not int[3]. We know why D does it 
>> the way it does and goes int[3] with no allocation only if 
>> requested explicitly. You can do that with a template with a 
>> flexible length like this:
>>      void takesStaticArray(size_t n)(int[n] staticArray);
>> Here, `n` can usually be inferred from the argument.
>> 
>> Interpolated strings could do the exact same thing:
>> 1. make typeof(i"...") result to `string`.
>> 2. make auto str = i"..." infer string (cf. typeof) and 
>> gc-allocate if necessary.
>> 3. give i"..." a secondary type akin to [1,2,3] having int[3] 
>> as a secondary type.
>
> I don't want to do it that way, because then the overload is 
> not easy to ask for. I really really don't want the string form 
> to be passed into a vararg template.

I think I understand you. I want the best of all worlds, too. 
Maybe I'm just not seeing it. As of now, I'm really convinced 
that, while it would be nice to have, it just would break too 
much intuition. Using something as simple and common as i"..." 
correctly MUST be trivial. One shouldn't have to look up how it 
works.

> I've been having second thoughts about having auto x = i"..."; 
> be a string, and typeof(i"...") be a string. See my later 
> response here: 
> https://forum.dlang.org/post/rv6jr4$uor$1@digitalmars.com

I didn't think too much about typeof(i"..."), but I agree that it 
being string but behaving differently form a plain string may be 
odd.

>> 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.
>> 
>> Getting a string is probably what most users expect most of 
>> the time. Handling the secondary type must be explicit. It is 
>> almost an implementation detail that shouldn't be exposed to 
>> the user too easily.
>
> I'm not sure how this could be possible. You can't say T... and 
> have it match the tuple over the string, unless the primary 
> type is the tuple.

I'm not completely sure what that paragraph means.

> But if you have ideas, surely I'd prefer it to be a string 
> first in most cases!

I'd say the best idea is to make i"..." decay into string unless 
forced to be interp!".." (or really being a better match, really 
think about it like binding [1,2,3] to int[3]). An easy way out 
would be giving the actual type of i"..." a property .interp or 
.__interp that (cf. tuple's expand) returns the interp sequence. 
That way, it can be tested in pragma(msg, i"...".__interp) while 
also being correct whenever used in a canonical form. __interp 
couldn't really be a library function. An alternative would be 
__traits(interp, i"...").

The interpolation tuple really is an implementation detail that 
is relevant for an important, but still a rather small minority 
of functions.


More information about the Digitalmars-d mailing list