DIP 1027---String Interpolation---Format Assessment

Adam D. Ruppe destructionator at gmail.com
Thu Feb 27 18:19:03 UTC 2020


On Thursday, 27 February 2020 at 17:41:12 UTC, Petar Kirov 
[ZombineDev] wrote:
>     auto s = new_type!(
>         "hi ", spec(null), ", you are visitor ", spec("%2d")
>     )(name, count);
>
> I.e. the referenced arguments are passed to the constructor of 
> new_type.

Right, that actually is what my old proposal was (and I fought 
for it on the first few pages of the last thread), and this is 
very close to what C# does successfully, but I decided to leave 
it behind because:

1. It doesn't work very nicely in templates:

int a;
foo!i"test $a"; // error, a cannot be evaluated at compile time

Even if `foo` otherwise could handle it (e.g. an `alias` 
parameter), passing the data to an intermediate object prohibits 
this.

I personally think that is worth losing in exchange for the other 
benefits it brings, which you correctly identified at the end of 
your message, but there's more we lose too:


2. It brings complication with features like `ref` (cannot have a 
ref struct member so once we pass it, it is gone...) and 
potentially `scope`, etc., or even UDAs are lost with an 
intermediary (though UDAs affecting printing might be weird af, 
the door is totally closed with it and possibly open without).

But bottom line: this means it wouldn't work with non-copyable 
types.

---
// in theory printable, has a toString method
struct NoCopy { @disable this(this); void toString(dg) {...} }

NoCopy nc;

// but this works with a tuple... not with an intermediary, unless
// the intermediary allocates a string upon construction, of 
course, but
// that gets us into the hidden GC worries again
print(i"i can print it without copying it $nc");
---

`print` there might take its arguments by `auto ref` and work 
just fine, but an intermediate object wouldn't have that option.

(ref also means you could do an interpolated `readf` string too, 
though I kinda think that is a little weird anyway personally, 
but some people in the other thread did have uses where it could 
be useful, so if we can avoid breaking it, we should. I think the 
non-copy print is more compelling though.)


3. As Walter pointed out with GC too, it is easy to go from tuple 
to object (just do `.whatever` to pass it to an object 
constructor/helper function), but object to tuple is not so 
simple. (of course there is `.tupleof`, but the details lost 
through the intermediate object can never be recovered.) So if 
there's other use cases we miss, the tuple has fewer potential 
regrets.


4. Just want to point out that some people feel strongly that the 
implicit conversion to fully interpolated string is altogether a 
bad idea because it would be a hidden GC allocation. I don't 
agree - I don't think it is that hidden since `alias this` only 
triggers if you name `string` and if you want to avoid GC allocs 
there's plenty of other ways to do it - but still a few people 
said it last thread so I wanna mention it here too.


If you like, we could copy/paste this into my DIP too, might be 
useful for future reference. I didn't spend much time on this 
since I was focused on just advocating for my amendment to 
Walter's and assumed the point was moot anyway (Walter's proposal 
shares these strengths since it also uses the tuple at its core).

But yeah, it is a good idea... just I think my new DIP as 
written, with a typed format string and a tuple of arguments, is 
a better idea since it works with more of D's unique features in 
addition to doing most of what C# can do - just sans the implicit 
conversion.


More information about the Digitalmars-d-announce mailing list