January 29, 2021
On 1/29/21 7:41 AM, Paul Backus wrote:
> On Friday, 29 January 2021 at 12:09:26 UTC, Dukc wrote:
>> On Friday, 29 January 2021 at 11:09:57 UTC, Walter Bright wrote:
>>> Sure, but #DIP1027 did not require a GC or fiddling around. So it's not like it's not possible.
>>
>> You need to remember that perhaps the most important use case for string interpolation are string mixins. With DIP1027, one would have to write `mixin(i"foreach(i;0..${iterations}) foo()".format)` instead of `mixin(i"foreach(i;0..${iterations}) foo()")` that works with this proposal. Added `.format` for every single interpolated string mixin.
> 
> You cannot actually pass an i"..." literal directly to `mixin` with this proposal; you have to call `idup` (or some other function) to convert it to a string first.

This is not true. mixin(i"...") will work just fine (an implicit idup will be added).

-Steve
January 29, 2021
On Friday, 29 January 2021 at 15:06:20 UTC, Steven Schveighoffer wrote:
> [snip]
>
> With a metaprogramming wrapper, it would be:
>
> printf(i"${item} %02d${other_item}");
>
> Without a metaprogramming wrapper, you call it like this:
>
> printf("%s %02d", item, other_item); // yes, just use printf the way it was intended
>
> The point of this is, we don't want to fit into printf-style formatting, because it's too niche a need, and extremely limiting. Use the wrapper if you want printf formatting. This is not a burden on anyone (the wrapper took me 15 minutes to write, and is an inlineable no-processing call).
> [snip]

Is there any reason why it needs to be an overload of printf instead of a separate function, like say iprintf?

January 29, 2021
On 1/29/21 9:54 AM, Dukc wrote:
> On Friday, 29 January 2021 at 14:30:03 UTC, Adam D. Ruppe wrote:
>> On Friday, 29 January 2021 at 14:21:39 UTC, Paul Backus wrote:
>>> ...unless you happen to have something else named `interp` in scope that makes the `.stringof` results compile. Have fun chasing down *that* bug. :)
>>
>> What are you talking about?
>>
>> this DIP is pretty explicit about where interp lives.
> 
> But you could define your own to the same module where the mixin lives. In that case, it would get called by the mixin, not `object.interp`.

The intent is for the compiler to identify the exact location of interp.

This doesn't necessarily mean lowering, it means that only the druntime interp template will be used (which is easy to do internally).

There will be no overriding of interp or idup allowed in user code. I could have sworn I had a statement in the DIP that said that, but I may have deleted it in the many rewrites.

-Steve
January 29, 2021
On Friday, 29 January 2021 at 15:28:21 UTC, Steven Schveighoffer wrote:
>
> The intent is for the compiler to identify the exact location of interp.
>
> This doesn't necessarily mean lowering, it means that only the druntime interp template will be used (which is easy to do internally).

Once the `interp` instance passes through the implicit .stringof in mixin(...), all of that semantic information is lost. Most of the time you will get lucky and it will work anyway, but you have no guarantee.

Adam knows all about the pitfalls of mixin + stringof, so feel free to ask him about it if you still don't understand.

> There will be no overriding of interp or idup allowed in user code. I could have sworn I had a statement in the DIP that said that, but I may have deleted it in the many rewrites.

Unless you make `interp` and `idup` reserved identifiers (which is a breaking language change), there is no way you can prevent this in the general case.
January 29, 2021
On 1/29/21 10:49 AM, Paul Backus wrote:
> On Friday, 29 January 2021 at 15:28:21 UTC, Steven Schveighoffer wrote:
>>
>> The intent is for the compiler to identify the exact location of interp.
>>
>> This doesn't necessarily mean lowering, it means that only the druntime interp template will be used (which is easy to do internally).
> 
> Once the `interp` instance passes through the implicit .stringof in mixin(...), all of that semantic information is lost. Most of the time you will get lucky and it will work anyway, but you have no guarantee.

mixin(i"int ${idname} = 5;"); will ALWAYS be rewritten to mixin(idup(i"int ${idname} = 5;"));

