Boost logo

Boost :

From: Brey, Edward D (EdwardDBrey_at_[hidden])
Date: 2002-01-30 09:45:32


> From: Karl Nelson [mailto:kenelson_at_[hidden]]
>
> Second the "format compile" only gets done once when reused.
> I am basing this on the concepts of regular expressions where the
> expression must have an expensive compile to an internal
> representation,
> but using that representation should be cheap.

Agreed. Reusing the precompiled format context is valuable. And it
requires a second object type to do it. I've been calling it the
format_context, in that most of the string generally comprises the context
that goes around the values substituted into the placeholders.

> If you are using comma list and group concepts, stickyness is totally
> out of place. Especially if you have a "format" specifier which
> states the base for every argument. Thus if you want the next
> argument to be hex you simply state that...
>
> cout << format("%s %x %x %d", i, j, k, l);
>
> Rather than
>
> cout << format("[1] [2] [3] [4]") % i % hex % j % k % dec % l;

Poor support for stickiness is the biggest non-technical weakness of the
formal argument syntax, IMHO. I agree that the above is not easy to read,
and neither is:

format("[1] [2] [3] [4]", i, hex, j, k, dec, l);

Whereas, using operator(), the stickies stand out better:

format("[1] [2] [3] [4]") [i] (hex) [j] [k] (dec) [l];

Of course, this is kind of a bad example, because there is no value to
stickiness here anyway. The following would be fine:

format("[1] [2:x] [3:x] [4]") [i] [j] [k] [l];
or
format("[1] [2:x] [3:x] [4]", i, j, k, l);

A more realistic example for stickiness would be more like

format("[1] [2] [3] [4]" (variable_manipulator) [i] [j] [k] [l];

where the manipulator was decided in some other portion of the code.
However, given the ability to pass in a format_context, passing manipulators
could be largely (entirely?) done away with. The trick is to all a
format_context to accept another format_context, e.g.

format_context variable_context(hex);
...
format(format_context(variable_context, "[1] [2] [3] [4]"), i, j, k, l);

This applies the positional context to the pre-existing context
variable_context, which could, for example, specify hex or decimal.

It is probably a matter of taste whether the above is clearer than:

format("[1] [2] [3] [4]", variable_context, i, j, k, l);

This avoids a layer of nesting and relies on format detecting that the
second argument is of type format_context, just like it would pick up a
manipulator. So long as the variable context tends to always be applied to
all parameters, there isn't any interleaving of parameters and context
overrides, so the readability isn't hampered too much. OTOH, it probably
means a lot more overloads for format.

This examples demonstrate a problem with placeholders that do not allow the
formatting details to be left unspecified: there are times when the
formatting details are not constant with respect to the placeholder string.

> Agree. That is why "%s" is to be a "format specifier" not a "type
> specifier" as in C. You are saying "string literary" should be used
> for any conversion of type->string.

I don't understand. What do you mean by string literary?

> Having persistence in a format is also bad in that it could wrap...
> Ie.
>
> format_expr f("[1] = [2]");
> cout << format(f) % 16 % hex % 16;
> cout << format(f) % 16 % hex % 16;

I think you misunderstand the intended scope of the persistence. It would
be on a per-object basis, not global across all instances of the format
class. So, given the above code, both cout lines would display "16 = 10".

> While under what I am writting you would write the above as
>
> format_expr f("%d = %x");
> cout << format(f, 16, 16);
> cout << format(f, 16, 16);

Again, in this simple example, persistent manipulators are not a good fit.
So yes, a form like the above were better. If one needed to use
manipulators (e.g. the base that was to be used on the right side of the
equality was non constant), one would use local, a local, not persistent
manipulator:

format_expr f("[1] = [2]);
cout << format(f, 16, manip(16));
cout << format(f, 16, manip(16));

Or, even better, one could use a format_context:

format_context context(manip);
...
cout << format(f, 16, context(16));
cout << format(f, 16, context(16));

This has an advantage in that the manipulators are already defined and
aren't designed to take local parameters. However, we can do that in a
format context with operator(). On the other hand, this means more
overloads for format again. I don't know whether that will be a problem or
not.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk