DIP 1027--String Interpolation--Final Review Discussion Thread
Adam D. Ruppe
destructionator at gmail.com
Mon Feb 3 03:57:09 UTC 2020
On Monday, 3 February 2020 at 02:57:41 UTC, Arine wrote:
> I don't think you should compromise. Using printf as the basis
> just limits what can be done with an interpolated string. How
> do you handle custom types?
Eh, that's a solved problem. See:
https://wiki.dlang.org/Defining_custom_print_format_specifiers
The format string is incredibly flexible and the tuple proposal
does a fairly good job maintaining all available information
until the last minute.
With the % -> %% encoding, it is also possible to reliably*
determine which
* with the exception of a user-defined format string that breaks
this convention. e.g. `i"${not_percent}(foo)"` will not be able
to tell for certain that foo is tied to not_percent, and this can
throw off processing of all subsequent arguments as well. Maybe
we should do something about this.
> Since printf() wouldn't be able to take a custom type.
Yeah, printf would likely fail with custom types, but that's
printf's limitation - D's writef works well with them, including
various custom format specifiers and allocation-free output.
And other custom functions, provided we identify the format
string as such, can do any special parsing of it.
With my proposed addendum, even compile-time validation of the
format string is possible in consumer functions:
void my_thing(Format, Args...)(Format fmt, Args args) {
static if(is(Format == _d_interpolated_string!S, string S))
static assert(string_is_ok(S));
else
static assert(0, "you didn't pass an interpolated string");
// use args according to fmt
}
(I would actually recommend we make the name and interface a wee
bit more friendly in the library for user consumption, including
methods that can be tested without tying us to just one argument
like that is expression does above, for future expansion
potential... like I kinda want to also say how many arguments
there are as CT params there, or even the slices of that string
that represent format strings - that would IMO be the holy grail
as we can not only get how many args but exactly where they are
without reparsing the string - but I digress. Regardless, the
compiler can output the _d_whatever ugly thing and I like to use
ugly things in these examples in an effort to avoid people
arguing over the name when I'd rather focus on the underlying
concept.)
But anyway since the format string is actually part of the
*type*, we can overload on it and extract the original string as
a compile-time constant - including when passed as a runtime
argument list - for further processing.
> For each object toString() would allocate it's own buffer, when
> it could be constructed in place.
void toString(
scope void delegate(const(char)[]) sink,
FormatSpec!char fmt)
is already possible with D's existing format function on custom
objects. No allocation and you can respond to arbitrary
formatting details as specified there.
So your example:
> Or to retain the type, it would then not work with printf().
A custom type wouldn't work with printf with the DIP as it
stands. It does not attempt to convert anything, it just forwards
the arguments.
Similarly your function could require that the format strings
must just be %s and you don't support customization. The
implementation there can be as simple as scanning forward for %
and a compile-time template could break it up into an array for
you with no runtime trouble. Or you could only support a custom
format that the user needs to put in the ${here}(var) thingy.
I'm *very* close to supporting this DIP, it isn't actually that
bad. As it is, I'd have to recommend we defeat it, but if we can
all agree to amend it to put in the template thing we can fix
everything. Even with just the one string arg, we can do a lot
with it...
(my struct would make simple cases simpler - you can just
.toString it without imports or even alias toString this - but
the template does actually allow more custom flexibility.)
More information about the Digitalmars-d
mailing list