If that is not clear in the DIP, it will be in the next update.

> Adam knows all about the pitfalls of mixin + stringof, so feel free to ask him about it if you still don't understand.

I understand and it's not relevant.

>> There will be no overriding of interp or idup allowed in user code. I could have sworn I had a statement in the DIP that said that, but I may have deleted it in the many rewrites.
> 
> Unless you make `interp` and `idup` reserved identifiers (which is a breaking language change), there is no way you can prevent this in the general case.

The compiler is building the instantiation of interp and idup, it can do whatever it wants to tell itself what it should do. The idea that they would need to be reserved identifiers is irrelevant, they don't appear in code. In fact, they can be __interp and __idup if you want, it doesn't really matter what they are called.

It is true that an explicit idup call will have to deal with any local overrides. But that is true for idup in general.

-Steve
January 29, 2021
On 1/29/21 10:26 AM, jmh530 wrote:
> On Friday, 29 January 2021 at 15:06:20 UTC, Steven Schveighoffer wrote:
>> [snip]
>>
>> With a metaprogramming wrapper, it would be:
>>
>> printf(i"${item} %02d${other_item}");
>>
>> Without a metaprogramming wrapper, you call it like this:
>>
>> printf("%s %02d", item, other_item); // yes, just use printf the way it was intended
>>
>> The point of this is, we don't want to fit into printf-style formatting, because it's too niche a need, and extremely limiting. Use the wrapper if you want printf formatting. This is not a burden on anyone (the wrapper took me 15 minutes to write, and is an inlineable no-processing call).
>> [snip]
> 
> Is there any reason why it needs to be an overload of printf instead of a separate function, like say iprintf?
> 

No reason at all. But it's possible if you want to (as I showed). The DIP provides the possibility for doing whatever you want, without accidentally doing what you don't want.

-Steve
January 29, 2021
On Friday, 29 January 2021 at 17:01:36 UTC, Steven Schveighoffer wrote:
> On 1/29/21 10:49 AM, Paul Backus wrote:
>> Once the `interp` instance passes through the implicit .stringof in mixin(...), all of that semantic information is lost. Most of the time you will get lucky and it will work anyway, but you have no guarantee.
>
> mixin(i"int ${idname} = 5;"); will ALWAYS be rewritten to mixin(idup(i"int ${idname} = 5;"));
>
> If that is not clear in the DIP, it will be in the next update.

This directly contradicts what is written in the DIP, which is that if the tuple expansion compiles successfully, it is used, and the idup expansion is not attempted. If this is not what you intended, then the DIP needs to be revised to reflect that.
January 29, 2021
On 1/29/21 3:02 AM, Walter Bright wrote:
> On 1/28/2021 8:47 PM, Adam D. Ruppe wrote:
>> D excels at these things.
> 
> Ok, it's doable, but it's writing your own printf to do these manipulations.

It's doing what you want because it's possible. When someone says "yeah but I can't do this", and I say "OK, here's a wrapper I wrote in 15 minutes that does what you want" and you say "But that means I need a wrapper!", I don't really know where to go from here. You asked for something that works with printf, I gave it to you. If you don't like it, I don't know what to say, but it's trivially easy and can be inlined to a direct call.

What if I complained that @safe feature is unusable because I had to wrap the OS `read` as a @trusted function? Would that be a reasonable argument? It requires a simple wrapper, write it and be done. Or don't use @safe code.

In fact DIP1027 CANNOT make an overload for printf that's usable in D code, and the existing printf can't be used with strings (ironically the default specifier for DIP1027) without horrible syntax.

If you want to use printf without a wrapper, use printf as it was intended. If you want to use printf with interpolation strings, use a trivial wrapper.

