January 31, 2021
On Sunday, 31 January 2021 at 13:25:01 UTC, SealabJaster wrote:
> On Sunday, 31 January 2021 at 13:17:21 UTC, Imperatorn wrote:
>> because a solution with 100% approval will never exist.
>
> Which is exactly why I fear string interpolation is never going to be accepted in the first place.

Well, nor DIP at all tbh 😬

Maybe a voting system would make it clearer, idk.
January 31, 2021
On Sunday, 31 January 2021 at 13:41:13 UTC, Imperatorn wrote:
> On Sunday, 31 January 2021 at 13:25:01 UTC, SealabJaster wrote:
>> On Sunday, 31 January 2021 at 13:17:21 UTC, Imperatorn wrote:
>>> because a solution with 100% approval will never exist.
>>
>> Which is exactly why I fear string interpolation is never going to be accepted in the first place.
>
> Well, nor DIP at all tbh 😬
>
> Maybe a voting system would make it clearer, idk.

The only thing a DIP needs to get accepted is Walter and Atila's approval.

Community review is not a vote or referendum; it's an opportunity for the D community to *collaborate* with the DIP authors and help them improve their proposal.
January 31, 2021
On 1/31/21 7:24 AM, Imperatorn wrote:
> On Saturday, 30 January 2021 at 02:57:59 UTC, Steven Schveighoffer wrote:
>> FYI, I was just made aware that this is because the message in the feedback thread is about to be deleted. I'm posting my reply the same as it was in there.
>>
>> [...]
> 
> In light of the criticism from various people, is there some kind of "middle ground" solution that could be made? 🤔
> 
> Like for example printf and friends, could the DIP somehow either have some helpers and/or show clear examples on how you would use interpolation in those cases?

I've already done that, see https://run.dlang.io/is/X5HcXS

printf with this DIP and it's BetterC compatible.

But that is not the point of the DIP at all. We are not trying to make a fancy way to call printf. So in my opinion, this is a distraction. It just shows the power of the DIP can make what you want trivial to accomplish.

> Btw, I want this to pass, so I'm just trying to find a way forward.

I don't think it's a question of middle ground, I think it's a question of goals.

-Steve
January 31, 2021
On 1/31/21 1:24 AM, Walter Bright wrote:
> On 1/29/2021 7:06 AM, Steven Schveighoffer wrote:
>> The point of this is, we don't want to fit into printf-style formatting,
> 
> That is abundantly clear :-)
> 
> But it is a test on how powerful the feature is and where its limits are.

Yes, and it passes the test quite clearly -- it is possible to write a formatting function with this DIP.

>> DIP1027's syntax is designed to fit with a few existing functions.
> 
> More accurately, it is designed to fit with an enormous amount of existing use. The printf format pattern is very common with other functions - dmd's source code has many examples of it.

But it does not work with printf for strings. Only writef and format provide full compatibility.

And beside the point, this is not a feature that is only to be used by DMD and it's style of code. The "parse a string to figure out what to do" is vastly inferior to introspection. Making decisions on what to do and how to do it at compile time is D's specialty, why should we give up that power for a crippled runtime string (which can be manipulated at will by the function caller)?

> DIP1027 actually had zero knowledge of printf formatting other than %s being the default format, which is shared with writefln. This was very intentional in its design.

%s is wrong for all standard D types when talking about printf. DIP1027 works with writef, and I consider that to be the goal, not printf.

> 
> 
>> It puts the burden on the user to make sure they understand how the rewrite will happen, and which functions to use to do this.
> 
> The rewrite is far simpler than #DIP1036's is, and no functions are used to do it. Note how short DIP1027 is.

How is the rewrite simpler? DIP1036 does not have to parse format specifiers. It produces arguments intuitively in the order provided instead of rearranging all of them and providing a runtime-only-accessible blueprint on what to do with them.

>> It is not forgiving of mistakes, which will compile and do the wrong thing.
> 
> Since D now does printf format checking, format mistakes will no longer compile. (We should have added that to D a decade ago! Dang I like that feature.)

You know who doesn't care about that feature? The 99% of D developers that don't use printf.

You once said that Java IDEs that provide shortcuts to write boilerplate for you was a failure compared to templates. I'm saying that same thing now.

This does not help with any other kind of formatting. It doesn't help with writef. It doesn't help with mysql. It's a very specific feature. The D language is not made to cater to printf. And if DIP1027 is an example of that, it's a poor example as it doesn't work with strings.

> 
> 
>> But I don't want to rehash DIP1027 here, that discussion has already happened.
> 
> Since #DIP1027 was rejected, it is necessary for #DIP1036 to be a substantial improvement over it, otherwise we just go sideways. Comparisons are fair.

DIP1027 and DIP1036 have substantially different goals. DIP1027 is a mechanism to make calls to format-blueprint style functions possible to write in a different way. DIP1036 intends to make it possible to hook string interpolation, prevent incorrect usage, and if not, just convert it to a string.

But if you want to compare them, I can give you a list:

* printf
   DIP1036: Not usable out of the gate. Works with wrapper, which can provides introspection (no formatting specifiers needed, but are supported).
   DIP1027: Works with some types, but not strings. Provides no introspection. Easy to get wrong (though special compiler magic can prevent some errors). No overloads possible to correct these deficiencies.
* writef / format
  DIP1036: Can be used, but will convert to a string first. With an overload, full support for everything with compile-time error checking of formats.
  DIP1027: Works as long as you don't insert extra or incorrect format specifiers, and as long as the interpolation string is the first parameter, and there are no other parameters. No compiler magic to check format specifiers. No overloads possible to correct these deficiencies.
* sql "printf style" functions
  DIP1036: Can be used as a string only out of the gate. With an additional overload, can provide a rich intuitive experience (see DIP for examples).
  DIP1027: All placeholders must be spelled out, no introspection of data to form SQL query. No compiler magic to check for proper placeholders. Format placeholders not checkable at compile time. No overloads possible to correct these deficiencies.
* string assignment/argument
  DIP1036: done automatically, or explicitly with a minimal druntime function. Or one may use std.conv.text directly.
  DIP1027: available with a call to format with Phobos. No compiler magic verification of formatting specification - only checkable at runtime. No overload possible to correct these deficiencies.

Compare usage:

DIP1027 printf(i"Hello, %.*s${}(cast(int)name.length)${}(name.ptr), how are you today?\n");
DIP1036 iprintf(i"Hello, ${name}, how are you today?\n"); // requires shim that is betterC compatible

DIP1027 writef(i"Hex value of x is ${%x}(x)");
DIP1036 writef(i"Hex value of x is %x${x}"); // requires overload

DIP1027 writeln(i"Hello, $name");
DIP1036 writeln(i"Hello, ${name}");

DIP1027 mysql_exec("UPDATE tbl SET col1=${?}(col1), col2=${?}(col2), col3=${?}(col3) WHERE id = ${?}(id)");
DIP1036 mysql_exec("UPDATE tbl SET col1=${col1}, col2=${col2}, col3=${col3} WHERE id = ${id}"); // requires overload

DIP1027 throw new Exception(i"Error, name and age are not valid (name = $name, age = $age)");
DIP1036 throw new Exception(i"Error, name and age are not valid (name = ${name}, age = ${age})");

Bonus: all of the above would compile with DIP1027. Spot the runtime issues with them.

> 
>> DIP1036 is designed to be used by library writers to provide a mechanism to distinguish and handle properly interpolation strings ONLY when intended,
> 
> The fallback to matching string parameters doesn't fit that, and isn't different from DIP1027 in that regard.

The idup rewrite allows usage of string interpolations as strings where library writers have not written overloads to accept the expanded form. It doesn't change the fact that library writers are *provided* a mechanism.

In other words, the expanded form shouldn't match where it wasn't intended. And the string form is usable by users where strings are intended.

DIP1027 is different in that it uses common existing types that match many existing functions (even ones that are not intended to).

>> and do it with little effort, all while also providing the user a mechanism to seamlessly convert normal data into string data.
> 
> It pains me to say this, but would I use #DIP1036 in my own code? No. It adds too many layers of abstraction, is hard to document, hard to remember, adds special new rules for overloading, is unclear when it uses the GC, I have to write wrappers to use it, and the user-facing part just doesn't look good.

So you would prefer:

string s = format("%s: %s", name, val);

over

string s = i"${name}: ${val}";

It's easy to know when the GC is used. If it makes a string, the GC is used. If not, the GC is not (unless the function accepting the parameters does it).

How do you know whether a function accepts it as the expanded form? you read the documentation.

Do you have to write wrappers to use it? No. You can use it purely as a string builder.

> DIP1027 was a simple lexical rewrite - easy to remember, easy to document, sensible defaults, no allocations, no function calls, no overloading, no wrappers. It wasn't perfect, but simplicity and predictability are huge advantages.

It is simple, unintuitive (the parameters are rearranged, placeholder defaults have nothing to do with which function is called), and usable only in a select few functions (which does not include printf IMO). Writing proper functions to accept them takes a perfectly usable ordering of string and expression data, and hides it behind a runtime-only accessible string. One which the user can override anywhere he wants, and only with printf does he get a compiler error for incorrect specifiers.

This is a very poor mechansim for a language built on top of introspection and metaprogramming.

> P.S. I used to write macros in C named "printf" that would muck about with the arguments, add some logic, then call the real printf. After a few years I got tired of them, and put them in a bag with some rocks and threw it in the swamp.

I'm not sure we can get past this if you keep ascribing completely irrelevant anecdotes to this DIP. The printf shim I wrote is not *even close* to a C macro. And it's completely unneccesary for this DIP's acceptance. This DIP is not aimed at printf *at all*.

-Steve
January 31, 2021
On Sunday, 31 January 2021 at 13:40:10 UTC, claptrap wrote:
> On Sunday, 31 January 2021 at 12:59:27 UTC, Paul Backus wrote:
>> On Sunday, 31 January 2021 at 12:24:30 UTC, Imperatorn wrote:
>>> On Saturday, 30 January 2021 at 02:57:59 UTC, Steven Schveighoffer wrote:
>>>> FYI, I was just made aware that this is because the message in the feedback thread is about to be deleted. I'm posting my reply the same as it was in there.
>>>>
>>>> [...]
>>>
>>> In light of the criticism from various people, is there some kind of "middle ground" solution that could be made? 🤔
>>
>> DIP 1036 *is* the middle-ground solution. That's why it's such a mess.
>>
>> The fact is, there's no broad consensus in the D community about how string interpolation ought to work. So no matter what solution you come up with, somebody is going to be disappointed with it.
>
> Try to please everybody and you end up pleasing nobody.

This right here. Sometimes you got to make a conversational decision in order for d to progress.

-Alex
January 31, 2021
On 1/29/21 5:39 PM, Dukc wrote:
> On Friday, 29 January 2021 at 19:10:55 UTC, Steven Schveighoffer wrote:
>> On 1/29/21 7:58 AM, Dukc wrote:
>>> 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.
>>
>> No, this isn't range-value propagation. There is no way to recreate or save the type that is a string literal.
> 
> It may be that VRP is not the correct term, but I meant that a string literal (just like an array literal, or VRPed integers) has one unambiguous primary type, that is used if it's not immediately assigned to something else.
> 
>> D has, however, added things like typeof(null), which still work as polysemous values (assignable to multiple types).
> 
> But even there: it has a primary type that is tried first, before any conversion rules kick in. Unlike what you're proposing.

I think we're going to end up with something like this. The more I think about it, the more I feel that having a primary type be the tuple is required.

When I wrote that typeof(i"...") is string, that bothered me, even though it's how I had pictured it. The thing that is really bad is:

pragma(msg, typeof(i"hello, ${name}")); // string
void foo(T...)(T args) { pragma(msg, T); }
foo(i"hello, ${name}"); // tuple(...)

This just can't work that way. It reminds me of autodecoding where hasLength!string is false, yet string.length works.

I think the idup rewrite is still viable, just not as seamless (e.g. if the tuple has a type, then auto x = i"..." will not be a string as outlined in the DIP). Adam is trying to set up an implementation to play with, where we can see if it's viable.

-Steve
January 31, 2021
> Try to please everybody and you end up pleasing nobody. 
...
> DIP1027 works with writef, and I consider that to be the goal, not printf.

Unpopular opinion follows (at this point I have no idea which side of the debate this puts me on).

I think working with either writef or printf is a bit of a side quest, and to the extent it affects the fundamental design it becomes a nongoal.

The printf family (which includes writef, too) has a fundamental characteristic: the formatting specification are SEPARATE from the data. You pass the formatting template, you pass the data, and the function puts them together and produces a string nice. This way of doing things has pluses and minuses that are well known.

Interpolated strings fundamentally do the converse: they MIX the formatting specification with the data. You see bits of literal strings mixed with pieces of data. That, too, has pluses and minuses.

From that vantage point, I look at the effort of supporting {print,write}f in interpolated strings leading to any number of contortions and come and ask: cui prodest? Indeed, cui the heck prodest?

The main client of string interpolation by A MILE, is code generation. Whether it's D code, SQL, your own embedded language - that's the ONE use case that any DIP proposing this should drive with. Supporting (print|write)f is some weird invention - I already have these functions that separate formatting from data, why do I want to transform the converse way of doing things into this?

But wait! one might say in response. What if I need on occasion some special formatting of one argument in one of them nice interpolated strings? No problem, I say. Do what Perl, PHP, and Python programmers have done for millenia - apply the formatting function separately for the desired argument:

i"Hello, ${format(`%45s`, var)} world"!

That's how the cookie crumbles. To have to pay syntactically and in complexity WHENEVER I EVER use an interpolated string on the off chance that I might need special formatting for ONE argument is unconscionable.

Define interpolated strings to be simple, cheap, obvious, and well fit for their MAIN USE CASE, which is code generation.

