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