Boost logo

Boost :

From: Samuel Krempp (krempp_at_[hidden])
Date: 2001-12-19 20:07:02


On Wed, 2001-12-19 at 22:09, Karl Nelson wrote:
> The implemention I sent of format had no problems with extra
> arguments.
>
> cout << format("A %2$s %1$s") << s1 << s2<< endl;

> For good reason. All extra agruments after the format
> became regular operations.

that's the problem for me : it won't notice user's errors.
The uer could mistype the format-string, eg hit "%" twice : "%%2$s"
I'd like the syntax to enforce the right number of arguments, no more no
less.
My code raises exceptions in both cases.
I know that yours does not notice excess of arguments,
and I don't know what happens with a lack of arguments.
Do you check for that inside the object's destructor ??
(or rather, the proxy's destructor. the first
cout << format("...") returns a temporary proxy)

Thus, if somebody forgets one argument :
cout << format("%2$s bla bla %1$s") << x;
When the proxy dies while still waiting for an argument, you can detect
that and raise an exception.

That's the most probable, and most disastrous mistake, so it's good that
your ofrstream can catch it.
But the other kind of user errors -too much arguments-, should be
detected too, and that is not possible unless you force the user to use
"endf" before continuing to use the stream.

That's why I thought the endf was required, rather than optional.
(in my opinion it should be required, so that excess of arguments can be
detected)

> became
> operator<< (cout,"A ");
> operator<< (cout, s1);
> operator<< (cout," ");
> operator<< (cout, s2);
> operator<< (cout, endl);

After reading Heintzelman messages, I thought you were claiming that
your class calls only those operations, in the sample case.
But you're using internal streams, and strings, just as I do,
Actually you are only describing what will be eventually output to cout.
(I'm explaining this in case other people misunderstood as I first did)

> Further, you can force it off with endf
> cout << format("A %s %s") << s1 << endf << s2;
>
> (extra argument lost)

err, what exactly happens in this case ?
Is s2 really lost ? (why not send it to cout?? that would be more
natural)
Does the format agrees to output the partial result (second argument is
missing), without raising an exception ??
It would be bad behviour, very error prone.

> Extreme shortness in typing charactors is not a
> very good reason for a design decision.

You're right. But that was not a reason for me,
just a bonus.
against those who say
"<< is better, it looks good. just like good old streams."
I can say :
"<< is better, it's shorter and makes the code easier to read."

> > On the other hand, with operator% :
> > 1. the code is smaller than with '<<' and, in my opinion, nicer.
>
> If it acts like stream make it look like a stream. The charactors
> saved are not worth force the user to have more concepts. Format
> should be considered a manipulator and as such should not change the
> syntax.

Do you really think it acts like a stream, and that a format object is
like a manipulator ??
I don't. It's much more complex than a manipulator, and does the
formatting internally, not with the stream passed on the left.

I think using the same notation than stream only confuses everything,
and could in the end mislead the user.
I prefer have format do his job, with a notation which makes it easy to
see where it starts and where it ends.
cout << "Time in London : " << format("%1 h %2") % h % m
   << "\nTime in Paris : " << format("%1 h %2") % (h+offset) % m
   << endl;

I see format objects as "string makers", that you can output to an
ostream.
nasonov said he thinks they should be seen only as "string makers" (in
substance), and thus he does not provide operator<<(stream, format).
I think this operator is useful and I provide it as a shortcut to
"take the string, send it to the stream", but somehow I agree with him.
I like the fact that operato% clearly identifies what goes with the
format object, and what goes with the stream. So it's compatible with
the operator<<(stream, format) while keeping the "string maker"
aspect.
It's visually very clear to see what is happenning in the previous
example.

> > point 3 is an inconvenient, but I think it's not a big price.
> > If you forget to print (1+2), it means :
                   ^^^^^
I meant 'type', here. not print..

> > ( format("%1 %2") % 1 ) + 2 % <the_rest_of_the_line>
> > So it tries to call operator+ on a format object, => the error is
> > detected at compile time.
>
> What is wrong with 'cout << (format("%1 %2") << 1) ;' ?

hum, the user forgot one of the 2 arguments (raise an exception, no ?)
but I don't see the link with what I tried to say.

What I meant is : in case of problems due to the precedence of %, it
won't pass compilation. (because it will call operator+(format, int) )
More generally, it will call operator+(format, T)
or operator-(format, T)
none of which will be defined.

It's an example of why not define conversion from format to string, as
it would make
cout << format(" %1 ") % s1+s2;
compile (when s1, s2 are strings) and print " "+s1+" "+s2
instead of " "+(s1+s2)+" " as the user could expect.

> The compiler should construct the format make its contents then
> put it out when it hits the stream.
>
> Just like
> basic_format<char, trait<char> > f("%1 %2");
> f << "a" << "b";
> cout << f;
>
> Should allow the format to be made ahead of time.

My format does that. (with %, of course..)

> (okay I am glossing over what should it do with
> cout << hex << format("%d") << 16;
> But the point is there we could implement something
> much niced and more stream like.)

ah ! That's a good example to show that formats dont act like a
manipulator. Which is the best reason to use a notation that does not
look like it were a manipulator.

> cout << hex << format("%d") << 16;
Who could guess that hex won't have an effect,a nd that it will print
"16" instead of "10" ??

Compare with :
cout << hex << format("%d") % 16;

That's a good point for % rather than <<.
In fact, in my opinion, it's the strongest point. the rest is mre
subjective.
While this one is essential : we should not use << because format is NOT
a manipulator.

I would use << only if we could turn format into some kind of clever
manipulator, which distributes the following arguments directly to the
stream, in the correct order (setting some stream flags on the fly if
asked to).
That's the ideal Heintzelman talked about, and I doubt it is feasible
(not yet looked what the 'bind' library does, though)

That's not at all what our format classes currently do (mine as well as
yours).
It's string makers, not manipulators.

regards,

-- 
Samuel

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