January 31, 2021
On Sunday, 31 January 2021 at 15:54:38 UTC, Andrei Alexandrescu wrote:
>> Try to please everybody and you end up pleasing nobody.
> ...
>> DIP1027 works with writef, and I consider that to be the goal, not printf.
>
> Unpopular opinion follows (at this point I have no idea which side of the debate this puts me on).
>
> I think working with either writef or printf is a bit of a side quest, and to the extent it affects the fundamental design it becomes a nongoal.
>
> The printf family (which includes writef, too) has a fundamental characteristic: the formatting specification are SEPARATE from the data. You pass the formatting template, you pass the data, and the function puts them together and produces a string nice. This way of doing things has pluses and minuses that are well known.
>
> Interpolated strings fundamentally do the converse: they MIX the formatting specification with the data. You see bits of literal strings mixed with pieces of data. That, too, has pluses and minuses.
>
> From that vantage point, I look at the effort of supporting {print,write}f in interpolated strings leading to any number of contortions and come and ask: cui prodest? Indeed, cui the heck prodest?
>
> The main client of string interpolation by A MILE, is code generation. Whether it's D code, SQL, your own embedded language - that's the ONE use case that any DIP proposing this should drive with. Supporting (print|write)f is some weird invention - I already have these functions that separate formatting from data, why do I want to transform the converse way of doing things into this?
>
> But wait! one might say in response. What if I need on occasion some special formatting of one argument in one of them nice interpolated strings? No problem, I say. Do what Perl, PHP, and Python programmers have done for millenia - apply the formatting function separately for the desired argument:
>
> i"Hello, ${format(`%45s`, var)} world"!
>
> That's how the cookie crumbles. To have to pay syntactically and in complexity WHENEVER I EVER use an interpolated string on the off chance that I might need special formatting for ONE argument is unconscionable.
>
> Define interpolated strings to be simple, cheap, obvious, and well fit for their MAIN USE CASE, which is code generation.

Isn't the specific formatting for a given argument mainly for things like floats in practice? We have good ways of doing this already, I think if any given proposal is merged it seems worth holding back and collecting experience before standardising anything other than calling format yourself (What alternatives do you have in mind? - the solution I see in python looks fairly arcane)

But I (intensely) agree that printf really doesn't matter here - even talking C, puts surely is the closest analogue.
January 31, 2021
On 1/30/21 2:36 AM, Jacob Carlborg wrote:
> On 2021-01-29 21:45, Steven Schveighoffer wrote:
> 
>> Yes, that would return false.
>>
>> But, this seems still pretty far fetched for a real use case. Not only that, but there is still a way to fix it, just use .idup if what you really meant was a string. And it's not something that's needed to be done by the author of someTemplate, just the user in the (probably one) case that he uses it.
>>
>> Consider that there are still places where one must use AliasSeq!(things) to work with them properly in templates (I get bit by this occasionally). It's quite similar actually.
>>
>> I remain unconvinced that this is a problem. But I will concede there are a few more cases where an explicit idup might be required than just tuple.
> 
> You could tweak the DIP slightly and say: in all places `idup` is automatically inserted, except in a parameter list where the first parameter is `interp`.
> 
> template someTemplate(Args...) {
>      static if (anySatisfy!(isSomeString, typeof(Args)) {
>          // ...
>      }
> }
> 
> someTemplate!(i"I have ${count} apples");
> 
> The above would evaluate to true.
> 
> template someTemplate2(interp!string i, Args...) {
>      static if (anySatisfy!(isSomeString, typeof(Args)) {
>          // ...
>      }
> }
> 
> someTemplate2!(i"I have ${count} apples");
> 
> The above would evaluate to false.
> 

No, I don't want to do this. It's possible, but very very unintuitive, especially when the expanded form MUST match a variadic parameter The more we special case these rules, the harder to understand it gets.

And besides, your first parameter is not right. There's actually no way to specify it outside a template constraint I think.

-Steve
January 31, 2021
On 1/31/21 10:54 AM, Andrei Alexandrescu wrote:
>> Try to please everybody and you end up pleasing nobody. 
> ...
>> DIP1027 works with writef, and I consider that to be the goal, not printf.
> 
> Unpopular opinion follows (at this point I have no idea which side of the debate this puts me on).

I don't think it's unpopular, or wrong. I 100% agree with your assessment.

> But wait! one might say in response. What if I need on occasion some special formatting of one argument in one of them nice interpolated strings? No problem, I say. Do what Perl, PHP, and Python programmers have done for millenia - apply the formatting function separately for the desired argument:
> 
> i"Hello, ${format(`%45s`, var)} world"!

This is how I would do it:

i"Hello, ${var.withFormat!"%45s"} world";

(where withFormat provides a toString overload that works with idup). No extra intermediate allocations necessary.

-Steve
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18