On Mon, Sep 08, 2025 at 01:09:02PM +1200, Richard (Rikki) Andrew Cattermole via Digitalmars-d-announce wrote: > std.format is on my list of modules that I want replaced. > > Its written with a lot of error conditions, rather than just adapting > to the inputs. Hence lots of potential for exceptions being thrown > that don't need to be. > > Multiple multipliers in ``formattedWrite``: format string, output > range.
IMO, a lot of template bloat could be removed by internally converting output ranges to a delegate of static type that receives a const(char)[] and writes to whatever output range was passed in from user code. 90% of the std.format code does not actually care for the concrete type of the output range; we do not need a copy of the entire formatting code for every output range type passed in. Just erase the type at the entry function and make most of the formatting code non-templated. > What I'd like to do is to force IES for one or more values, if you > want finer grained control you want do one value a time > (``formatValue``). > > ```d > writeln(i"$i ${i:X}: $(j + 1)/${(j + 1):X} $1 ${0:X}", k, obj, "atend"); > ``` I'm still a fan of old-school format strings, I've to admit. Having to manually type `formatValue(x), formatValue(y), ...` is just way too much boilerplate. > Require the use of a string builder, rather than any old output range. Too much boilerplate to use a string builder. > This is a required change for pretty printing. It requires the use of > arbitrary inserts and removals that ranges can't do. Format strings should be just strings. It should not accept arbitrary ranges (does it do that currently?). Arguments may be ranges. > Every template parameter like these that you have is a multiplier of > instances, and that isn't good for compile times. Simplifying them > down may seem like a pain, but it helps quite significantly. Given > that there are some clear requirements and use cases we can in fact > simplify it without hurting anyone enough to care. See, the thing is that the current implementation of std.format goes about things the wrong way. It really should be just a thin wrapper template, the sole purpose of which is to unpack the incoming arguments and forward them to non-templated formatting functions. Or, at least, formatting functions templated only on a *single* argument type (like formatValue!int, formatValue!string, formatValue!float, ...), or perhaps just overload on various basic types, maybe plus a couple of templates for handling structs and classes, not on the entire `Args...` tuple of types. The latter causes combinatorial explosion of template instances, which is both bloating and needless. Only the top-level std.format.format needs to be templated on `Args...`. This should be split up so that instead of O(n*m) template instantiations we have only O(n) template instantiations (or preferably, O(1) template instantiations if all the type-dependent stuff is handled at the top level, and all lower-level functions are isolated formatting functions that only do one job each). Also, I dream of the day when we can pass compile-time format strings to std.format and it will *only* instantiate the formatting functions that you actually use. Float-formatting functions are particularly complex and bloaty; why should your program pay for that extra baggage if you never actually format a float? The various formatting functions should be pulled in only when you actually use them. Just because you call std.format with "%d" should not also pull in the whole shebang for formatting floats, structs, classes, BigInts, and who knows what else. T -- Economics: (n.) The science of explaining why yesterday's predictions didn't come true today.