Replacement for snprintf

H. S. Teoh hsteoh at quickfur.ath.cx
Wed Nov 6 20:18:21 UTC 2019


On Wed, Nov 06, 2019 at 06:21:43PM +0000, Rumbu via Digitalmars-d wrote:
> On Wednesday, 6 November 2019 at 17:28:58 UTC, H. S. Teoh wrote:
> > 
> > Then programs that want to support locales can just do this:
> > 
> > 	writefln("%.2?d", curLocale.separator, 3.141592);
[...]
> For %f, the decimal separator is not the only locale specific info.
> Full list:
> 
> -decimal separator
> -negative pattern
> -positive pattern
> -infinity symbol
> -nan symbol
> -digit shapes, especially for Arabic and Thai
> 
> For %d and %g there are more like digit grouping/group separator.
[...]

Haha, wonderful. Don't you just love it when i18n consistently throws a
monkey wrench into any simplistic scheme?  Almost makes me want to
suggest that we need std.i18n before we can implement anything sane
i18n-wise.

But since that's not gonna happen in the foreseeable future, and I'm
sick and tired of the trend around these parts of letting the perfect be
the enemy of the good, I'm going to propose that we just forget about
i18n and just implement formatting for an English-specific locale. If
users *really* want to support locales, just use %s with a wrapper
struct with a toString method that does whatever it takes to get the
right output. I've used this pattern for various problems with
formatting complex objects, and it works fairly well:

	struct i18nFmt {
		float f; // or double, real, whatever
		int precision;
		... // any other params here, like decimal point format, etc.

		void toString(S)(S sink)
			if (isOutputRange!(S, char))
		{
			... // do whatever you need to do here to
			    // produce the right output
		}
	}

	...
	float myData = ...;

	// just use %s instead of some incomprehensible over-engineered
	// crap like %1:3,$13&.*^_7?f
	output = format("%s", myData.i18nFmt);

	// or:
	output2 = format("%s", myData.i18nFmt(curLocale.precision, ...
				/* whatever else */));

This way you lift the complexity out of std.format where it really
doesn't belong, and make it possible to plug in different locale
handling modules in its place. This even opens the door for a future
std.i18n that simply exports a bunch of these locale-dependent proxy
formatters that you could just append to your data items. Much more
extensible and flexible than trying to shoehorn everything into
std.format, which will inevitably turn it into a nasty hairball of
intractible dependencies that's impossible to make pure, nothrow, etc..
(Oh wait, it's already such a hairball. :-D  Let's not make it worse!)
And it makes std.format more pay-as-you-go; if you never need to use
std.i18n it won't pull it in as a dependency just because it needs to
support an obscure format specifier that you don't actually use.


T

-- 
Being forced to write comments actually improves code, because it is easier to fix a crock than to explain it. -- G. Steele 


More information about the Digitalmars-d mailing list