Topic: A proposal to add a printf-like interface to the
Author: Zhihao Yuan <lichray@gmail.com>
Date: Sun, 23 Dec 2012 00:53:58 -0600
Raw View
Hi,
After some further research, I prepared an proposal to add
std::experimental::putf (and sputf, no description yet).
https://github.com/lichray/formatxx/blob/proposal/proposal/printf.md
(The table of contents only works with maruku; not supported by GitHub preview).
Comments and suggestions are welcome. Thanks.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Jeffrey Yasskin <jyasskin@googlers.com>
Date: Sun, 23 Dec 2012 01:36:22 -0800
Raw View
--f46d044631807f559c04d181d18d
Content-Type: text/plain; charset=ISO-8859-1
Your proposal says it intentionally omits the positional formatting
specifiers. This makes it useless for localization, which often needs to
change the order of a sentence. Reordering is the primary use case that
can't be supported by existing iostreams or a hypothetical StrCat()
facility, so I consider it essential for any format string proposal.
I would also hope that any proposal in this area would look at some of the
other format string syntaxes in other existing languages instead of just
blindly copying a subset of printf(). It's possible that printf() is the
best we can do, or that backward-compatibility concerns win out over the
benefits of the other syntaxes, but variadic templates' removal of the need
to specify type information definitely frees up more options, which the
paper needs to explicitly consider.
Jeffrey
On Sat, Dec 22, 2012 at 10:53 PM, Zhihao Yuan <lichray@gmail.com> wrote:
> Hi,
>
> After some further research, I prepared an proposal to add
> std::experimental::putf (and sputf, no description yet).
>
> https://github.com/lichray/formatxx/blob/proposal/proposal/printf.md
>
> (The table of contents only works with maruku; not supported by GitHub
> preview).
>
> Comments and suggestions are welcome. Thanks.
>
> --
> Zhihao Yuan, ID lichray
> The best way to predict the future is to invent it.
> ___________________________________________________
> 4BSD -- http://4bsd.biz/
>
> --
>
>
>
>
--
--f46d044631807f559c04d181d18d
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div style=3D"font-family:arial,helvetica,sans-serif;font-size:10pt"><div d=
ir=3D"ltr"><div class=3D"gmail_default" style>Your proposal says it intenti=
onally omits the positional formatting specifiers. This makes it useless fo=
r localization, which often needs to change the order of a sentence. Reorde=
ring is the primary use case that can't be supported by existing iostre=
ams or a hypothetical StrCat() facility, so I consider it essential for any=
format string proposal.</div>
<div class=3D"gmail_default" style><br></div><div class=3D"gmail_default" s=
tyle>I would also hope that any proposal in this area would look at some of=
the other format string syntaxes in other existing languages instead of ju=
st blindly copying a subset of printf(). It's possible that printf() is=
the best we can do, or that backward-compatibility concerns win out over t=
he benefits of the other syntaxes, but variadic templates' removal of t=
he need to specify type information definitely frees up more options, which=
the paper needs to explicitly consider.</div>
<div class=3D"gmail_default" style><br></div><div class=3D"gmail_default" s=
tyle>Jeffrey</div></div><div class=3D"gmail_extra"><br><br><div class=3D"gm=
ail_quote">On Sat, Dec 22, 2012 at 10:53 PM, Zhihao Yuan <span dir=3D"ltr">=
<<a href=3D"mailto:lichray@gmail.com" target=3D"_blank">lichray@gmail.co=
m</a>></span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex">Hi,<br>
<br>
After some further research, I prepared an proposal to add<br>
std::experimental::putf (and sputf, no description yet).<br>
<br>
<a href=3D"https://github.com/lichray/formatxx/blob/proposal/proposal/print=
f.md" target=3D"_blank">https://github.com/lichray/formatxx/blob/proposal/p=
roposal/printf.md</a><br>
<br>
(The table of contents only works with maruku; not supported by GitHub prev=
iew).<br>
<br>
Comments and suggestions are welcome. =A0Thanks.<br>
<br>
--<br>
Zhihao Yuan, ID lichray<br>
The best way to predict the future is to invent it.<br>
___________________________________________________<br>
4BSD -- <a href=3D"http://4bsd.biz/" target=3D"_blank">http://4bsd.biz/</a>=
<br>
<span class=3D"HOEnZb"><font color=3D"#888888"><br>
--<br>
<br>
<br>
<br>
</font></span></blockquote></div><br></div></div>
<p></p>
-- <br />
<br />
<br />
<br />
--f46d044631807f559c04d181d18d--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Sun, 23 Dec 2012 05:33:03 -0600
Raw View
On Sun, Dec 23, 2012 at 3:36 AM, Jeffrey Yasskin <jyasskin@googlers.com> wrote:
> Your proposal says it intentionally omits the positional formatting
> specifiers. This makes it useless for localization, which often needs to
> change the order of a sentence. Reordering is the primary use case that
> can't be supported by existing iostreams or a hypothetical StrCat()
> facility, so I consider it essential for any format string proposal.
Well, I found a way to implement one, with a recursive linear search (thus
turns a runtime value into a tuple index). So add positional arguments...
> I would also hope that any proposal in this area would look at some of the
> other format string syntaxes in other existing languages instead of just
> blindly copying a subset of printf(). It's possible that printf() is the
> best we can do, or that backward-compatibility concerns win out over the
> benefits of the other syntaxes, but variadic templates' removal of the need
> to specify type information definitely frees up more options, which the
> paper needs to explicitly consider.
For me, I prefer a format specification with type hint. A pure positional
syntax like %1%, %2% or even a pure sequential syntax like {}, {} do not
make much sense to me. But %d obviously offers more information.
Another desired feature may be a container access syntax, like python's
..format(). But a syntax like "%0[1]$d" and "%0{age}$d" looks too complex.
Maybe we need one more proposal (for a brand new syntax).
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Sun, 23 Dec 2012 21:34:11 -0600
Raw View
On Sun, Dec 23, 2012 at 5:33 AM, Zhihao Yuan <lichray@gmail.com> wrote:
> Well, I found a way to implement one, with a recursive linear search (thus
> turns a runtime value into a tuple index). So add positional arguments...
Now positional specifications (%n$ and *n$) are already supported. Before
updating the proposal, I have a question: should mixing positional and non-
positional specifications being allowed? POSIX says the behavior is
undefined. But, why not just letting non-positional arguments count from
left to right? Like:
printf("%2$d, %d, %1$d\n", 1, 2, 3);
I hope it prints 2, 1, 1, but the implementation that I tested prints 2, 3, 1.
So there are 3 (at least) choices:
1. An undefined printing result and a failbit;
2. Only non-positional argument counts;
3. Positional argument reset the counter.
Any thoughts?
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Bjorn Reese <breese@mail1.stofanet.dk>
Date: Mon, 24 Dec 2012 11:00:56 +0100
Raw View
On 2012-12-23 10:36, Jeffrey Yasskin wrote:
> Your proposal says it intentionally omits the positional formatting
> specifiers. This makes it useless for localization, which often needs to
> change the order of a sentence. Reordering is the primary use case that
> can't be supported by existing iostreams or a hypothetical StrCat()
> facility, so I consider it essential for any format string proposal.
There are some challenges with the positional arguments of printf.
As arguments are passed as variadic arguments, we must know the type of
each argument. This information is implicit in the conversion specifier
and the optional length modifier. This means that you cannot have gaps
in the positional numbering. SUS states that "specifying the Nth
argument requires that all the leading arguments, from the first to the
(N-1)th, are specified in the format string." This makes the positional
arguments somewhat limited, because arbitrary arguments cannot be
omitted from localized output (unless we also introduce a suppression
modifier as in scanf.)
Furthermore, SUS allows multiple references to arguments in the
formatting string. That is, you may use %2$ several times in order to
reuse the argument. This may make sense for the width and precision
modifiers, e.g. "%1$.*3$d %2$.*3$d", but SUS does not say what happens
if you use different types, such as "%1$d %1$lf".
The overall message that I would like to confer is that the positional
arguments are an error-prone construct, where much of the burden is
put on the developer, and that makes you wonder if it is the correct
solution to the localization problem. Having said that, I do not have
a suggestion for an alternative solution.
--
.
Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Mon, 24 Dec 2012 12:54:40 +0200
Raw View
On 24 December 2012 12:00, Bjorn Reese <breese@mail1.stofanet.dk> wrote:
> (N-1)th, are specified in the format string." This makes the positional
> arguments somewhat limited, because arbitrary arguments cannot be
> omitted from localized output (unless we also introduce a suppression
> modifier as in scanf.)
> Furthermore, SUS allows multiple references to arguments in the
> formatting string. That is, you may use %2$ several times in order to
> reuse the argument. This may make sense for the width and precision
> modifiers, e.g. "%1$.*3$d %2$.*3$d", but SUS does not say what happens
> if you use different types, such as "%1$d %1$lf".
> The overall message that I would like to confer is that the positional
> arguments are an error-prone construct, where much of the burden is
> put on the developer, and that makes you wonder if it is the correct
> solution to the localization problem. Having said that, I do not have
> a suggestion for an alternative solution.
Then I guess the overall message is to avoid being bug-compatible with printf.
I find it perfectly reasonable to have format strings that omit some arguments,
and print an argument multiple times with different formats. Those limitations
of printf are probably caused by printf's relying on variable arguments, and I'd
imagine a variadic template can solve such problems.
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Mon, 24 Dec 2012 05:42:45 -0600
Raw View
On Mon, Dec 24, 2012 at 4:00 AM, Bjorn Reese <breese@mail1.stofanet.dk> wrote:
> As arguments are passed as variadic arguments, we must know the type of
> each argument. This information is implicit in the conversion specifier
> and the optional length modifier. This means that you cannot have gaps
> in the positional numbering. [...]
At the beginning, I have the same impression. But after read folly's code:
https://github.com/facebook/folly/blob/master/folly/Format.h
I know how to deal with it. Once we read a positional index, we recursively
call the format function, with a K + 1 template argument, until index - 1 == K;
the out of range overload is poisoned (failbit and return).
> [...] SUS states that "specifying the Nth
> argument requires that all the leading arguments, from the first to the
> (N-1)th, are specified in the format string." [...]
We have no such limitation with the implementation technique described above.
> [...] but SUS does not say what happens
> if you use different types, such as "%1$d %1$lf".
As you know, C va_arg requires type information in the format string, while
variadic template already have. If a type-hint does not match, the argument
is printed using the << operator // with the flags, fill settings.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: stackmachine@hotmail.com
Date: Mon, 24 Dec 2012 03:54:39 -0800 (PST)
Raw View
------=_Part_11_8017325.1356350079634
Content-Type: text/plain; charset=ISO-8859-1
There is no problem at all with positional format specifiers. In another
thread I've already shown how one could do that: https://ideone.com/6Eoj9C
Basically, I use type erasure to put all arguments into an array and then
print the elements with the format specifier index. Also, in my
implementation it is allowed to mix positional and non-positional format
specifiers, as non-positional specifiers just 'iterate' through the
arguments.
--
------=_Part_11_8017325.1356350079634
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
There is no problem at all with positional format specifiers. In another th=
read I've already shown how one could do that: <a href=3D"https://ideone.co=
m/6Eoj9C" target=3D"_blank">https://ideone.com/6Eoj9C</a><br>Basically, I u=
se type erasure to put all arguments into an array and then print the eleme=
nts with the format specifier index. Also, in my implementation it is allow=
ed to mix positional and non-positional format specifiers, as non-positiona=
l specifiers just 'iterate' through the arguments.<br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_11_8017325.1356350079634--
.
Author: Martinho Fernandes <martinho.fernandes@gmail.com>
Date: Mon, 24 Dec 2012 15:08:27 +0100
Raw View
On 24 December 2012 11:00:56, Bjorn Reese wrote:
> There are some challenges with the positional arguments of printf.
>
> As arguments are passed as variadic arguments, we must know the type of
> each argument. This information is implicit in the conversion specifier
> and the optional length modifier. This means that you cannot have gaps
> in the positional numbering. SUS states that "specifying the Nth
> argument requires that all the leading arguments, from the first to the
> (N-1)th, are specified in the format string." This makes the positional
> arguments somewhat limited, because arbitrary arguments cannot be
> omitted from localized output (unless we also introduce a suppression
> modifier as in scanf.)
This may be a problem in C, because of the lousy variadic arguments,=20
but in C++ it is a non-problem. In C++ we can have type-safe variadic=20
arguments. The type information does not need to obtained from the=20
format string: it can be obtained from the compiler itself.
> Furthermore, SUS allows multiple references to arguments in the
> formatting string. That is, you may use %2$ several times in order to
> reuse the argument. This may make sense for the width and precision
> modifiers, e.g. "%1$.*3$d %2$.*3$d", but SUS does not say what happens
> if you use different types, such as "%1$d %1$lf".
Again, in C++ we can obtain type information from the compiler itself,=20
so there is no need to infer the type from the formatters. So this does=20
not need to be a problem either.
> The overall message that I would like to confer is that the positional
> arguments are an error-prone construct, where much of the burden is
> put on the developer, and that makes you wonder if it is the correct
> solution to the localization problem. Having said that, I do not have
> a suggestion for an alternative solution.
No, the positional arguments are not an error-prone construct; the=20
lousy C variadic arguments are an error-prone construct.
Note how the proposal uses variadic templates.
--
Mit freundlichen Gr=FC=DFen,
Martinho Fernandes
--=20
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Mon, 24 Dec 2012 19:45:21 -0600
Raw View
Hi,
The positional arguments (numbered specifications & parametrized lengths) are
already documented in the proposal:
https://github.com/lichray/formatxx/blob/proposal/proposal/printf.md
And the implementation is available at
https://github.com/lichray/formatxx/tree/proposal
as always.
About mixing positional and non-positional arguments,
On Sun, Dec 23, 2012 at 9:34 PM, Zhihao Yuan <lichray@gmail.com> wrote:
> 2. Only non-positional argument counts;
> 3. Positional argument reset the counter.
since there are at least two explanations, and it results an undefined behavior
in C, I decided to pick neither. Instead, this is an well-defined error in the
proposal, which results in a failbit-and-return at the format specification
causing the error.
Thanks to the people who strongly suggested me to add the positional
arguments ;)
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Herb Sutter <hsutter@microsoft.com>
Date: Tue, 25 Dec 2012 17:30:29 +0000
Raw View
Thanks for doing this. A few questions and suggestions:
- In the Overview, it's usually helpful to start by showing a few examples =
of how the user's code would look, so we can see how the feature would be u=
sed. Could you include a few examples, maybe a simple one, then showing for=
matting, then showing positional/multiple parameters? (Suggestion: Perhaps =
even with printf and Boost.Format side by side equivalents for each example=
, to show at a glance how much it's similar for cases where the capabilitie=
s are the same, and how much it's better for cases the others can't cover w=
ell.)
- What is the performance like: (a) specifically compared to printf in the =
overlapping cases; and (b) generally not paying for what I don't use? In pa=
rticular, if I don't use some of positional stuff which would require space=
/time overhead for multiple passes or caching, will I get performance rough=
ly equivalent to printf? That would be ideal, if it's possible, and it woul=
d be a major selling point that should be highlighted if it's true.
- Is the format string fully backward-compatible with Boost.Format? It soun=
ds like it is but I wasn't sure from the description.
Thanks again,
Herb
P.S.: This is a perfect example of what it takes to get a proposal into the=
standard. It's not enough to say "the standard should allow X, why don't t=
hey just add that?" Someone has to do the work of generating a well-specifi=
ed proposal and the legwork of successive refinement based on feedback. Tha=
nks for contributing this time and effort!
> -----Original Message-----
> From: Zhihao Yuan [mailto:lichray@gmail.com]
> Sent: Monday, December 24, 2012 5:45 PM
> To: std-proposals@isocpp.org
> Subject: Re: [std-proposals] A proposal to add a printf-like interface to=
the
> streams library
>=20
> Hi,
>=20
> The positional arguments (numbered specifications & parametrized lengths)
> are already documented in the proposal:
>=20
> https://github.com/lichray/formatxx/blob/proposal/proposal/printf.md
>=20
> And the implementation is available at
>=20
> https://github.com/lichray/formatxx/tree/proposal
>=20
> as always.
>=20
> About mixing positional and non-positional arguments,
>=20
> On Sun, Dec 23, 2012 at 9:34 PM, Zhihao Yuan <lichray@gmail.com> wrote:
> > 2. Only non-positional argument counts; 3. Positional argument reset
> > the counter.
>=20
> since there are at least two explanations, and it results an undefined
> behavior in C, I decided to pick neither. Instead, this is an well-defin=
ed error
> in the proposal, which results in a failbit-and-return at the format
> specification causing the error.
>=20
> Thanks to the people who strongly suggested me to add the positional
> arguments ;)
>=20
>=20
> --
> Zhihao Yuan, ID lichray
> The best way to predict the future is to invent it.
> ___________________________________________________
> 4BSD -- http://4bsd.biz/
>=20
> --
>=20
>=20
>=20
>=20
--=20
.
Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Tue, 25 Dec 2012 16:04:53 -0800 (PST)
Raw View
------=_Part_427_27538723.1356480293861
Content-Type: text/plain; charset=ISO-8859-1
Op zondag 23 december 2012 07:53:58 UTC+1 schreef Zhihao Yuan het volgende:
> Nice proposal!
> If an *internally formattable* argument is an object of an instantiation
of basic_string, it is printed as if a return value of its data()member
function is printed.
I assume size() is used too?
Otherwise you're running into issues with string termination.
--
------=_Part_427_27538723.1356480293861
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Op zondag 23 december 2012 07:53:58 UTC+1 schreef Zhihao Yuan het volgende:=
<br><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">Nice proposal!</blockquote=
><div><br></div><div>> <span style=3D"color: rgb(51, 51, 51); font-=
family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14.399999=
618530273px; line-height: 17.600000381469727px;">If an </span><em styl=
e=3D"color: rgb(51, 51, 51); font-family: Helvetica, arial, freesans, clean=
, sans-serif; font-size: 14.399999618530273px; line-height: 17.600000381469=
727px;">internally formattable</em><span style=3D"color: rgb(51, 51, 51); f=
ont-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 14.39=
9999618530273px; line-height: 17.600000381469727px;"> argument is an o=
bject of an instantiation of </span><code style=3D"margin-right: 2px; =
margin-left: 2px; padding-right: 5px; padding-left: 5px; border: 1px solid =
rgb(234, 234, 234); font-size: 12px; font-family: Consolas, 'Liberation Mon=
o', Courier, monospace; background-color: rgb(248, 248, 248); border-top-le=
ft-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3=
px; border-bottom-left-radius: 3px; white-space: nowrap; color: rgb(51, 51,=
51);">basic_string</code><span style=3D"color: rgb(51, 51, 51); font-famil=
y: Helvetica, arial, freesans, clean, sans-serif; font-size: 14.39999961853=
0273px; line-height: 17.600000381469727px;">, it is printed as if a return =
value of its </span><code style=3D"margin-right: 2px; margin-left: 2px=
; padding-right: 5px; padding-left: 5px; border: 1px solid rgb(234, 234, 23=
4); font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, mon=
ospace; background-color: rgb(248, 248, 248); border-top-left-radius: 3px; =
border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-botto=
m-left-radius: 3px; white-space: nowrap; color: rgb(51, 51, 51);">data()</c=
ode><span style=3D"color: rgb(51, 51, 51); font-family: Helvetica, arial, f=
reesans, clean, sans-serif; font-size: 14.399999618530273px; line-height: 1=
7.600000381469727px;">member function is printed.</span></div><div><br></di=
v><div>I assume size() is used too?</div><div>Otherwise you're running into=
issues with string termination. </div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_427_27538723.1356480293861--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Tue, 25 Dec 2012 23:48:33 -0600
Raw View
On Tue, Dec 25, 2012 at 11:30 AM, Herb Sutter <hsutter@microsoft.com> wrote=
:
> - In the Overview, it's usually helpful to start by showing a few example=
s of how the user's code would look, so we can see how the feature would be=
used. Could you include a few examples, maybe a simple one, then showing f=
ormatting, then showing positional/multiple parameters? (Suggestion: Perhap=
s even with printf and Boost.Format side by side equivalents for each examp=
le, to show at a glance how much it's similar for cases where the capabilit=
ies are the same, and how much it's better for cases the others can't cover=
well.)
Really helpful suggestions! Now I show the difference between
_internally formattable_ and _potentially formattable_ visually,
before explaining their definitions.
> - What is the performance like: (a) specifically compared to printf in th=
e overlapping cases; and (b) generally not paying for what I don't use? In =
particular, if I don't use some of positional stuff which would require spa=
ce/time overhead for multiple passes or caching, will I get performance rou=
ghly equivalent to printf? That would be ideal, if it's possible, and it wo=
uld be a major selling point that should be highlighted if it's true.
I made a benchmark using Boost.Format's code,
http://students.cs.niu.edu/~z1565938/printf.html#performance_notes
and it shows that my implementation is 70% slower than using
iostreams alone, but is still 100% faster than Boost.Format.
Considering _internally formattable_ can be formatted
inside the standard library, the final performance can be further
closer to the streams library.
It's not... fair... to be compared with printf, because:
1. I defined a very strict error handling policy, while printf may
prints garbage, or crashes with these errors.
2. The streams library (shipped with g++48) is already 50% slower
than printf. -- Function calls are expensive; even std::putf can
be implemented inside libstdc++, the recursions can't be saved.
> - Is the format string fully backward-compatible with Boost.Format? It so=
unds like it is but I wasn't sure from the description.
Syntactically, 100% compatible with its legacy syntax, since
Boost.Format uses a subset of POSIX printf, while ours is
99.99% close to POSIX (only, without %n). For instance,
Boost.Format does not support %*d (parametrized width).
http://students.cs.niu.edu/~z1565938/printf.html#syntax
And the formatting features of std::putf are also 99.99% compatible
with POSIX printf, when the argument is _internally formattable_.
If it's not, the supported feature set is even smaller than
Boost.Format, since I don't want to pay for any possible extra
copying. These are shown in the examples in the proposal:
http://students.cs.niu.edu/~z1565938/printf.html#extensibility
I uploaded the release-candidate version of my proposal to
http://students.cs.niu.edu/~z1565938/printf.html
Now the table of contents work :)
> P.S.: This is a perfect example of what it takes to get a proposal into t=
he standard. It's not enough to say "the standard should allow X, why don't=
they just add that?" Someone has to do the work of generating a well-speci=
fied proposal and the legwork of successive refinement based on feedback. T=
hanks for contributing this time and effort!
Thanks so much for your encouragements and suggestions.
String truncation on basic_string is removed by the way. And
the benefit is that the proposal now works with Beman's
"String Interoperation Library" out of box.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.
--=20
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Wed, 26 Dec 2012 02:53:43 -0600
Raw View
On Tue, Dec 25, 2012 at 11:48 PM, Zhihao Yuan <lichray@gmail.com> wrote:
> I made a benchmark using Boost.Format's code,
> http://students.cs.niu.edu/~z1565938/printf.html#performance_notes
>
> and it shows that my implementation is 70% slower than using
> iostreams alone, but is still 100% faster than Boost.Format.
At the beginning I think empty function calls (to locate the positional
arguments) are cheap, but a further benchmark shows that they are not.
With 4 arguments, positional arguments are slower than non-positional
version by 11%, and the overhead comparing with iostreams drops
from 70% to 52%.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Wed, 26 Dec 2012 04:52:54 -0800 (PST)
Raw View
------=_Part_129_4855607.1356526374459
Content-Type: text/plain; charset=ISO-8859-1
Op woensdag 26 december 2012 06:48:33 UTC+1 schreef Zhihao Yuan het
volgende:
> I made a benchmark using Boost.Format's code,
> http://students.cs.niu.edu/~z1565938/printf.html#performance_notes
>
> and it shows that my implementation is 70% slower than using
> iostreams alone, but is still 100% faster than Boost.Format.
>
> I thought iostreams was slow already.
Performance is important, but I think it's more important to get the
interface right as it's far easier to change the implementation than to
change the interface.
I don't see a sprintf variant in the proposal, shouldn't there be one?
--
------=_Part_129_4855607.1356526374459
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Op woensdag 26 december 2012 06:48:33 UTC+1 schreef Zhihao Yuan het volgend=
e:<br><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;">I made a benchmark using=
Boost.Format's code,
<br><a href=3D"http://students.cs.niu.edu/~z1565938/printf.html#performance=
_notes" target=3D"_blank">http://students.cs.niu.edu/~<wbr>z1565938/printf.=
html#<wbr>performance_notes</a>
<br>
<br>and it shows that my implementation is 70% slower than using
<br>iostreams alone, but is still 100% faster than Boost.Format.
<br><br></blockquote><div>I thought iostreams was slow already.</div><div>P=
erformance is important, but I think it's more important to get the interfa=
ce right as it's far easier to change the implementation than to change the=
interface.</div><div><br></div><div>I don't see a sprintf variant in the p=
roposal, shouldn't there be one?</div><div><br></div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_129_4855607.1356526374459--
.
Author: Herb Sutter <hsutter@microsoft.com>
Date: Wed, 26 Dec 2012 17:18:45 +0000
Raw View
Great! This looks good, and I see the paper captures the answers below.
Thanks again,
Herb
> -----Original Message-----
> From: Zhihao Yuan [mailto:lichray@gmail.com]
> Sent: Tuesday, December 25, 2012 9:49 PM
> To: std-proposals@isocpp.org
> Subject: Re: [std-proposals] A proposal to add a printf-like interface to the
> streams library
>
> On Tue, Dec 25, 2012 at 11:30 AM, Herb Sutter <hsutter@microsoft.com>
> wrote:
> > - In the Overview, it's usually helpful to start by showing a few
> > examples of how the user's code would look, so we can see how the
> > feature would be used. Could you include a few examples, maybe a
> > simple one, then showing formatting, then showing positional/multiple
> > parameters? (Suggestion: Perhaps even with printf and Boost.Format
> > side by side equivalents for each example, to show at a glance how
> > much it's similar for cases where the capabilities are the same, and
> > how much it's better for cases the others can't cover well.)
>
> Really helpful suggestions! Now I show the difference between _internally
> formattable_ and _potentially formattable_ visually, before explaining their
> definitions.
>
> > - What is the performance like: (a) specifically compared to printf in the
> overlapping cases; and (b) generally not paying for what I don't use? In
> particular, if I don't use some of positional stuff which would require
> space/time overhead for multiple passes or caching, will I get performance
> roughly equivalent to printf? That would be ideal, if it's possible, and it would
> be a major selling point that should be highlighted if it's true.
>
> I made a benchmark using Boost.Format's code,
> http://students.cs.niu.edu/~z1565938/printf.html#performance_notes
>
> and it shows that my implementation is 70% slower than using iostreams
> alone, but is still 100% faster than Boost.Format.
> Considering _internally formattable_ can be formatted inside the standard
> library, the final performance can be further closer to the streams library.
>
> It's not... fair... to be compared with printf, because:
>
> 1. I defined a very strict error handling policy, while printf may
> prints garbage, or crashes with these errors.
> 2. The streams library (shipped with g++48) is already 50% slower
> than printf. -- Function calls are expensive; even std::putf can
> be implemented inside libstdc++, the recursions can't be saved.
>
> > - Is the format string fully backward-compatible with Boost.Format? It
> sounds like it is but I wasn't sure from the description.
>
> Syntactically, 100% compatible with its legacy syntax, since Boost.Format uses
> a subset of POSIX printf, while ours is 99.99% close to POSIX (only, without
> %n). For instance, Boost.Format does not support %*d (parametrized
> width).
> http://students.cs.niu.edu/~z1565938/printf.html#syntax
>
> And the formatting features of std::putf are also 99.99% compatible with
> POSIX printf, when the argument is _internally formattable_.
> If it's not, the supported feature set is even smaller than Boost.Format, since
> I don't want to pay for any possible extra copying. These are shown in the
> examples in the proposal:
> http://students.cs.niu.edu/~z1565938/printf.html#extensibility
>
>
> I uploaded the release-candidate version of my proposal to
>
> http://students.cs.niu.edu/~z1565938/printf.html
>
> Now the table of contents work :)
>
> > P.S.: This is a perfect example of what it takes to get a proposal into the
> standard. It's not enough to say "the standard should allow X, why don't they
> just add that?" Someone has to do the work of generating a well-specified
> proposal and the legwork of successive refinement based on feedback.
> Thanks for contributing this time and effort!
>
> Thanks so much for your encouragements and suggestions.
>
> String truncation on basic_string is removed by the way. And the benefit is
> that the proposal now works with Beman's "String Interoperation Library"
> out of box.
>
>
> --
> Zhihao Yuan, ID lichray
> The best way to predict the future is to invent it.
> ___________________________________________________
> 4BSD -- http://4bsd.
>
> --
>
>
>
>
--
.
Author: "Hartmut Kaiser" <hkaiser@boost.org>
Date: Wed, 26 Dec 2012 11:26:42 -0600
Raw View
> I made a benchmark using Boost.Format's code,
> http://students.cs.niu.edu/~z1565938/printf.html#performance_notes
>
> and it shows that my implementation is 70% slower than using
> iostreams alone, but is still 100% faster than Boost.Format.
> I thought iostreams was slow already.
> Performance is important, but I think it's more important to get the
> interface right as it's far easier to change the implementation than to
> change the interface.
Not quite a printf compatible way of doing output, but it terms of speed
Boost.Spirit.Karma[1] is unsurpassed[2].
Moreover, it has been shown that it's fairly easy to use Boost.Spirit (Qi
and Karma) as the backend for a printf like subset of formatting[3].
It shares the most important features with this proposal:
a) flexible and typesafe formatting
b) separation of format and data
Regards Hartmut
---------------
http://boost-spirit.com
http://stellar.cct.lsu.edu
[1]
http://www.boost.org/doc/libs/1_52_0/libs/spirit/doc/html/spirit/karma.html
[2]
http://www.boost.org/doc/libs/1_52_0/libs/spirit/doc/html/spirit/karma/perfo
rmance_measurements/numeric_performance.html
[3]
http://www.boost.org/doc/libs/1_52_0/libs/spirit/example/karma/printf_style_
double_format.cpp
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Wed, 26 Dec 2012 11:53:01 -0600
Raw View
On Wed, Dec 26, 2012 at 6:52 AM, Olaf van der Spek <olafvdspek@gmail.com> wrote:
> Performance is important, but I think it's more important to get the
> interface right as it's far easier to change the implementation than to
> change the interface.
Yea, and that's why my proposal do not support the formatting features
other than the ones provided by iostreams if a user-defined (outside
<ostream>) << is needed.
> I don't see a sprintf variant in the proposal, shouldn't there be one?
Ah, totally forgot. I added std::sputf's synopsis, but forgot to say
a word. Let me add something...
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Wed, 26 Dec 2012 13:45:47 -0600
Raw View
On Wed, Dec 26, 2012 at 11:26 AM, Hartmut Kaiser <hkaiser@boost.org> wrote:
> Moreover, it has been shown that it's fairly easy to use Boost.Spirit (Qi
> and Karma) as the backend for a printf like subset of formatting[3].
It's possible. And I also know some fast itoa/dtoa, like
https://code.google.com/p/stringencoders/
and
https://code.google.com/p/double-conversion/
A (std) library implementer may want to learn more about these.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Wed, 26 Dec 2012 15:44:40 -0600
Raw View
To anyone who helped me here:
The proposal has been sent to lwgchair@. The final draft is
available at:
http://students.cs.niu.edu/~z1565938/printf.html
Thank you so much.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: stackmachine@hotmail.com
Date: Wed, 26 Dec 2012 15:08:54 -0800 (PST)
Raw View
------=_Part_959_12310654.1356563334366
Content-Type: text/plain; charset=ISO-8859-1
C++ is getting worse and worse. This proposal is part of it.
--
------=_Part_959_12310654.1356563334366
Content-Type: text/html; charset=ISO-8859-1
C++ is getting worse and worse. This proposal is part of it.<br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_959_12310654.1356563334366--
.
Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Wed, 26 Dec 2012 15:59:12 -0800 (PST)
Raw View
------=_Part_328_6657598.1356566352273
Content-Type: text/plain; charset=ISO-8859-1
Op woensdag 26 december 2012 18:53:01 UTC+1 schreef Zhihao Yuan het
volgende:
> > I don't see a sprintf variant in the proposal, shouldn't there be one?
>
> Ah, totally forgot. I added std::sputf's synopsis, but forgot to say
> a word. Let me add something...
>
What happens with errors when sputf is used?
Would passing the output string by reference make sense? Might be faster in
case of appending to it or for reusing an existing memory allocation.
What about string_ref?
Are user-defined types supported for input and output args?
--
------=_Part_328_6657598.1356566352273
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Op woensdag 26 december 2012 18:53:01 UTC+1 schreef Zhihao Yuan het volgend=
e:<br><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;">> I don't see a sprin=
tf variant in the proposal, shouldn't there be one?
<br>
<br>Ah, totally forgot. I added std::sputf's synopsis, but forgot to =
say
<br>a word. Let me add something...
<br></blockquote><div><br></div><div>What happens with errors when sputf is=
used?</div><div>Would passing the output string by reference make sense? M=
ight be faster in case of appending to it or for reusing an existing memory=
allocation.</div><div><br></div><div>What about string_ref? </div><di=
v>Are user-defined types supported for input and output args?</div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_328_6657598.1356566352273--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Wed, 26 Dec 2012 19:31:32 -0600
Raw View
On Wed, Dec 26, 2012 at 5:59 PM, Olaf van der Spek <olafvdspek@gmail.com> wrote:
> What happens with errors when sputf is used?
Sorry, I did not clearly state what kind of "formatting results".
The results should be the same as the ones you get with std::putf,
which are well-defined any kinds of errors.
> Would passing the output string by reference make sense? Might be faster in
> case of appending to it or for reusing an existing memory allocation.
I considered this possibility. Other benefits about this style
include:
1. We can return something to indicate the error.
2. Its interface is as same as std::sgetf (if there is one, sscanf's
equivalent).
However, there are something make me hesitate:
1. A usage of `string x = sputf(...);` is natural.
2. Why appending, not insertion? Why not an STL algorithm?
4. Return code? May not be a good style.
3. If we can't answer Q2, overwriting might be a choice, but does it
worth?
Hard to say. And another problem is, if the interface is not
convenient enough, people will write their own wrappers
again and again. So I choose to stay with this simple interface
for now.
We can discuss `std::sputf` here, so I can make a decision
after the proposal getting a document number (is it allowed
to modify the proposal before I send it to lwgchair@ again?).
> What about string_ref?
> Are user-defined types supported for input and output args?
Probably not. Even the members can match, char types can not.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Thu, 27 Dec 2012 01:18:18 -0600
Raw View
After a mental battle, I made a painful decision: drop std::sputf.
The problem starts with:
On Wed, Dec 26, 2012 at 7:31 PM, Zhihao Yuan <lichray@gmail.com> wrote:
> The results should be the same as the ones you get with std::putf,
> which are well-defined any kinds of errors.
A well-defined error is still an error, which can't be ignored. So
there must be someway to indicate such an error.
We can not return an empty string. The error path must be separated
from the normal path.
An optional<string>? Probably not good for an interface.
A return value of bool is also NG; the "iostreams" way is to return a
stream.
So to return a moved basic_ostringstream? Then it's exceptions and
fill char are not configurable.
So to add one more parameter, basic_ostringstream&, so that a stream
can be reused. Then we have 4 different kinds of parameters: stream,
output string, format string, and many formatees. --Dead End
Why? Because the design of the streams library is orthogonal, and
std::sputf can't be a minimal functional component of any kind to the
library.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Felipe Magno de Almeida <felipe.m.almeida@gmail.com>
Date: Thu, 27 Dec 2012 10:31:28 -0200
Raw View
On Thu, Dec 27, 2012 at 5:18 AM, Zhihao Yuan <lichray@gmail.com> wrote:
> After a mental battle, I made a painful decision: drop std::sputf.
>
> The problem starts with:
>
> On Wed, Dec 26, 2012 at 7:31 PM, Zhihao Yuan <lichray@gmail.com> wrote:
>> The results should be the same as the ones you get with std::putf,
>> which are well-defined any kinds of errors.
>
> A well-defined error is still an error, which can't be ignored. So
> there must be someway to indicate such an error.
>
> We can not return an empty string. The error path must be separated
> from the normal path.
>
> An optional<string>? Probably not good for an interface.
Why not return a bool, and have a OutputIterator argument?
[snip]
> --
> Zhihao Yuan, ID lichray
> The best way to predict the future is to invent it.
Regards,
--
Felipe Magno de Almeida
--
.
Author: Korcan Hussein <korcan.hussein@googlemail.com>
Date: Thu, 27 Dec 2012 06:34:05 -0800 (PST)
Raw View
------=_Part_33_2459811.1356618845501
Content-Type: text/plain; charset=ISO-8859-1
I'm not a fan of these proposed libraries for format strings for C++
iostreams, why can't we do something similar to OCaml/F#.
Can't we instead do something like this. Overload printf family functions
with versions which take std::basic_i/o/iostream and are variadic
templates, have a special format string type which uses generalized
constant expressions to expand out positional arguments and maybe use
user-defined literals. Use static assertions to give compile errors about
mismatching number of arguments.
On Thursday, December 27, 2012 7:18:18 AM UTC, Zhihao Yuan wrote:
>
> After a mental battle, I made a painful decision: drop std::sputf.
>
> The problem starts with:
>
> On Wed, Dec 26, 2012 at 7:31 PM, Zhihao Yuan <lic...@gmail.com<javascript:>>
> wrote:
> > The results should be the same as the ones you get with std::putf,
> > which are well-defined any kinds of errors.
>
> A well-defined error is still an error, which can't be ignored. So
> there must be someway to indicate such an error.
>
> We can not return an empty string. The error path must be separated
> from the normal path.
>
> An optional<string>? Probably not good for an interface.
>
> A return value of bool is also NG; the "iostreams" way is to return a
> stream.
>
> So to return a moved basic_ostringstream? Then it's exceptions and
> fill char are not configurable.
>
> So to add one more parameter, basic_ostringstream&, so that a stream
> can be reused. Then we have 4 different kinds of parameters: stream,
> output string, format string, and many formatees. --Dead End
>
> Why? Because the design of the streams library is orthogonal, and
> std::sputf can't be a minimal functional component of any kind to the
> library.
>
>
> --
> Zhihao Yuan, ID lichray
> The best way to predict the future is to invent it.
> ___________________________________________________
> 4BSD -- http://4bsd.biz/
>
--
------=_Part_33_2459811.1356618845501
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
I'm not a fan of these proposed libraries for format strings for C++ iostre=
ams, why can't we do something similar to OCaml/F#.<br><br>Can't we instead=
do something like this. Overload printf family functions with versions whi=
ch take std::basic_i/o/iostream and are variadic templates, have a special =
format string type which uses generalized constant expressions to expand ou=
t positional arguments and maybe use user-defined literals. Use static asse=
rtions to give compile errors about mismatching number of arguments.<br><br=
>On Thursday, December 27, 2012 7:18:18 AM UTC, Zhihao Yuan wrote:<blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
1px #ccc solid;padding-left: 1ex;">After a mental battle, I made a painful=
decision: drop std::sputf.
<br>
<br>The problem starts with:
<br>
<br>On Wed, Dec 26, 2012 at 7:31 PM, Zhihao Yuan <<a href=3D"javascript:=
" target=3D"_blank" gdf-obfuscated-mailto=3D"zcSqUQWzI0EJ">lic...@gmail.com=
</a>> wrote:
<br>> The results should be the same as the ones you get with std::putf,
<br>> which are well-defined any kinds of errors.
<br>
<br>A well-defined error is still an error, which can't be ignored. S=
o
<br>there must be someway to indicate such an error.
<br>
<br>We can not return an empty string. The error path must be separat=
ed
<br>from the normal path.
<br>
<br>An optional<string>? Probably not good for an interface.
<br>
<br>A return value of bool is also NG; the "iostreams" way is to return a
<br>stream.
<br>
<br>So to return a moved basic_ostringstream? Then it's exceptions an=
d
<br>fill char are not configurable.
<br>
<br>So to add one more parameter, basic_ostringstream&, so that a strea=
m
<br>can be reused. Then we have 4 different kinds of parameters: stre=
am,
<br>output string, format string, and many formatees. --Dead End
<br>
<br>Why? Because the design of the streams library is orthogonal, and
<br>std::sputf can't be a minimal functional component of any kind to the
<br>library.
<br>
<br>
<br>--
<br>Zhihao Yuan, ID lichray
<br>The best way to predict the future is to invent it.
<br>______________________________<wbr>_____________________
<br>4BSD -- <a href=3D"http://4bsd.biz/" target=3D"_blank">http://4bsd.biz/=
</a>
<br></blockquote>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_33_2459811.1356618845501--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Thu, 27 Dec 2012 12:12:24 -0600
Raw View
On Thu, Dec 27, 2012 at 8:34 AM, Korcan Hussein
<korcan.hussein@googlemail.com> wrote:
> [...] why can't we do something similar to OCaml/F#.
Sorry, not quite familiar with their formatting solutions. My searches
of "ocaml/c# format output" give me their printf modules...
> [...] Use static assertions to give compile errors about mismatching
> number of arguments.
It's not hard to implement one, but the problem is that the checking
can't appears inside a runtime function (unless your function is a
macro), but obviously a macro can't appear under std.
Let's not a shame to leave the checking to the compilers, since the
proposal is free from a type-safety problem or a bad behavior with
mismatched arguments. We survive without a compile-time checking.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Thu, 27 Dec 2012 12:35:00 -0600
Raw View
On Thu, Dec 27, 2012 at 6:31 AM, Felipe Magno de Almeida
<felipe.m.almeida@gmail.com> wrote:
> Why not return a bool, and have a OutputIterator argument?
Still 4 different kinds of arguments, and the OutputIterator argument
has to be created from a stream...
BTW I pushed an implementation of std::vputf, which takes a tuple,
like std::tuple, std::pair, std::array. The last one is my favorite,
since it has a container-like interface, which appears to be more
"programmable".
array<int, 3> args { 0, 1, 2 };
args[0] = 4;
cout << vputf("%2$.*1$d %2$.*1$d\n", args);
Prints:
0001 0002
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
.
Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Fri, 28 Dec 2012 03:22:08 -0800 (PST)
Raw View
------=_Part_58_9656824.1356693728902
Content-Type: text/plain; charset=ISO-8859-1
Op donderdag 27 december 2012 02:31:32 UTC+1 schreef Zhihao Yuan het
volgende:
> However, there are something make me hesitate:
> 1. A usage of `string x = sputf(...);` is natural.
>
True, you should provide both variants.
> 2. Why appending, not insertion?
Insertion into the middle of the string? Less common and would require an
extra position argument.
>
> Why not an STL algorithm?
>
You mean a range argument? Might be a better idea.
> 4. Return code? May not be a good style.
>
Exceptions?
> > What about string_ref?
> > Are user-defined types supported for input and output args?
>
> Probably not. Even the members can match, char types can not.
>
>
String_ref should definitely be supported.
BTW, not including sputf isn't acceptable. ;)
--
------=_Part_58_9656824.1356693728902
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Op donderdag 27 december 2012 02:31:32 UTC+1 schreef Zhihao Yuan het volgen=
de:<br><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;">However, there are some=
thing make me hesitate:
<br>1. A usage of `string x =3D sputf(...);` is natural.
<br></blockquote><div><br></div><div>True, you should provide both variants=
..</div><div> </div><blockquote class=3D"gmail_quote" style=3D"margin: =
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">2. Why=
appending, not insertion? </blockquote><div><br></div><div>Insertion=
into the middle of the string? Less common and would require an extra posi=
tion argument.</div><div><br></div><div>> </div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;">Why not an STL algorithm?
<br></blockquote><div><br></div><div>You mean a range argument? Might be a =
better idea.</div><div> </div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;">4. Return code? May not be a good style.
<br></blockquote><div><br></div><div>Exceptions?</div><div> </div><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;">> What about string_ref?
<br>> Are user-defined types supported for input and output args?
<br>
<br>Probably not. Even the members can match, char types can not.
<br><br></blockquote><div><br></div><div> String_ref should definitely=
be supported.</div><div><br></div><div>BTW, not including sputf isn't acce=
ptable. ;)</div>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_58_9656824.1356693728902--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Fri, 28 Dec 2012 10:47:50 -0600
Raw View
On Fri, Dec 28, 2012 at 5:22 AM, Olaf van der Spek <olafvdspek@gmail.com> w=
rote:
>> 1. A usage of `string x =3D sputf(...);` is natural.
>
> True, you should provide both variants.
Three years ago I have the same impression against stack::pop.
>> 4. Return code? May not be a good style.
>
> Exceptions?
So configure the .exceptions() on a stringstream.
> String_ref should definitely be supported.
string_ref helps non-destructive operations, and I don't think
appending is one of them.
> BTW, not including sputf isn't acceptable. ;)
=E2=95=AE=EF=BC=88=E2=95=AF=EF=BC=BF=E2=95=B0=EF=BC=89=E2=95=AD
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--=20
.
Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Fri, 28 Dec 2012 18:30:18 +0100
Raw View
On Fri, Dec 28, 2012 at 5:47 PM, Zhihao Yuan <lichray@gmail.com> wrote:
> On Fri, Dec 28, 2012 at 5:22 AM, Olaf van der Spek <olafvdspek@gmail.com> wrote:
>>> 1. A usage of `string x = sputf(...);` is natural.
>>
>> True, you should provide both variants.
>
> Three years ago I have the same impression against stack::pop.
Impression? What do you mean?
>>> 4. Return code? May not be a good style.
>>
>> Exceptions?
>
> So configure the .exceptions() on a stringstream.
What stringstream? sputf's stringstream is just an implementation detail.
>> String_ref should definitely be supported.
>
> string_ref helps non-destructive operations, and I don't think
> appending is one of them.
I meant string_ref as one of the input arguments.
--
Olaf
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Fri, 28 Dec 2012 13:00:12 -0600
Raw View
On Fri, Dec 28, 2012 at 11:30 AM, Olaf van der Spek
<olafvdspek@gmail.com> wrote:
> On Fri, Dec 28, 2012 at 5:47 PM, Zhihao Yuan <lichray@gmail.com> wrote:
>> On Fri, Dec 28, 2012 at 5:22 AM, Olaf van der Spek <olafvdspek@gmail.com> wrote:
>>>> 1. A usage of `string x = sputf(...);` is natural.
>>>
>>> True, you should provide both variants.
>>
>> Three years ago I have the same impression against stack::pop.
>
> Impression? What do you mean?
A pop() returning the dropped item can not have a exception safety,
because it does too much. Similarly, std::sputf does not have to good
way to report an error, because it does too much.
> What stringstream? sputf's stringstream is just an implementation detail.
An implementation detail is something can and worth to be hide, but
error can not be hide, and other configurabilities are not worth to be
hide.
> I meant string_ref as one of the input arguments.
Oh, yea, definitely. I guess you were talking about writing to a
string_ref with std::sputf.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://
--
.
Author: Olaf van der Spek <olafvdspek@gmail.com>
Date: Fri, 28 Dec 2012 20:43:42 +0100
Raw View
On Fri, Dec 28, 2012 at 8:00 PM, Zhihao Yuan <lichray@gmail.com> wrote:
> A pop() returning the dropped item can not have a exception safety,
> because it does too much. Similarly, std::sputf does not have to good
> way to report an error, because it does too much.
I don't agree. A variant returning a string is an commonly used variant.
I'm sure there's a good way to deal with errors.
--
Olaf
--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Sat, 31 Aug 2013 02:02:39 -0400
Raw View
On Fri, Aug 30, 2013 at 9:48 PM, <fmatthew5876@gmail.com> wrote:
> Why does this have to use operator<<?
One reason is to help migrating from boost::format (although
boost::format uses '%' mine uses ', ', the position of the stream
parameter is the same).
Another reason is to reuse the intermediate object returned
from std::putf. I need to talk to more people about this.
> Why not this variant instead?
>
> template <typename... Args>
> /*something*/ std::putf(std::ostream& os, const char* fmt, Args&&... args);
In the latest revision, I included an suggestion to overload
std::printf with the signature above.
> ///Also possible, if so inclined
> template <typename... Args>
> /*something*/ std::putf(FILE* fp, const char* fmt, Args&&... args);
Afaics, not possible :)
> It seems to me that it would be rather ugly to chain putf calls with other
> operator<< calls like
> cout << "INTGER i IS " << i << " and " << std::putf("FLOAT f IS %f",f);
> The recommendation will probably be to use one or the other.
I agree. However, there are some popular logging system
rely on `cout << (your formatting object)`, and here is
where boost::format and std::putf rocks.
> With cout << putf(..), the implementation of putf is basically forced to
> allocate a buffer, format the arguments into it, and then pass it to the
> stream through some unnamed type that is putf's return value.
Not need, at least in my implementation, and that's why
std::putf is 1x faster then boost::format.
> A single function call putf also has a return value which can be used for
> error detection. The operator<< version has no such method of detecting
> errors other than using the stream methods.
It returns an stream reference, which is conditional converted
to bool, so it has.
> Take a look at D's printf, it has some nice features
> - %s works for all types and prints it in a default manner.
std::putf has similar capability, further more, it allows you
to %1%, %2% instead of %s. However, unmatched types
implies less formatting support. It's too verbose to explain
those rules here; see
http://students.cs.niu.edu/~z1565938/printf.html#formatting
> Also, can we have any kind of guarantee that putf will at least
> *theoretically* match or exceed the performance of printf? At least in terms
> of the interface of putf and the interface of iostream.
> Iostreams biggest drawback is that it is notoriously slow.
std::putf is kinda faster, and I actually have ideas to make
it even faster. But unfortunately, as you said, iostream is
slow. Personally I wish we can have a replacement...
Let's not to talk about this here :(
> template <typename... Args>
> /*something*/ std::putf(char* buf, size_t len, const char* fmt, Args&&...
> args);
Formatting only works on stream interfaces, that's a part
of iostreams' design. I'm sorry that I can't challenge it...
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: fmatthew5876@gmail.com
Date: Fri, 30 Aug 2013 18:48:36 -0700 (PDT)
Raw View
------=_Part_1061_3967484.1377913716744
Content-Type: text/plain; charset=ISO-8859-1
Why does this have to use operator<<?
Why not this variant instead?
template <typename... Args>
/*something*/ std::putf(std::ostream& os, const char* fmt, Args&&... args);
template <typename... Args>
inline /*something*/ std::putf(const char* fmt, Args&&... args) {
return std::putf(std::cout, fmt, std::forward<Args>(args)...);
}
///Also possible, if so inclined
template <typename... Args>
/*something*/ std::putf(FILE* fp, const char* fmt, Args&&... args);
//example
std::putf(cout, "%d %f", 2, 1.0f);
It seems to me that it would be rather ugly to chain putf calls with other
operator<< calls like
cout << "INTGER i IS " << i << " and " << std::putf("FLOAT f IS %f",f);
The recommendation will probably be to use one or the other.
Also, for those of us who adopt the putf syntax instead of operator<<(),
having to write cout << is extra unnecessary typing and confusing to
beginners.
putf to me seems like an alternative or replacement to the horrible (in my
opinion) syntax of chaining operator<< calls. In my perfect world,
operator<<() becomes deprecated and some form of putf/printf the new
standard, but I understand that's rather extreme at this point.
There are also some potential optimizations that are prevented by the
operator<< interface.
With cout << putf(..), the implementation of putf is basically forced to
allocate a buffer, format the arguments into it, and then pass it to the
stream through some unnamed type that is putf's return value.
With my proposed version, we have a single function call and thus the
implementation can allocate a stack buffer (say 4K or so) and first try to
format the results into that. If the format results are small enough we can
avoid a heap allocation entirely.
A single function call putf also has a return value which can be used for
error detection. The operator<< version has no such method of detecting
errors other than using the stream methods.
Take a look at D's printf, it has some nice features
- %s works for all types and prints it in a default manner. In this case
it could just do the equivalent of operator<<(ostream&, const T&); Its
redundant to have to say %d and then pass an int because the type system
can already figure that out. The %d/%f etc.. notation is only useful
however when you want to specify precision and other arguments.
- %b for binary printing.
Also, can we have any kind of guarantee that putf will at least
*theoretically* match or exceed the performance of printf? At least in
terms of the interface of putf and the interface of iostream.
Iostreams biggest drawback is that it is notoriously slow. Many people
refuse to use it all because of this. If putf is still slower than printf,
then many people will continue using the old interface.
I'd also love to have this:
template <typename... Args>
/*something*/ std::putf(char* buf, size_t len, const char* fmt, Args&&...
args);
Otherwise I'll be using putf for IO and snprintf for writing to memory
buffers which is rather silly.
Other variants are also possible, but the set of possible combinations
explodes rapidly:
template <typename... Args>
/*something*/ std::putf(std::string, const char* fmt, Args&&... args);
template <typename... Args>
/*something*/ std::putf(std::vector<char>, const char* fmt, Args&&... args);
template <size_t N, typename... Args>
/*something*/ std::putf(std::array<char, N>, const char* fmt, Args&&...
args);
On Sunday, December 23, 2012 1:53:58 AM UTC-5, Zhihao Yuan wrote:
>
> Hi,
>
> After some further research, I prepared an proposal to add
> std::experimental::putf (and sputf, no description yet).
>
> https://github.com/lichray/formatxx/blob/proposal/proposal/printf.md
>
> (The table of contents only works with maruku; not supported by GitHub
> preview).
>
> Comments and suggestions are welcome. Thanks.
>
> --
> Zhihao Yuan, ID lichray
> The best way to predict the future is to invent it.
> ___________________________________________________
> 4BSD -- http://4bsd.biz/
>
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_1061_3967484.1377913716744
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Why does this have to use operator<<?<div><br></div>=
<div>Why not this variant instead?</div><div><br></div><div>template <ty=
pename... Args></div><div>/*something*/ std::putf(std::ostream& os, =
const char* fmt, Args&&... args);</div><div><br></div><div><div>tem=
plate <typename... Args></div><div>inline /*something*/ std::putf(con=
st char* fmt, Args&&... args) {</div><div> return std::putf(s=
td::cout, fmt, std::forward<Args>(args)...);<br>}</div></div><div><br=
></div><div><br></div><div>///Also possible, if so inclined<br></div><div><=
div>template <typename... Args></div><div>/*something*/ std::putf(FIL=
E* fp, const char* fmt, Args&&... args);</div></div><div><br></div>=
<div>//example</div><div>std::putf(cout, "%d %f", 2, 1.0f);</div><div><br><=
/div><div>It seems to me that it would be rather ugly to chain putf calls w=
ith other operator<< calls like</div><div>cout << "INTGER i IS =
" << i << " and " << std::putf("FLOAT f IS %f",f); <=
/div><div>The recommendation will probably be to use one or the other.</div=
><div><br></div><div>Also, for those of us who adopt the putf syntax instea=
d of operator<<(), having to write cout << is extra unnece=
ssary typing and confusing to beginners.</div><div>putf to me seems li=
ke an alternative or replacement to the horrible (in my opinion) syntax of =
chaining operator<< calls. In my perfect world, operator<<() be=
comes deprecated and some form of putf/printf the new standard, but I under=
stand that's rather extreme at this point.</div><div><br></div><div>There a=
re also some potential optimizations that are prevented by the operator<=
< interface.</div><div>With cout << putf(..), the implementation o=
f putf is basically forced to allocate a buffer, format the arguments into =
it, and then pass it to the stream through some unnamed type that is putf's=
return value.</div><div>With my proposed version, we have a single functio=
n call and thus the implementation can allocate a stack buffer (say 4K or s=
o) and first try to format the results into that. If the format results are=
small enough we can avoid a heap allocation entirely. </div><div><br>=
</div><div>A single function call putf also has a return value which can be=
used for error detection. The operator<< version has no such method =
of detecting errors other than using the stream methods.</div><div><br></di=
v><div>Take a look at D's printf, it has some nice features</div><div> =
;- %s works for all types and prints it in a default manner. In this case i=
t could just do the equivalent of operator<<(ostream&, const T&am=
p;); Its redundant to have to say %d and then pass an int because the type =
system can already figure that out. The %d/%f etc.. notation is only useful=
however when you want to specify precision and other arguments.</div><div>=
- %b for binary printing.</div><div><br></div><div>Also, can we have =
any kind of guarantee that putf will at least *theoretically* match or exce=
ed the performance of printf? At least in terms of the interface of putf an=
d the interface of iostream. </div><div>Iostreams biggest drawback is =
that it is notoriously slow. Many people refuse to use it all because of th=
is. If putf is still slower than printf, then many people will continue usi=
ng the old interface.</div><div><br></div><div><br></div><div>I'd also love=
to have this:</div><div><div><br></div><div><div>template <typename... =
Args></div><div>/*something*/ std::putf(char* buf, size_t len, const cha=
r* fmt, Args&&... args);</div></div></div><div><br></div><div>Other=
wise I'll be using putf for IO and snprintf for writing to memory buffers w=
hich is rather silly.<br></div><div><br></div><div>Other variants are also =
possible, but the set of possible combinations explodes rapidly:</div><div>=
<div>template <typename... Args></div><div>/*something*/ std::putf(st=
d::string, const char* fmt, Args&&... args);</div></div><div><div>t=
emplate <typename... Args></div><div>/*something*/ std::putf(std::vec=
tor<char>, const char* fmt, Args&&... args);</div></div><div>=
<div>template <size_t N, typename... Args></div><div>/*something*/ st=
d::putf(std::array<char, N>, const char* fmt, Args&&... args)=
;</div></div><div><br></div><div><br></div><div><br>On Sunday, December 23,=
2012 1:53:58 AM UTC-5, Zhihao Yuan wrote:<blockquote class=3D"gmail_quote"=
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-=
left: 1ex;">Hi,
<br>
<br>After some further research, I prepared an proposal to add
<br>std::experimental::putf (and sputf, no description yet).
<br>
<br><a href=3D"https://github.com/lichray/formatxx/blob/proposal/proposal/p=
rintf.md" target=3D"_blank">https://github.com/lichray/<wbr>formatxx/blob/p=
roposal/<wbr>proposal/printf.md</a>
<br>
<br>(The table of contents only works with maruku; not supported by GitHub =
preview).
<br>
<br>Comments and suggestions are welcome. Thanks.
<br>
<br>--
<br>Zhihao Yuan, ID lichray
<br>The best way to predict the future is to invent it.
<br>______________________________<wbr>_____________________
<br>4BSD -- <a href=3D"http://4bsd.biz/" target=3D"_blank">http://4bsd.biz/=
</a>
<br></blockquote></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_1061_3967484.1377913716744--
.
Author: fmatthew5876@gmail.com
Date: Sat, 31 Aug 2013 10:01:11 -0700 (PDT)
Raw View
------=_Part_1616_12853085.1377968471311
Content-Type: text/plain; charset=ISO-8859-1
On Saturday, August 31, 2013 2:02:39 AM UTC-4, Zhihao Yuan wrote:
>
> On Fri, Aug 30, 2013 at 9:48 PM, <fmatth...@gmail.com <javascript:>>
> wrote:
> > Why does this have to use operator<<?
>
> One reason is to help migrating from boost::format (although
> boost::format uses '%' mine uses ', ', the position of the stream
> parameter is the same).
>
While this might be helpful, I don't think we necessarily have to be
constrained by boost compatibility. Breaking boost compatibility for a
better interface which will be in the standard forever is a worthwhile
trade off. Those who like boost or don't want to change their code can
continue to use boost.
>
> Another reason is to reuse the intermediate object returned
> from std::putf. I need to talk to more people about this.
>
Not sure exactly what you mean here? How would the returned object be used?
Do you have a use case?
>
> > Why not this variant instead?
> >
> > template <typename... Args>
> > /*something*/ std::putf(std::ostream& os, const char* fmt, Args&&...
> args);
>
> In the latest revision, I included an suggestion to overload
> std::printf with the signature above.
>
Will this new ostream printf use the old printed format specifiers and
varargs or the new putf format specifiers with variadic templates? I'm not
sure its a good idea for just one overload of printf to support entirely
different semantics from the others.
This will be even more confusing for beginners when printf(stuff) and
printf(cout, stuff) have completely different semantics.
It would probably be better to use a different name.
You could even just have 2 versions of putf. One which takes an ostream as
the first argument and another which does not and returns a special value
for use with <<.
i.e.
template <typename... Args>
long putf(std::ostream& os, const char* fmt, Args&&... args);
template <typename... Args>
MagicType putf(const char* fmt, Args&&... args);
std::ostream& operator<<(std::ostream& os, const MagicType& magic);
Of course the problem here for beginners is when they ask why this program
doesn't work:
void main() {
putf("Hello World");
}
With my proposal, the above would be the default C++ hello world program.
Its really nice when selecting the stream is optional and defaults to
stdout.
Maybe you could even provide this behavior with your version of putf. The
object thats returned by putf, if its passed to operator<<() it's written
to a stream. Otherwise its destructor will make it write to stdout. Then
the << syntax becomes an optional
stream selection syntax.
putf(...) //Magic temporary object returned by putf is destroyed and
destructor writes to stdout.
cerr << putf(...) //operator<<() is called which simply changes the stream
the magic object refers to and then the magic object's destructor writes to
that stream.
I still like my idea better though.
> > ///Also possible, if so inclined
> > template <typename... Args>
> > /*something*/ std::putf(FILE* fp, const char* fmt, Args&&... args);
>
> Afaics, not possible :)
>
It would be if you use an ostringstream to do the formatting and then a
single fwrite call at the end to commit the bits to the stream. This would
probably be very slow. However for formatting of basic ints, floats,
strings, etc (stuff that printf supports), we could avoid the stringstream
entirely and have hand optimized routines that write directly into a stack
buffer of characters which could then be written to the stream using
write().
You could also have your own optimized stringstream streambuffer class
internally that contains a fixed size stack buffer (maybe 4k) and does a
heap allocation only if the size is exceeded. This is similar to the
concept of a small_vector from facebook's folly and llvm. It still wouldn't
help with the slowness involved in operator<<() and locales though.
Still, supporting FILE* doesn't seem to be very important.
> > It seems to me that it would be rather ugly to chain putf calls with
> other
> > operator<< calls like
> > cout << "INTGER i IS " << i << " and " << std::putf("FLOAT f IS %f",f);
> > The recommendation will probably be to use one or the other.
>
> I agree. However, there are some popular logging system
> rely on `cout << (your formatting object)`, and here is
> where boost::format and std::putf rocks.
>
As in they do their logging magic within operator<<() or with a new stream
class derived from ostream?
In the first case, you're right the << syntax is the only conforming way.
In the later case, the log stream object can just be passed to putf
extern MyLogClass mylogstream;
template <typename... Args>
inline /* something*/ logf(const char* fmt, Args&&... args) {
return std::putf(mylogstream, fmt, std::forward<Args>(args)...);
}
>
> > With cout << putf(..), the implementation of putf is basically forced to
> > allocate a buffer, format the arguments into it, and then pass it to the
> > stream through some unnamed type that is putf's return value.
>
> Not need, at least in my implementation, and that's why
> std::putf is 1x faster then boost::format.
>
Thats good to know.
>
> > A single function call putf also has a return value which can be used
> for
> > error detection. The operator<< version has no such method of detecting
> > errors other than using the stream methods.
>
> It returns an stream reference, which is conditional converted
> to bool, so it has.
>
It breaks if you try to follow Herb Sutter's advice about always using auto.
bool printMsg(std::ostream& os) {
//user expects this to be a bool
auto itworked = os << putf(stuff);
//Do some other stuff with os, possibly clearing the error flags
return itworked;
}
This compiles just fine and may silently fail for some inputs some of the
time.
In general I dispise conversion operators, even for smart pointers (its not
much extra typing and self documents intent to say if(ptr == nullptr)).
There's so many subtle ways like this where it can break, especially with
auto. Its these kinds of issues that keeps C++ as an experts only language.
>
> > Take a look at D's printf, it has some nice features
> > - %s works for all types and prints it in a default manner.
>
> std::putf has similar capability, further more, it allows you
> to %1%, %2% instead of %s. However, unmatched types
> implies less formatting support. It's too verbose to explain
> those rules here; see
> http://students.cs.niu.edu/~z1565938/printf.html#formatting
>
> > Also, can we have any kind of guarantee that putf will at least
> > *theoretically* match or exceed the performance of printf? At least in
> terms
> > of the interface of putf and the interface of iostream.
> > Iostreams biggest drawback is that it is notoriously slow.
>
> std::putf is kinda faster, and I actually have ideas to make
> it even faster. But unfortunately, as you said, iostream is
> slow. Personally I wish we can have a replacement...
> Let's not to talk about this here :(
>
As hinted at above in the FILE* discussion, unless you're printing user
defined types with overloaded operator<<(), you can completely avoid the
iostream slowness with hand optimized and inlined integer to string types
of routines. The only iostream method required would be a final call to
ostream::write() (one would at least hope this is comparable to fwrite()).
string_ref and string can also be optimized in this way.
Here is one article from facebook about writing a fast integer to string
routine.
https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
> > template <typename... Args>
> > /*something*/ std::putf(char* buf, size_t len, const char* fmt,
> Args&&...
> > args);
>
> Formatting only works on stream interfaces, that's a part
> of iostreams' design. I'm sorry that I can't challenge it...
>
See above with the comment on FILE* with using a stringstream, the same
could be done here.
>
> --
> Zhihao Yuan, ID lichray
> The best way to predict the future is to invent it.
> ___________________________________________________
> 4BSD -- http://4bsd.biz/
>
One other advantage to printf style vs << is the possibility og thread
safety. Each << is a separate function call and therefore you have no way
to prevent interleaved output without explicitly locking the stream with an
external mutex.
With a single function call like printf/putf, you can easily ensure the
stream is written to atomically.
You just have to do all of the formatting into a temporary buffer
(stringstream), and then commit the results to the underlying stream using
a single atomic call to write(). If the stream's write is guaranteed to be
atomic, putf becomes atomic for free.
Have you considered whether its worthwhile to provide any thread safety
guarantees for putf or maybe another version like tputf? Maybe this should
be left to the user?
One question I would have with putf is code size. With variadic templates,
the ammount of code that can be generated could be enormous, even for
simple combinations of ints and floats. With the old varargs printf, there
is only one printf implementation for all possible inputs.
I'm a printf C++ programmer and hate iostreams with a passion. Thanks for
your hard work here, really excited about this proposal!
I really hope I can retire printf when this becomes available. However the
performance is still a major concern. If putf is 3 times slower than
printf, then there is still a good reason to use the old printf.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_1616_12853085.1377968471311
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Saturday, August 31, 2013 2:02:39 AM UTC-4, Zhi=
hao Yuan wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On Fri, Aug 30,=
2013 at 9:48 PM, <<a href=3D"javascript:" target=3D"_blank" gdf-o=
bfuscated-mailto=3D"6-1vrVs9EycJ">fmatth...@gmail.com</a>> wrote:
<br>> Why does this have to use operator<<?
<br>
<br>One reason is to help migrating from boost::format (although
<br>boost::format uses '%' mine uses ', ', the position of the stream
<br>parameter is the same).
<br></blockquote><div><br></div><div>While this might be helpful, I don't t=
hink we necessarily have to be constrained by boost compatibility=
.. Breaking boost compatibility for a better interface which will be in the =
standard forever is a worthwhile trade off. Those who like boost or don't w=
ant to change their code can continue to use boost.</div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;">
<br>Another reason is to reuse the intermediate object returned
<br>from std::putf. I need to talk to more people about this.
<br></blockquote><div><br></div><div>Not sure exactly what you mean here? H=
ow would the returned object be used? Do you have a use case?</div><div>&nb=
sp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>> Why not this variant instead?
<br>>
<br>> template <typename... Args>
<br>> /*something*/ std::putf(std::ostream& os, const char* fmt, Arg=
s&&... args);
<br>
<br>In the latest revision, I included an suggestion to overload
<br>std::printf with the signature above.
<br></blockquote><div><br></div><div>Will this new ostream printf use the o=
ld printed format specifiers and varargs or the new putf format specifiers =
with variadic templates? I'm not sure its a good idea for just one overload=
of printf to support entirely different semantics from the others.</div><d=
iv><br></div><div>This will be even more confusing for beginners when print=
f(stuff) and printf(cout, stuff) have completely different semantics.</div>=
<div><br></div><div>It would probably be better to use a different name.&nb=
sp;</div><div><br></div><div>You could even just have 2 versions of putf. O=
ne which takes an ostream as the first argument and another which does not =
and returns a special value for use with <<.</div><div>i.e.</div><div=
><br></div><div>template <typename... Args></div><div>long putf(std::=
ostream& os, const char* fmt, Args&&... args);</div><div><br></=
div><div>template <typename... Args><br>MagicType putf(const char* fm=
t, Args&&... args);</div><div><br></div><div>std::ostream& oper=
ator<<(std::ostream& os, const MagicType& magic);</div><div><=
br></div><div>Of course the problem here for beginners is when they ask why=
this program doesn't work:</div><div><br></div><div>void main() {<br> =
; putf("Hello World");</div><div>}</div><div><br></div><div>With my proposa=
l, the above would be the default C++ hello world program. Its really nice =
when selecting the stream is optional and defaults to stdout.</div><div><br=
></div><div>Maybe you could even provide this behavior with your version of=
putf. The object thats returned by putf, if its passed to operator<<=
() it's written to a stream. Otherwise its destructor will make it write to=
stdout. Then the << syntax becomes an optional</div><div>stream sele=
ction syntax.</div><div><br></div><div>putf(...) //Magic temporary object r=
eturned by putf is destroyed and destructor writes to stdout.</div><div>cer=
r << putf(...) //operator<<() is called which simply changes th=
e stream the magic object refers to and then the magic object's destructor =
writes to that stream.</div><div><br></div><div>I still like my idea better=
though.</div><div><br></div><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>> ///Also possible, if so inclined
<br>> template <typename... Args>
<br>> /*something*/ std::putf(FILE* fp, const char* fmt, Args&&.=
... args);
<br>
<br>Afaics, not possible :)
<br></blockquote><div><br></div><div>It would be if you use an ostringstrea=
m to do the formatting and then a single fwrite call at the end to commit t=
he bits to the stream. This would probably be very slow. However for format=
ting of basic ints, floats, strings, etc (stuff that printf supports), we c=
ould avoid the stringstream entirely and have hand optimized routines that =
write directly into a stack buffer of characters which could then be writte=
n to the stream using write().</div><div><br></div><div>You could also have=
your own optimized stringstream streambuffer class internally that contain=
s a fixed size stack buffer (maybe 4k) and does a heap allocation only if t=
he size is exceeded. This is similar to the concept of a small_vector from =
facebook's folly and llvm. It still wouldn't help with the slowness involve=
d in operator<<() and locales though.</div><div><br></div><div>Still,=
supporting FILE* doesn't seem to be very important.</div><div><br></div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;">
<br>> It seems to me that it would be rather ugly to chain putf calls wi=
th other
<br>> operator<< calls like
<br>> cout << "INTGER i IS " << i << " and " << =
std::putf("FLOAT f IS %f",f);
<br>> The recommendation will probably be to use one or the other.
<br>
<br>I agree. However, there are some popular logging system
<br>rely on `cout << (your formatting object)`, and here is
<br>where boost::format and std::putf rocks.
<br></blockquote><div><br></div><div>As in they do their logging magic with=
in operator<<() or with a new stream class derived from ostream?</div=
><div><br></div><div>In the first case, you're right the << syntax is=
the only conforming way. In the later case, the log stream object can just=
be passed to putf </div><div><br></div><div>extern MyLogClass mylogst=
ream;</div><div><br></div><div>template <typename... Args></div><div>=
inline /* something*/ logf(const char* fmt, Args&&... args) {</div>=
<div> return std::putf(mylogstream, fmt, std::forward<Args&g=
t;(args)...);<br>} </div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>> With cout << putf(..), the implementation of putf is basical=
ly forced to
<br>> allocate a buffer, format the arguments into it, and then pass it =
to the
<br>> stream through some unnamed type that is putf's return value.
<br>
<br>Not need, at least in my implementation, and that's why
<br>std::putf is 1x faster then boost::format.
<br></blockquote><div><br></div><div>Thats good to know. </div><blockq=
uote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-lef=
t: 1px #ccc solid;padding-left: 1ex;">
<br>> A single function call putf also has a return value which can be u=
sed for
<br>> error detection. The operator<< version has no such method o=
f detecting
<br>> errors other than using the stream methods.
<br>
<br>It returns an stream reference, which is conditional converted
<br>to bool, so it has.
<br></blockquote><div><br></div><div>It breaks if you try to follow Herb Su=
tter's advice about always using auto.</div><div><br></div><div>bool printM=
sg(std::ostream& os) {</div><div> //user expects this to be a boo=
l </div><div> auto itworked =3D os << putf(stuff);</div><=
div> //Do some other stuff with os, possibly clearing the error flags=
</div><div> return itworked;</div><div>}</div><div><br></div><div>Thi=
s compiles just fine and may silently fail for some inputs some of the time=
..</div><div>In general I dispise conversion operators, even for smart point=
ers (its not much extra typing and self documents intent to say if(ptr =3D=
=3D nullptr)). There's so many subtle ways like this where it can break, es=
pecially with auto. Its these kinds of issues that keeps C++ as an experts =
only language.</div><div> <br></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;">
<br>> Take a look at D's printf, it has some nice features
<br>> - %s works for all types and prints it in a default manner.
<br>
<br>std::putf has similar capability, further more, it allows you
<br>to %1%, %2% instead of %s. However, unmatched types
<br>implies less formatting support. It's too verbose to explain
<br>those rules here; see
<br><a href=3D"http://students.cs.niu.edu/~z1565938/printf.html#formatting"=
target=3D"_blank">http://students.cs.niu.edu/~<wbr>z1565938/printf.html#<w=
br>formatting</a>
<br>
<br>> Also, can we have any kind of guarantee that putf will at least
<br>> *theoretically* match or exceed the performance of printf? At leas=
t in terms
<br>> of the interface of putf and the interface of iostream.
<br>> Iostreams biggest drawback is that it is notoriously slow.
<br>
<br>std::putf is kinda faster, and I actually have ideas to make
<br>it even faster. But unfortunately, as you said, iostream is
<br>slow. Personally I wish we can have a replacement...
<br>Let's not to talk about this here :(
<br></blockquote><div><br></div><div>As hinted at above in the FILE* discus=
sion, unless you're printing user defined types with overloaded operator<=
;<(), you can completely avoid the iostream slowness with hand optimized=
and inlined integer to string types of routines. The only iostream method =
required would be a final call to ostream::write() (one would at least hope=
this is comparable to fwrite()). string_ref and string can also =
be optimized in this way.</div><div><br></div><div>Here is one article from=
facebook about writing a fast integer to string routine. <a href=3D"h=
ttps://www.facebook.com/notes/facebook-engineering/three-optimization-tips-=
for-c/10151361643253920">https://www.facebook.com/notes/facebook-engineerin=
g/three-optimization-tips-for-c/10151361643253920</a></div><div><br></div><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;">
<br>> template <typename... Args>
<br>> /*something*/ std::putf(char* buf, size_t len, const char* fmt, Ar=
gs&&...
<br>> args);
<br>
<br>Formatting only works on stream interfaces, that's a part
<br>of iostreams' design. I'm sorry that I can't challenge it...
<br></blockquote><div><br></div><div>See above with the comment on FILE* wi=
th using a stringstream, the same could be done here. </div><blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;">
<br>--=20
<br>Zhihao Yuan, ID lichray
<br>The best way to predict the future is to invent it.
<br>______________________________<wbr>_____________________
<br>4BSD -- <a href=3D"http://4bsd.biz/" target=3D"_blank">http://4bsd.biz/=
</a>
<br></blockquote><div><br></div><div>One other advantage to printf style vs=
<< is the possibility og thread safety. Each << is a separate =
function call and therefore you have no way to prevent interleaved output w=
ithout explicitly locking the stream with an external mutex.</div><div><br>=
</div><div>With a single function call like printf/putf, you can easily ens=
ure the stream is written to atomically.</div><div>You just have to do all =
of the formatting into a temporary buffer (stringstream), and then commit t=
he results to the underlying stream using a single atomic call to write(). =
If the stream's write is guaranteed to be atomic, putf becomes atomic for f=
ree.</div><div><br></div><div>Have you considered whether its worthwhile to=
provide any thread safety guarantees for putf or maybe another version lik=
e tputf? Maybe this should be left to the user?</div><div><br></div><div>On=
e question I would have with putf is code size. With variadic templates, th=
e ammount of code that can be generated could be enormous, even for simple =
combinations of ints and floats. With the old varargs printf, there is only=
one printf implementation for all possible inputs.</div><div><br></div><di=
v><br></div><div>I'm a printf C++ programmer and hate iostreams with a pass=
ion. Thanks for your hard work here, really excited about this proposal!</d=
iv><div><br></div><div>I really hope I can retire printf when this becomes =
available. However the performance is still a major concern. If putf is 3 t=
imes slower than printf, then there is still a good reason to use the old p=
rintf.</div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_1616_12853085.1377968471311--
.
Author: Zhihao Yuan <lichray@gmail.com>
Date: Sat, 31 Aug 2013 14:41:24 -0400
Raw View
On Sat, Aug 31, 2013 at 1:01 PM, <fmatthew5876@gmail.com> wrote:
>> Another reason is to reuse the intermediate object returned
>> from std::putf. I need to talk to more people about this.
>
> Not sure exactly what you mean here? How would the returned object be used?
> Do you have a use case?
auto fmt = std::putf("...", obj1, obj2);
for (...) {
// modify obj1, obj2
cout << fmt; // not sure whether this is helpful
}
> This will be even more confusing for beginners when printf(stuff) and
> printf(cout, stuff) have completely different semantics.
I don't think this is something hard to teach... No matter where
your students come from.
And I almost never include stdio.h or cstdio in a C++ program :(
> template <typename... Args>
> long putf(std::ostream& os, const char* fmt, Args&&... args);
>
> template <typename... Args>
> MagicType putf(const char* fmt, Args&&... args);
This is No-Go :)
> With my proposal, the above would be the default C++ hello world program.
> Its really nice when selecting the stream is optional and defaults to
> stdout.
getline does not defaults to `cin`, so output function can not
defaults to cout.
> template <typename... Args>
> inline /* something*/ logf(const char* fmt, Args&&... args) {
> return std::putf(mylogstream, fmt, std::forward<Args>(args)...);
> }
Neither boost::format nor std::putf accepts customize stream
out-of-box. But I got your point. Maybe I should expect a straw poll
on this topic in Chicago.
> It breaks if you try to follow Herb Sutter's advice about always using auto.
Obviously `auto` does not work with any non-value semantics
object; auto&& does.
> bool printMsg(std::ostream& os) {
> //user expects this to be a bool
> auto itworked = os << putf(stuff);
That's "conditionally converted to bool"'s problem :)
And no stream output function work like that.
> //Do some other stuff with os, possibly clearing the error flags
> return itworked;
> }
>
> This compiles just fine and may silently fail for some inputs some of the
> time.
Don't worry it does not. Firstly iostream is not copyable,
secondly even with auto&&, iostream is not implicitly convertable
to bool.
> As hinted at above in the FILE* discussion, unless you're printing user
> defined types with overloaded operator<<(), you can completely avoid the
> iostream slowness with hand optimized and inlined integer to string types of
> routines.
Yes, I placed "as-if" rule to *not* to require operator<< to be used
when the object is internally formattable, so it's possible to
implement in that way. Need to be careful about locales anyway.
> One other advantage to printf style vs << is the possibility og thread
> safety. Each << is a separate function call and therefore you have no way to
> prevent interleaved output without explicitly locking the stream with an
> external mutex.
There are some proposals to address this:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3535.html
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3665.html
> One question I would have with putf is code size.
It's a very valid concern but I don't have an answer for this :'(
> I'm a printf C++ programmer and hate iostreams with a passion. Thanks for
> your hard work here, really excited about this proposal!
Thank you.
> If putf is 3 times slower than printf,
> then there is still a good reason to use the old printf.
Yea. But after I digged into printf, I found that printf is really,
really hard to be used correctly. Maybe we need a study
group to find out how to drop iostreams :)
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.