-Steve
January 29, 2021
On 1/29/21 12:16 PM, Paul Backus wrote:
> On Friday, 29 January 2021 at 17:01:36 UTC, Steven Schveighoffer wrote:
>> On 1/29/21 10:49 AM, Paul Backus wrote:
>>> Once the `interp` instance passes through the implicit .stringof in mixin(...), all of that semantic information is lost. Most of the time you will get lucky and it will work anyway, but you have no guarantee.
>>
>> mixin(i"int ${idname} = 5;"); will ALWAYS be rewritten to mixin(idup(i"int ${idname} = 5;"));
>>
>> If that is not clear in the DIP, it will be in the next update.
> 
> This directly contradicts what is written in the DIP, which is that if the tuple expansion compiles successfully, it is used, and the idup expansion is not attempted. If this is not what you intended, then the DIP needs to be revised to reflect that.

Yes, I was not aware of the mixin parameter list acceptance. The intention was for it to convert to a string in that case. It will be fixed in an update as mentioned.

The intention is for the expanded version only to be used in template or function arguments.

-Steve
January 29, 2021
Continuing from the feedback thread...

On Friday, 29 January 2021 at 16:55:05 UTC, Steven Schveighoffer wrote:
> On 1/28/21 6:06 PM, Paul Backus wrote:
>> As with any heuristic or approximation, there are edge cases where this breaks down. One of them is called out in the DIP itself--type inference via `auto`--but it is not hard to imagine others. For example, a programmer who writes
>> 
>>      tuple(i"Good morning ${name}", i"Good evening ${name}")
>> 
>> ...is probably not going to get what they intended, even though their code compiles.
>
> This is quite the unique edge case though. Any proposal that provides the flexible version is going to have trouble with tuple as it is now.

You are missing the forest for the trees here. My criticism of DIP 1036 is not
that it has trouble with `tuple`. My criticism is that DIP 1036 attempts to
guess what the programmer wants, because guessing what the programmer wants is
bad language design.

> There are solutions that can be had. For instance, tuple could be instrumented never to accept parameters that contain interpolation literals. Therefore, the idup rewrite happens, and they get what they expect. This is not hard to solve.

What was it Andrei said about this kind of thing? Ah, right:

    Good Work begets more Good Work. Typically Good Work produces context,
    opportunity, and precedent for more of the same. The same reviewer who
    rubber stamped a piece of Good Work will have an idea how to produce more
    Good Work derived from it. The kind of environment where Good Work is
    revered encourages its creation, in a cycle that creates the illusion of
    progress. Because Good Work is complex, it produces "bug ripples" whereby
    increasingly complex Good Work fixes one bug but is liable to introduce
    others. [1]

When you find yourself saying things like "it's fine, we can just add special
cases to printf...and tuple...and mixin...", that's a sure sign that something
has gone wrong in your language-feature design.

>> Every D programmer who wants to make effective use of DIP 1036's interpolation literals will have to go through the process of learning when .idup is required, when it's optional, when it's allowed-but-unnecessary, and when it's forbidden--which means that, in practice, they will have to learn how it actually works, under the hood.
>
> This is not my interpretation at all. I can't think of a reasonable case aside from your tuple example where idup is required (if that's what you want). Can you?

Sure, here's another one:

    anySatisfy!(isSomeString, i"I have ${count} apples")

Hopefully this is enough to satisfy you that it's your imagination that's
failing you here, not my reasoning.

>> This is not a desirable trait for a language feature that's intended to make programming *easier*.
>
> Your logic is not very sound. It's ironic to say the language doing what you expect for 99% of cases is a higher burden than requiring you to write it yourself for 100% of cases.

A language that does unexpected things 1% of the time is much worse than a
language that does exactly what I tell it to 100% of the time.

>> Ultimately, I think attempting to guess the programmer's intent is the wrong way to go here. Either force them to spell it out explicitly (with a call to .idup, .text, etc.), or take away the choice and give up on one of the two approaches.
>
> I want to say something about this idea of doing only one or the other.

To be clear: you can still have both, just not with the same syntax.

If you want both, my recommendation would be to use the i"..." syntax for the
convenient string version, and qq"..." ("quasiquote") for the flexible
tuple version. At that point, it would probably make sense to split them into
two separate DIPs, too.

[1] https://forum.dlang.org/post/q7u6g1$94p$1@digitalmars.com