On Sat, Mar 11, 2017 at 03:03:30PM +0000, Nick Treleaven via Digitalmars-d wrote: > On Friday, 10 March 2017 at 19:02:06 UTC, H. S. Teoh wrote: > > A long-standing item on my todo list is to implement compile-time > > writefln format strings using this technique. > > Yes, the actual checking seems straightforward - here I implemented CT > format as an overload: > > import std.format : format; > > auto format(string fmt, A...)(A args) > { > static assert(__traits(compiles, {enum s = .format(fmt, A.init);}), > "Arguments do not match format string: '" ~ fmt ~ "' with " ~ > A.stringof); > return .format(fmt, args); > } > > unittest > { > auto s = format!"%s is %s"(5, "five"); > static assert(!__traits(compiles, {s = format!"%d"("four");})); > }
Yes, that's the general idea of it. But I want to go further: to eliminate unnecessary dependencies of format() based on the contents of the format string. More specifically, currently calling format() will instantiate a whole bunch of stuff for typesetting *all* possible format strings, like floating-point, array expansion, etc.. That means a simple format("%s",s) will pull in a whole bunch of code into your executable that may not actually be used. (And not even LTO can get rid of it, because the code is inside if- or switch-statements, and technically is "referenced" by the caller; the linker has no way to know it won't actually get called.) Not to mention, "%s" itself pulls in a whole bunch of code for dealing with things like field width, max width, padding, etc. (i.e., to handle things like "%10s", "%10.5s", and so on), all of which isn't actually needed to implement plain ole "%s". So the idea is to analyse the format string at compile-time to determine exactly what functionality is actually used, and instantiate only that. Think of it as a format-string mini-compiler: given a format string and a list of argument types, compile it into the equivalent minimal D code. E.g.: format("abc%sdef", s) should get compiled into: "abc" ~ s ~ "def" // N.B.: no floating-point code, no // width handling, etc. and so on. T -- What doesn't kill me makes me stranger.