Maybe my question is stupid, but
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
Il 16/09/2021 15:40, Paavo Helde ha scritto:
16.09.2021 15:59 alessandro volturno kirjutas:
Maybe my question is stupid, but
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
I speak as a non-competent, hobbyist programmer and computer-user.
What are the use cases for rationals? If something is not in the
standard, then often there are different use cases which cannot be
easily covered by a common "standard" implementation.
Computers were born to manipulate numbers and the languages for doing
that, at that time, were mainly two: FORTRAN, and LISP. I have noticed
that C++ (that I presume it could be thought of as a descendant of
FORTRAN, is shifting towards Functional programming language facilities,
like that offered by the LISP family. That's good, but numerical
programming is still important nowadays.
16.09.2021 15:59 alessandro volturno kirjutas:
Maybe my question is stupid, but
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
What are the use cases for rationals? If something is not in the
standard, then often there are different use cases which cannot be
easily covered by a common "standard" implementation.
For rationals it feels like a fast implementation would have a pretty
limited numeric range, and unlimited range would require arbitrary
precision integers and would probably be many times slower even in case
of small numbers.
Nevertheless, there is at least one proposal to include rationals in the standard, see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3363.html
Meanwhile one can use the Boost Rational library.
alessandro volturno <alessandro.volturno@libero.it> writes:
Il 16/09/2021 15:40, Paavo Helde ha scritto:
16.09.2021 15:59 alessandro volturno kirjutas:
Maybe my question is stupid, but
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
I speak as a non-competent, hobbyist programmer and computer-user.
What are the use cases for rationals? If something is not in the
standard, then often there are different use cases which cannot be
easily covered by a common "standard" implementation.
Computers were born to manipulate numbers and the languages for doing
that, at that time, were mainly two: FORTRAN, and LISP. I have noticed
that C++ (that I presume it could be thought of as a descendant of
FORTRAN, is shifting towards Functional programming language facilities,
like that offered by the LISP family. That's good, but numerical
programming is still important nowadays.
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code
for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
https://en.wikipedia.org/wiki/List_of_numerical_libraries
Il 16/09/2021 15:40, Paavo Helde ha scritto:
For rationals it feels like a fast implementation would have a pretty
limited numeric range, and unlimited range would require arbitrary
precision integers and would probably be many times slower even in
case of small numbers.
Mine uses long long int, that is the maximum offered by the language,
but calculation speed is constantly increasing. I don't see that a as a limiting factor.
True that C++ applications can be built for every available hardware configuration (and so they can be run on older or slower cpus), but
rational are an important class of numbers and its family is wider than integers'
Il 16/09/2021 15:40, Paavo Helde ha scritto:
16.09.2021 15:59 alessandro volturno kirjutas:
Maybe my question is stupid, but
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
I speak as a non-competent, hobbyist programmer and computer-user.
What are the use cases for rationals? If something is not in the
standard, then often there are different use cases which cannot be
easily covered by a common "standard" implementation.
Computers were born to manipulate numbers and the languages for doing
that, at that time, were mainly two: FORTRAN, and LISP. I have noticed
that C++ (that I presume it could be thought of as a descendant of
FORTRAN, is shifting towards Functional programming language facilities,
like that offered by the LISP family. That's good, but numerical
programming is still important nowadays.
For rationals it feels like a fast implementation would have a pretty
limited numeric range, and unlimited range would require arbitrary
precision integers and would probably be many times slower even in
case of small numbers.
Mine uses long long int, that is the maximum offered by the language,
but calculation speed is constantly increasing. I don't see that a as a limiting factor.
Thank you for your kind reply,
On 16/09/2021 18:24, alessandro volturno wrote:
Il 16/09/2021 15:40, Paavo Helde ha scritto:
For rationals it feels like a fast implementation would have a pretty
limited numeric range, and unlimited range would require arbitrary
precision integers and would probably be many times slower even in
case of small numbers.
Mine uses long long int, that is the maximum offered by the language,
but calculation speed is constantly increasing. I don't see that a as a
limiting factor.
True that C++ applications can be built for every available hardware
configuration (and so they can be run on older or slower cpus), but
rational are an important class of numbers and its family is wider than
integers'
There are two key difficulties about constructive use of rationals. One
is that you have to handle reduction by greatest common denominator -
that is not a simple operation, but is time-consuming and has
unpredictable timing. The other is that the sizes of the denominator
and numerator very quickly get very big for all but the simplest of calculations - you don't have to do a lot with them before the
arithmetic becomes impossible within the fixed size framework. (This is
in comparison to complex numbers, which are easy.)
Basically, I don't think there is that much need of rationals of fixed
size - you can usually make do with floating point or integers, or you
need arbitrary precision. Rationals are very important in mathematics,
much less so in practical programming.
However, as a hobby task, a good set of rational number classes would be great fun to work on. You can start with a basic implementation, then
work on a templated version handling different sizes, learn about
concepts with a practical use-case, figure how to make everything
constexpr, get neat ways to make bigger fixed-size rational types,
explore ways to handle overflows. The scope for enjoyment and learning
is huge here.
You get a similar problem with arbitrary precision floats. (At least,
in my library. I don't know how others deal with it; I use upper
limits on precision).
Multiply two numbers with M and N digits of precision respectively,
and the result will have M*N digits of precision, without the
magnitude necessarily getting bigger.
Bart <bc@freeuk.com> writes:
You get a similar problem with arbitrary precision floats. (At least,
in my library. I don't know how others deal with it; I use upper
limits on precision).
Multiply two numbers with M and N digits of precision respectively,
and the result will have M*N digits of precision, without the
magnitude necessarily getting bigger.
That sounds odd. If it's binary FP, multiplying 2 by 2 need not result
in a result with more digits than the already exact operands. Do you
always widen the mantissa in a multiplication?
Bart <bc@freeuk.com> writes:
You get a similar problem with arbitrary precision floats. (At least,
in my library. I don't know how others deal with it; I use upper
limits on precision).
Multiply two numbers with M and N digits of precision respectively,
and the result will have M*N digits of precision, without the
magnitude necessarily getting bigger.
That sounds odd. If it's binary FP, multiplying 2 by 2 need not result
in a result with more digits than the already exact operands. Do you
always widen the mantissa in a multiplication?
On 16 Sep 2021 22:26, Ben Bacarisse wrote:
Bart <bc@freeuk.com> writes:
You get a similar problem with arbitrary precision floats. (At least,
in my library. I don't know how others deal with it; I use upper
limits on precision).
Multiply two numbers with M and N digits of precision respectively,
and the result will have M*N digits of precision, without the
magnitude necessarily getting bigger.
That sounds odd. If it's binary FP, multiplying 2 by 2 need not result
in a result with more digits than the already exact operands. Do you
always widen the mantissa in a multiplication?
I think Ben meant to write M + N, not M*N. :-o
Consider the product of A = a*r^n and B = b*r^m, where a and b are
integers and r is the numeral system radix.
You get a result C = A*B = a*b*r^(n+m), where the number of digits of C
is roughly (the number of digits of a) + (the number of digits of b).
printDescription() // prints a description of the number and its
// numerical value
16.09.2021 19:24 alessandro volturno kirjutas:
Il 16/09/2021 15:40, Paavo Helde ha scritto:
What are the use cases for rationals? If something is not in the
standard, then often there are different use cases which cannot be
easily covered by a common "standard" implementation.
I notice that you still haven't presented any use case for rationals. I
have to admit I also wrote a C++ class for rational numbers ca 20 years
ago, but so far I have not found any usage for it in my work (which also involves a lot of heavy numeric computations).
The only advantage what rationals offer above floating-point is that the calculation results are always exact. However, in numeric programming
the input data often comes from a physical measurement, meaning that it already contains measurement inaccuracies. Thus the end result will not
be absolutely accurate anyway, so there is no need to use absolutely
precise computations.
[...]
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves like an arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code
for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
Am 16.09.21 um 19:05 schrieb Scott Lurndal:
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code
for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
I am a scientist, and Matlab and R are popular, but slowly they give way
to Python. With the "numpy" package wrapping LAPACK and "scipy", which
is based on it, Python code almost looks like Matlab, but it's
completely open source. To my understanding, that and the machine
learning libs are the reasons why Python gained so much in the last
years. The language on its own is not that much better than other modern scripting languages, it's the libraries with a large user base.
Am 16.09.21 um 19:05 schrieb Scott Lurndal:
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code
for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
I am a scientist, and Matlab and R are popular, but slowly they give way
to Python. With the "numpy" package wrapping LAPACK and "scipy", which
is based on it, Python code almost looks like Matlab, but it's
completely open source. To my understanding, that and the machine
learning libs are the reasons why Python gained so much in the last
years. The language on its own is not that much better than other modern scripting languages, it's the libraries with a large user base.
Il 16/09/2021 22:12, Paavo Helde ha scritto:
16.09.2021 19:24 alessandro volturno kirjutas:
Il 16/09/2021 15:40, Paavo Helde ha scritto:
What are the use cases for rationals? If something is not in the
standard, then often there are different use cases which cannot be
easily covered by a common "standard" implementation.
I notice that you still haven't presented any use case for rationals.
I have to admit I also wrote a C++ class for rational numbers ca 20
years ago, but so far I have not found any usage for it in my work
(which also involves a lot of heavy numeric computations).
I am not a mathematician nor a physicist but probably solving systems of linear equations with Gauss or Gauss-Jordan methods can be an
application of rational numbers.
Many years ago trying to use the Common lisp programming language, I was impressed by its natural handling of rational numbers and by its use of integers or floating point numbers of arbitrary precision. Common Lisp
is an ANSI standard dated 1990 but it inherits properties and behaviours
from ancient LISP dialects. So it seemed to me a bit strange that a programming language as widespread as C++ doesn't offer that same
facilities.
The only advantage what rationals offer above floating-point is that
the calculation results are always exact. However, in numeric
programming the input data often comes from a physical measurement,
meaning that it already contains measurement inaccuracies. Thus the
end result will not be absolutely accurate anyway, so there is no need
to use absolutely precise computations.
there are not only physical measures, you could develop examples with
integer numbers just for didactic goals. C++ must be learned like any
other discipline. And having wide numerical facilities can be very
useful permitting to develop new strategies by tackling numerical
problems in a different way.
I'm sorry for my general argumentation and lack of practical examples,
but as I had already written, I do program just for fun.
[...]
And talking about features offered by a programming language, there is
just another addition that could help developing large applications or
bigger projects, and that is 2d and GUI facilities.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0267r10.pdf
Thank you again for the opportunity of this discussion.
alessandro
On 17/09/2021 19:21, Christian Gollwitzer wrote:
Am 16.09.21 um 19:05 schrieb Scott Lurndal:
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code
for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
I am a scientist, and Matlab and R are popular, but slowly they give way
to Python. With the "numpy" package wrapping LAPACK and "scipy", which
is based on it, Python code almost looks like Matlab, but it's
completely open source. To my understanding, that and the machine
learning libs are the reasons why Python gained so much in the last
years. The language on its own is not that much better than other modern
scripting languages, it's the libraries with a large user base.
Matlab does have one advantage (at least in our environment); it can
convert models into C++ code!
Il 17/09/2021 07:36, Juha Nieminen ha scritto:
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves like an
arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
if you read the two lines right before the one here reported you can see
I did that.
I wrote that function to give an extensive description of a rational
number in a way like this:
"4/16 reduces to 1/4 and evaluates to 0.25"
On 17/09/2021 09:21, Christian Gollwitzer wrote:
Am 16.09.21 um 19:05 schrieb Scott Lurndal:
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code
for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
I am a scientist, and Matlab and R are popular, but slowly they give way
to Python. With the "numpy" package wrapping LAPACK and "scipy", which
is based on it, Python code almost looks like Matlab, but it's
completely open source. To my understanding, that and the machine
learning libs are the reasons why Python gained so much in the last
years. The language on its own is not that much better than other modern
scripting languages, it's the libraries with a large user base.
Python might not be much better than Matlab as a language for the
numerical bits (I haven't done Matlab programming to compare), but as a general purpose language it is vastly more powerful for everything else
than highly specialised and consequently limited tools like Matlab.
All
the extra capabilities from Python, such sending emails when your calculations are done, interacting with databases, generating pdf
reports from the results, etc., are going to make it a lot more
attractive if it can handle the maths you need.
On 17/09/2021 19:21, Christian Gollwitzer wrote:
Am 16.09.21 um 19:05 schrieb Scott Lurndal:
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code
for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
I am a scientist, and Matlab and R are popular, but slowly they give way
to Python. With the "numpy" package wrapping LAPACK and "scipy", which
is based on it, Python code almost looks like Matlab, but it's
completely open source. To my understanding, that and the machine
learning libs are the reasons why Python gained so much in the last
years. The language on its own is not that much better than other modern
scripting languages, it's the libraries with a large user base.
Matlab does have one advantage (at least in our environment); it can
convert models into C++ code!
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves like an >arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
Juha Nieminen <nospam@thanks.invalid> writes:
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves like an
arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
I could rant for hours on the unsuitability of the silly
C++ output stream crap in real applications.
But I've got too much on my plate right now. Much of which
is making performance improvements to a large CPU-bound
C++ application; primarily by getting rid of all outputstringstream
crap (replacing with snprintf) and eliminating most trivial
run-time (vs. startup time) uses of std::string.
void
a(void)
{
std::string fred = "this is a test";
printf("%s", fred.c_str());
}
[...long assembly...]
Am 17.09.21 um 16:03 schrieb Scott Lurndal:
Juha Nieminen <nospam@thanks.invalid> writes:
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves
like an
arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
I could rant for hours on the unsuitability of the silly
C++ output stream crap in real applications.
But I've got too much on my plate right now. Much of which
is making performance improvements to a large CPU-bound
C++ application; primarily by getting rid of all outputstringstream
crap (replacing with snprintf) and eliminating most trivial
run-time (vs. startup time) uses of std::string.
void
a(void)
{
std::string fred = "this is a test";
printf("%s", fred.c_str());
}
[...long assembly...]
Wow, thats an awful lot of code. Does it improve if you do const
std::string or constexpr or the like?
Christian
Am 17.09.21 um 10:34 schrieb David Brown:
On 17/09/2021 09:21, Christian Gollwitzer wrote:
Am 16.09.21 um 19:05 schrieb Scott Lurndal:
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code >>>> for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
I am a scientist, and Matlab and R are popular, but slowly they give way >>> to Python. With the "numpy" package wrapping LAPACK and "scipy", which
is based on it, Python code almost looks like Matlab, but it's
completely open source. To my understanding, that and the machine
learning libs are the reasons why Python gained so much in the last
years. The language on its own is not that much better than other modern >>> scripting languages, it's the libraries with a large user base.
Python might not be much better than Matlab as a language for the
numerical bits (I haven't done Matlab programming to compare), but as a
general purpose language it is vastly more powerful for everything else
than highly specialised and consequently limited tools like Matlab.
I agree, and maybe I wasn't clearly expressing myself. Matlab has a
little edge if one does linear algebra stuff. There are some weird extra parentheses in numpy sometimes (e.g. numpy.zeros((3,4)) vs zeros(3,4) in Matlab), numpy does not distinguish row and column vectors and therefore leads to more cumbersome code for matrix multiplications, and literals
also look cleaner in Matlab. In addition, the documentation of Matlab
and the toolboxes is really high standard, commercial quality and well maintained whereas in Scipy you can often see that it is more of a
"hobbyist" thing.
But these are minor disadvantages of Python that are a bit annoying in interactive use like Jupyter notebooks and not real show-stoppers.
All
the extra capabilities from Python, such sending emails when your
calculations are done, interacting with databases, generating pdf
reports from the results, etc., are going to make it a lot more
attractive if it can handle the maths you need.
OTOH, Matlab is a terrible general purpose language. They have bolted on
to that matrix language everything, you *can* use object orientation,
general I/O, GUIs and also send emails https://www.mathworks.com/help/matlab/import_export/sending-email.html connect databases https://www.mathworks.com/help/database/ug/odbc.html
and create PDFs https://www.mathworks.com/help/rptgen/ug/create-an-html-or-pdf-template.html but it often looks quirky and not like a language I would want to write
a larger program in.
Python was constructed as a sane language to begin with, but so have
been Lua, Julia, Ruby, Kotlin, and surely dozens of others. Why Python
has become the Nr#1? I suspect that as soon as scientists picked it up
with numpy it grew as an alternative to the de-facto standard Matlab
simply because it was free. And then the machine learning guys really
boosted it to a point where it couldn't be ignored any longer.
The same happened years ago with Tcl. Python and Tcl are almost the same
age. Due to Tk, which allowed non-guru-level programmers to make simple
GUIs and the adoption of the circuit CAD industry, Tcl became the
de-facto scripting standard for many years. The decline came with the
stall of development (Sun pulled the money out) and the main focus has shifted away from desktop GUI and circuit board designers. Now it's
Python that everyone uses and recommends.
I still think that designwise such a function does not belong in that class.
Sure, nobody is stopping you from adding such functions to your class, if
and when you want to use just in your own small projects, but generally,
when designing such classes for general use for a wider audience and a
wider set of applications, that's just not something that logically
belongs to such a class.
A class that behaves like a numerical value shouldn't itself print
anything, because that doesn't make much logical sense. You could have separate functions that do that, but they don't belong as members of
the class.
On 17/09/2021 15:55, Christian Gollwitzer wrote:
Tcl is okay as a "tool control language", but it is far too weak for
more advanced work.
Am 17.09.21 um 17:12 schrieb Christian Gollwitzer:
Am 17.09.21 um 16:03 schrieb Scott Lurndal:
Juha Nieminen <nospam@thanks.invalid> writes:
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves
like an
arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
I could rant for hours on the unsuitability of the silly
C++ output stream crap in real applications.
But I've got too much on my plate right now. Much of which
is making performance improvements to a large CPU-bound
C++ application; primarily by getting rid of all outputstringstream
crap (replacing with snprintf) and eliminating most trivial
run-time (vs. startup time) uses of std::string.
void
a(void)
{
std::string fred = "this is a test";
printf("%s", fred.c_str());
}
[...long assembly...]
Wow, thats an awful lot of code. Does it improve if you do const
std::string or constexpr or the like?
Christian
Quick test on compiler explorer shows a much more reasonable code: https://godbolt.org/z/5MzscK95W
with gcc 11.
Christian
On 9/17/2021 5:16 PM, Christian Gollwitzer wrote:
Am 17.09.21 um 17:12 schrieb Christian Gollwitzer:
Am 17.09.21 um 16:03 schrieb Scott Lurndal:
Juha Nieminen <nospam@thanks.invalid> writes:
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves
like an
arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
I could rant for hours on the unsuitability of the silly
C++ output stream crap in real applications.
But I've got too much on my plate right now. Much of which
is making performance improvements to a large CPU-bound
C++ application; primarily by getting rid of all outputstringstream
crap (replacing with snprintf) and eliminating most trivial
run-time (vs. startup time) uses of std::string.
void
a(void)
{
std::string fred = "this is a test";
printf("%s", fred.c_str());
}
[...long assembly...]
Wow, thats an awful lot of code. Does it improve if you do const
std::string or constexpr or the like?
Christian
Quick test on compiler explorer shows a much more reasonable code:
https://godbolt.org/z/5MzscK95W
with gcc 11.
Christian
Still,
Feeding a C string to a std::string to be fed to printf() /is/ masochism
(or sadism, depending on which side you are on).
You will quickly get meaninglessly big numbers if you use rationals for
that kind of thing. Calculations with rationals usually only makes
sense for pure mathematics and number theory, not applied mathematics or physics.
C++ arithmetic aims for efficiency, predictability, and fixed sizes.
Fixed size rationals are of quite limited use - you can't do much
arithmetic on them before the sizes overflow.
For C++, it's a /lot/ harder to decide what to do for the standard
library, as C++ programmers have such different needs. Someone who just wants to do arithmetic up to 4K bits for cryptography will not want the
cost to support megabit sizes. Someone who needs a lot of decimal I/O
might want a base-10 model rather than a base-2 model. People with particular processors might want a model optimised for the SIMD
instructions they have, though it might be much less efficient on other processors.
C++ does not try to put /everything/ a programmer might need into its standard library - it aims to have the tools and basics there, so that
others can make libraries as needed. That's the case here.
The only advantage what rationals offer above floating-point is that
the calculation results are always exact. However, in numeric
programming the input data often comes from a physical measurement,
meaning that it already contains measurement inaccuracies.
[...] you could develop examples with
integer numbers just for didactic goals. C++ must be learned like any
other discipline. And having wide numerical facilities can be very
useful permitting to develop new strategies by tackling numerical
problems in a different way.
I agree with those aims. And a C++ standard library for rational
numbers would be completely against that aim
making good classes and abstractions using rational numbers if the
library already supported them? Make it yourself - that's how you will learn.
On 17/09/2021 12:07, Ian Collins wrote:
On 17/09/2021 19:21, Christian Gollwitzer wrote:
Am 16.09.21 um 19:05 schrieb Scott Lurndal:
I suspect that the vast majority of people use existing
software packages like Matlab or R (for statistics) than write C++ code >>>> for numerical software nowadays. It's really hard to get it
right when using binary floating point, hence standard numerical
libraries (LINPACK, et alia).
I am a scientist, and Matlab and R are popular, but slowly they give way >>> to Python. With the "numpy" package wrapping LAPACK and "scipy", which
is based on it, Python code almost looks like Matlab, but it's
completely open source. To my understanding, that and the machine
learning libs are the reasons why Python gained so much in the last
years. The language on its own is not that much better than other modern >>> scripting languages, it's the libraries with a large user base.
Matlab does have one advantage (at least in our environment); it can
convert models into C++ code!
A few times in the past, I've seen C code generated by Matlab, produced
by researchers who then wanted the whole think running in a little microcontroller. The generated code was utterly hideous - vastly over-complex, and ridiculous inefficiencies (malloc allocation for
things that should be local stack variables, multiplying integers by 0.5 instead of dividing by 2, using strings and strcmp() instead of enums,
etc.). But perhaps it was the user rather than the software that was at fault - it's not a tool I use myself. I just know that for use on a
small microcontroller, I'd rather hand-translate some well-written
Python than clear up the vomit that Matlab produced.
Juha Nieminen <nospam@thanks.invalid> writes:
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves like an
arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
I could rant for hours on the unsuitability of the silly
C++ output stream crap in real applications.
But I've got too much on my plate right now. Much of which
is making performance improvements to a large CPU-bound
C++ application; primarily by getting rid of all outputstringstream
crap (replacing with snprintf) and eliminating most trivial
run-time (vs. startup time) uses of std::string.
void
a(void)
{
std::string fred = "this is a test";
printf("%s", fred.c_str());
}
0000000000400970 <a()>:
400970: 53 push %rbx
400971: be 50 0b 40 00 mov $0x400b50,%esi
400976: 48 83 ec 20 sub $0x20,%rsp
40097a: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
40097f: 48 8d 54 24 0f lea 0xf(%rsp),%rdx
400984: e8 97 fe ff ff callq 400820 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)@plt>
400989: 48 8b 74 24 10 mov 0x10(%rsp),%rsi
40098e: bf 5f 0b 40 00 mov $0x400b5f,%edi
400993: 31 c0 xor %eax,%eax
400995: e8 36 fe ff ff callq 4007d0 <printf@plt>
40099a: 48 8b 44 24 10 mov 0x10(%rsp),%rax
40099f: 48 8d 78 e8 lea -0x18(%rax),%rdi
4009a3: 48 81 ff 80 10 60 00 cmp $0x601080,%rdi
4009aa: 75 06 jne 4009b2 <a()+0x42>
4009ac: 48 83 c4 20 add $0x20,%rsp
4009b0: 5b pop %rbx
4009b1: c3 retq
4009b2: b9 00 00 00 00 mov $0x0,%ecx
4009b7: 48 8d 57 10 lea 0x10(%rdi),%rdx
4009bb: 48 85 c9 test %rcx,%rcx
4009be: 74 35 je 4009f5 <a()+0x85>
4009c0: 83 c8 ff or $0xffffffff,%eax
4009c3: f0 0f c1 02 lock xadd %eax,(%rdx)
4009c7: 85 c0 test %eax,%eax
4009c9: 7f e1 jg 4009ac <a()+0x3c>
4009cb: 48 8d 74 24 0f lea 0xf(%rsp),%rsi
4009d0: e8 3b fe ff ff callq 400810 <std::string::_Rep::_M_destroy(std::allocator<char> const&)@plt>
4009d5: eb d5 jmp 4009ac <a()+0x3c>
4009d7: 48 89 c3 mov %rax,%rbx
4009da: 48 8b 44 24 10 mov 0x10(%rsp),%rax
4009df: 48 8d 74 24 0f lea 0xf(%rsp),%rsi
4009e4: 48 8d 78 e8 lea -0x18(%rax),%rdi
4009e8: e8 03 fe ff ff callq 4007f0 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
4009ed: 48 89 df mov %rbx,%rdi
4009f0: e8 5b fe ff ff callq 400850 <_Unwind_Resume@plt>
4009f5: 8b 50 f8 mov -0x8(%rax),%edx
4009f8: 8d 4a ff lea -0x1(%rdx),%ecx
4009fb: 89 48 f8 mov %ecx,-0x8(%rax)
4009fe: 89 d0 mov %edx,%eax
400a00: eb c5 jmp 4009c7 <a()+0x57>
400a02: 66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
400a09: 1f 84 00 00 00 00 00
(and that's _with_ -O3).
Il 17/09/2021 11:15, David Brown ha scritto:...
The only advantage what rationals offer above floating-point is that
the calculation results are always exact. However, in numeric
programming the input data often comes from a physical measurement,
meaning that it already contains measurement inaccuracies.
Physics is not the only Science out there
Il 17/09/2021 11:15, David Brown ha scritto:
C++ arithmetic aims for efficiency, predictability, and fixed sizes.
Fixed size rationals are of quite limited use - you can't do much
arithmetic on them before the sizes overflow.
This is my personal opinion: C's and C++'s search for efficiency is
probably one of the cause that made other computer scientists develop
newer or more complete and easy to use computer languages.
The only advantage what rationals offer above floating-point is that
the calculation results are always exact. However, in numeric
programming the input data often comes from a physical measurement,
meaning that it already contains measurement inaccuracies.
Physics is not the only Science out there
On 17/09/2021 19:19, alessandro volturno wrote:
Il 17/09/2021 11:15, David Brown ha scritto:
C++ arithmetic aims for efficiency, predictability, and fixed sizes.
Fixed size rationals are of quite limited use - you can't do much
arithmetic on them before the sizes overflow.
This is my personal opinion: C's and C++'s search for efficiency is
probably one of the cause that made other computer scientists develop
newer or more complete and easy to use computer languages.
Yes - and that's a good thing. There are all kinds of programming
tasks, and all kinds of programmers - there needs to be a variety of programming languages. C++ should not become Python or Lisp any more
than Python should become Lua or Lisp should become Fortran.
The only advantage what rationals offer above floating-point is that >>>>> the calculation results are always exact. However, in numeric
programming the input data often comes from a physical measurement,
meaning that it already contains measurement inaccuracies.
Physics is not the only Science out there
You were the one that brought up physics ("I am not a mathematician or a physicist"). /All/ sciences - to be worthy of the name "science" -
involve measurements of real things. Almost always, these are inexact measurements, with the exceptions being relatively small whole number
counts. Rational numbers turn up very rarely in science of any kind. Probably the only science in which they /do/ turn up is quantum
mechanics in physics, and even there we are talking about small and
specific values (half-integer spin, third or two-third charges on
quarks, that kind of thing).
Rational arithmetic does not really turn up anywhere outside pure
mathematics and certain direct applications (such as in cryptography).
On 17/09/2021 19:19, alessandro volturno wrote:
The only advantage what rationals offer above floating-point is that >>>>> the calculation results are always exact. However, in numeric
programming the input data often comes from a physical measurement,
meaning that it already contains measurement inaccuracies.
Physics is not the only Science out there
You were the one that brought up physics ("I am not a mathematician or a physicist"). /All/ sciences - to be worthy of the name "science" -
involve measurements of real things. Almost always, these are inexact measurements, with the exceptions being relatively small whole number
counts. Rational numbers turn up very rarely in science of any kind. Probably the only science in which they /do/ turn up is quantum
mechanics in physics, and even there we are talking about small and
specific values (half-integer spin, third or two-third charges on
quarks, that kind of thing).
Rational arithmetic does not really turn up anywhere outside pure
mathematics and certain direct applications (such as in cryptography).
On 18/09/2021 02:03, Scott Lurndal wrote:
Juha Nieminen <nospam@thanks.invalid> writes:
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves
like an
arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
I could rant for hours on the unsuitability of the silly
C++ output stream crap in real applications.
But I've got too much on my plate right now. Much of which
is making performance improvements to a large CPU-bound
C++ application; primarily by getting rid of all outputstringstream
crap (replacing with snprintf) and eliminating most trivial
run-time (vs. startup time) uses of std::string.
void
a(void)
{
std::string fred = "this is a test";
printf("%s", fred.c_str());
}
(and that's _with_ -O3).
Maybe a better compiler would help? With clang++ and -O2:
On 17/09/2021 23:34, Ian Collins wrote:
Or pretty much any version of gcc with -O2, at least according to my
Maybe a better compiler would help? With clang++ and -O2:
tests on <https://godbolt.org>
Maybe Scott has unusual options, or an unusual library, or other
surrounding code that affects the results.
There are plenty of reasons to dislike C++ output streams (for me, it is
the moronic design decision of stateful formatting flags that are the
big problem).
The quality of code generated for a weird mixture of
C-style and C++-style, for an operation that is always big and slow, is
not such a concern.
David Brown <david.brown@hesbynett.no> writes:
On 17/09/2021 23:34, Ian Collins wrote:
Or pretty much any version of gcc with -O2, at least according to my
Maybe a better compiler would help? With clang++ and -O2:
tests on <https://godbolt.org>
Maybe Scott has unusual options, or an unusual library, or other
surrounding code that affects the results.
$ gcc --version
gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
It's what I had on the system I was posting from, and the code
was an illustrative example, not from our proprietary production
code.
There are plenty of reasons to dislike C++ output streams (for me, it is
the moronic design decision of stateful formatting flags that are the
big problem).
Indeed, and they're completely unreadable.
The quality of code generated for a weird mixture of
C-style and C++-style, for an operation that is always big and slow, is
not such a concern.
snprintf makes a single pass over the formatting string. It's a single function call.
output string streams (the "C++" way) has multiple function calls and generates a shitload of code. And is much less readable and
not as maintainable. The arguments about mismatched format
types is obviated by all modern compilers warning for the *printf
family arguments.
Performance _does_ matter in some applications - ours can eat a
24-core system for lunch, so every cycle matters; especially when
the customer complains about performance (but then our application
simulates a full SoC - sufficient to boot multicore linux and run packet processing application stacks (e.g DPDK) on the simulator prior
to hardware availability).
On 18/09/2021 15:54, Scott Lurndal wrote:
snprintf makes a single pass over the formatting string. It's a single
function call.
output string streams (the "C++" way) has multiple function calls and
generates a shitload of code. And is much less readable and
not as maintainable. The arguments about mismatched format
types is obviated by all modern compilers warning for the *printf
family arguments.
Both approaches are terrible in my opinion:
C++: std::cout << "A=" << a << " B=" << b << " C=" << c << std::endl;
C: printf("A=%d B=%f C=%s\n", a, b, c);
Compared with the equivalent in any of my languages:
M: println =a, =b, =c
The C++ just looks dreadful (and I keep forgetting the << or writing
commas instead).
a=3 b=4 c=Halloa=3;b=4;c='Hallo'
print(f'a={a} b={b} c={c}')
My approach is to have print directly supported by the language. It can
map your code to a series of function calls or, at one time when I
transpiled to C, into a single synthesised printf call.
'input_003.png'f'input_{a:03}.png'
David Brown <david.brown@hesbynett.no> writes:
On 17/09/2021 23:34, Ian Collins wrote:
Or pretty much any version of gcc with -O2, at least according to my
Maybe a better compiler would help? With clang++ and -O2:
tests on <https://godbolt.org>
Maybe Scott has unusual options, or an unusual library, or other
surrounding code that affects the results.
$ gcc --version
gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
It's what I had on the system I was posting from, and the code
was an illustrative example, not from our proprietary production
code.
There are plenty of reasons to dislike C++ output streams (for me, it is
the moronic design decision of stateful formatting flags that are the
big problem).
Indeed, and they're completely unreadable.
The quality of code generated for a weird mixture of
C-style and C++-style, for an operation that is always big and slow, is
not such a concern.
snprintf makes a single pass over the formatting string. It's a single function call.
output string streams (the "C++" way) has multiple function calls and generates a shitload of code.
On 18/09/2021 15:54, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 17/09/2021 23:34, Ian Collins wrote:
snprintf makes a single pass over the formatting string. It's a single
function call.
C: printf("A=%d B=%f C=%s\n", a, b, c);
Am 18.09.21 um 18:36 schrieb Bart:
On 18/09/2021 15:54, Scott Lurndal wrote:
snprintf makes a single pass over the formatting string. It's a single >>> function call.
output string streams (the "C++" way) has multiple function calls and
generates a shitload of code. And is much less readable and
not as maintainable. The arguments about mismatched format
types is obviated by all modern compilers warning for the *printf
family arguments.
Both approaches are terrible in my opinion:
C++: std::cout << "A=" << a << " B=" << b << " C=" << c << std::endl;
C: printf("A=%d B=%f C=%s\n", a, b, c);
Compared with the equivalent in any of my languages:
M: println =a, =b, =c
The C++ just looks dreadful (and I keep forgetting the << or writing
commas instead).
There is widespread support for this in other languages; e.g. Python3:
Python 3.8.8 (default, Apr 13 2021, 12:59:45)
[Clang 10.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
a=3 b=4 c=Halloa=3;b=4;c='Hallo'
print(f'a={a} b={b} c={c}')
Tcl:
(base) Apfelkiste:Sources chris$ wish86
% set a 3; set b 4; set c Hallo
Hallo
% puts "a=$a b=$b c=$c"
a=3 b=4 c=Hallo
%
My approach is to have print directly supported by the language. It
can map your code to a series of function calls or, at one time when I
transpiled to C, into a single synthesised printf call.
In the other languages as demonstrated above, it is not a special
"print" function but rather a way to build strings; you can feed it to
any function or assign it to a variable, not just print it. And so it is
much more useful; consider e.g. constructing file names
'input_003.png'f'input_{a:03}.png'
...and, surprise:
Bart <bc@freeuk.com> writes:
On 18/09/2021 15:54, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 17/09/2021 23:34, Ian Collins wrote:
snprintf makes a single pass over the formatting string. It's a single
function call.
C: printf("A=%d B=%f C=%s\n", a, b, c);
A trivially useless format string. Try adding field widths and
re-ordering the arguments within the format string for i18n/l10n
purposes.
On 18/09/2021 23:48, Scott Lurndal wrote:
Bart <bc@freeuk.com> writes:
On 18/09/2021 15:54, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 17/09/2021 23:34, Ian Collins wrote:
snprintf makes a single pass over the formatting string. It's a single >>>> function call.
C: printf("A=%d B=%f C=%s\n", a, b, c);
A trivially useless format string. Try adding field widths and
re-ordering the arguments within the format string for i18n/l10n
purposes.
that I would write:
println /"Serial number:", sn
in my code, but at the customer site, it might output:
Serie nummer: 1234
if they spoke Dutch. "/" is a translation operator.)
Although the rules for spacing and newlines still differ widely. My
example will add spacing between the elements. In C++, you need to write:
std::cout << A << " " << B << " " << C;
where you gradually lose the will to live. I assume there is a formatted Print feature other than C's printf.
But I've got too much on my plate right now. Much of which
is making performance improvements to a large CPU-bound
C++ application; primarily by getting rid of all outputstringstream
crap (replacing with snprintf) and eliminating most trivial
run-time (vs. startup time) uses of std::string.
Am 19.09.21 um 01:46 schrieb Bart:
On 18/09/2021 23:48, Scott Lurndal wrote:
Bart <bc@freeuk.com> writes:
On 18/09/2021 15:54, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 17/09/2021 23:34, Ian Collins wrote:
snprintf makes a single pass over the formatting string. It's a
single
function call.
C: printf("A=%d B=%f C=%s\n", a, b, c);
A trivially useless format string. Try adding field widths and
re-ordering the arguments within the format string for i18n/l10n
purposes.
that I would write:
println /"Serial number:", sn
in my code, but at the customer site, it might output:
Serie nummer: 1234
if they spoke Dutch. "/" is a translation operator.)
You didn't get the problem Scott was talking about. If you have more
than 1 variable in a sentence, in the translation the word order might
be changed. E.g.
"The $animal bites $name"
could be tranlsated as
"$name gets bitten by the $animal"
in some language.
Therefore, if you do
printf("The %s bites %s", "dog", "Harry")
and the translator does
"%s gets bitten by the %s"
you will end up with
"dog gets bitten by the Harry"
If, however, there is proper string interpolation like in Python format strings, then the translator would translatate the string as above,
changing
"The {animal} bites {name}"
into
"{name} gets bitten by the {animal}"
and it would come out correctly. Obviously, there are still problems
with inflections; in most languages the dog, Harry etc. are adapted
depending on the function in the sentence (grammatical cases).
"The {animal} bites {name}"
into
"{name} gets bitten by the {animal}"
One quite often runs across C++ purists (or new grads) who falsly eschew
C constructs as "not C++".
Unfortunately, we need to support GCC4 through GCC11 efficiently.
Both approaches are terrible in my opinion:
C++: std::cout << "A=" << a << " B=" << b << " C=" << c << std::endl;
C: printf("A=%d B=%f C=%s\n", a, b, c);
Compared with the equivalent in any of my languages:
M: println =a, =b, =c
The C++ just looks dreadful (and I keep forgetting the << or writing
commas instead).
Bart <bc@freeuk.com> wrote:
Both approaches are terrible in my opinion:
C++: std::cout << "A=" << a << " B=" << b << " C=" << c << std::endl;
C: printf("A=%d B=%f C=%s\n", a, b, c);
Compared with the equivalent in any of my languages:
M: println =a, =b, =c
Uh... println in your languages will automatically print "name=" before printing the value of a variable? What if you want to use spaces around
the '='? What if you want to use another character instead, like ':',
and have a space only after that character but not before it?
Anyway, it's relatively easy in C++ to implement a function that behaves
like std::ostream, but uses a function call syntax instead, like:
myprint("a=", a, ", b=", b, ", c=", c, "\n");
The C++ just looks dreadful (and I keep forgetting the << or writing
commas instead).
It's C++'s fault that you keep forgetting the <<?
Scott Lurndal <scott@slp53.sl.home> wrote:
One quite often runs across C++ purists (or new grads) who falsly eschew
C constructs as "not C++".
My response to them is that "if it's in the C++ standard, then it's C++, >through and through. Use the tools that are best for the task at hand."
Just because something is "inherited" from C (so to speak) doesn't mean
it's not suitable and perfectly valid to use in C++. After all, keywords
like 'for' and 'if' are inherited from C. Does that mean they shouldn't
be used in C++? Why is using those ok, but eg. using std::printf() is not? >What's the difference?
Unfortunately, we need to support GCC4 through GCC11 efficiently.
I find it fascinating how common gcc 4 is still out there in the wild,
even to this day.
I blame certain Linux distros for this.
Yes, because it is so peculiar. I wouldn't know how to create such a function, but it would have been a better way of presenting a print
feature, and more conventional.
I blame certain Linux distros for this.
I wouldn't use the verb "blame" here. Most programmers don't
particularly care about the version of the compiler, so long as
it works.
Bart <bc@freeuk.com> wrote:
Yes, because it is so peculiar. I wouldn't know how to create such a
function, but it would have been a better way of presenting a print
feature, and more conventional.
The basic idea with overloading a binary operator, rather than using a function call syntax, is that the output can be expanded with your own
custom types (which is not really possible if it used a function call syntax).
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
I suppose there could be a contrived way of achieving the same thing
with a function call syntax, ie. that you could write
std::cout("Value = ", obj, "\n");
but I'm not sure how simple that could be made to be. Especially in C++98.
Scott Lurndal <scott@slp53.sl.home> wrote:
I blame certain Linux distros for this.
I wouldn't use the verb "blame" here. Most programmers don't
particularly care about the version of the compiler, so long as
it works.
Yeah, the problem with gcc 4 is that it doesn't support fully C++11
(if I remember correctly), much less newer versions.
Bart <bc@freeuk.com> wrote:
Yes, because it is so peculiar. I wouldn't know how to create such a
function, but it would have been a better way of presenting a print
feature, and more conventional.
The basic idea with overloading a binary operator, rather than using a >function call syntax, is that the output can be expanded with your own
custom types (which is not really possible if it used a function call >syntax).
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
Juha Nieminen <nospam@thanks.invalid> writes:
Bart <bc@freeuk.com> wrote:
Yes, because it is so peculiar. I wouldn't know how to create such a
function, but it would have been a better way of presenting a print
feature, and more conventional.
The basic idea with overloading a binary operator, rather than using a
function call syntax, is that the output can be expanded with your own
custom types (which is not really possible if it used a function call
syntax).
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
fprintf(stdout, "Value = %s\n" obj.to_string());
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
I suppose there could be a contrived way of achieving the same thing
with a function call syntax, ie. that you could write
std::cout("Value = ", obj, "\n");
but I'm not sure how simple that could be made to be. Especially in C++98.
That doesn't make sense to me, or maybe there are some limitations in
C++ so that it can only work that way.
I don't do overloads in my languages except for the 'tostr' operator (normally unary, but see below) in my dynamic language.
'tostr' is applied automatically to each item in a statement like this:
println a, b, c
And it turns whatever a, b, c are into strings.
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
fprintf(stdout, "Value = %s\n" obj.to_string());
On 19/09/2021 22:54, Scott Lurndal wrote:
Juha Nieminen <nospam@thanks.invalid> writes:
Bart <bc@freeuk.com> wrote:
Yes, because it is so peculiar. I wouldn't know how to create such a
function, but it would have been a better way of presenting a print
feature, and more conventional.
The basic idea with overloading a binary operator, rather than using a
function call syntax, is that the output can be expanded with your own
custom types (which is not really possible if it used a function call
syntax).
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
fprintf(stdout, "Value = %s\n" obj.to_string());
I don't know how well C++ can match even a simple scripting language in capabilities. But there, you could do something like this:
x := (obj1, obj2, obj3) # list of 3 objects
All objects could be of different types, with their own to-string
methods. But even if all of the same type, you'd need this:
print x
to apply those custom to-string methods to the elements of x without
being told. Include x itself if that had its own to-string routine.
Bart <bc@freeuk.com> wrote:
In other words, you can achieve this:That doesn't make sense to me, or maybe there are some limitations in
MyClass obj;
std::cout << "Value = " << obj << "\n";
I suppose there could be a contrived way of achieving the same thing
with a function call syntax, ie. that you could write
std::cout("Value = ", obj, "\n");
but I'm not sure how simple that could be made to be. Especially in C++98. >>
C++ so that it can only work that way.
What doesn't make sense to you?
How exactly do you expect being able to have an existing standard library function support your own custom type as a parameter?
I don't do overloads in my languages except for the 'tostr' operator
(normally unary, but see below) in my dynamic language.
'tostr' is applied automatically to each item in a statement like this:
println a, b, c
And it turns whatever a, b, c are into strings.
So if one of them is, say, a list of a thousand objects, and you want to print that list like that, it will dynamically allocate and construct a
huge string, which gets printed, and then destroyed?
Instead of, you know, the object just printing every element individually, requiring no extra memory and no extra allocations. Something that overloading operator<< easily achieves.
On 20/09/2021 01:31, Bart wrote:
On 19/09/2021 22:54, Scott Lurndal wrote:
Juha Nieminen <nospam@thanks.invalid> writes:
Bart <bc@freeuk.com> wrote:
Yes, because it is so peculiar. I wouldn't know how to create such a >>>>> function, but it would have been a better way of presenting a print
feature, and more conventional.
The basic idea with overloading a binary operator, rather than using a >>>> function call syntax, is that the output can be expanded with your own >>>> custom types (which is not really possible if it used a function call
syntax).
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
fprintf(stdout, "Value = %s\n" obj.to_string());
I don't know how well C++ can match even a simple scripting language in
capabilities. But there, you could do something like this:
x := (obj1, obj2, obj3) # list of 3 objects
All objects could be of different types, with their own to-string
methods. But even if all of the same type, you'd need this:
print x
to apply those custom to-string methods to the elements of x without
being told. Include x itself if that had its own to-string routine.
There should be no problem making a variadic template function "print"
that turns "print(a, b, c);" into "cout << a << b << c;", if someone
really dislikes the << syntax. It could also turn it into "cout << a.to_string() << ' ' << b.to_string() << ' ' << c.to_string();", or
whatever is the day's preference.
On 20/09/2021 07:33, David Brown wrote:
On 20/09/2021 01:31, Bart wrote:
On 19/09/2021 22:54, Scott Lurndal wrote:
Juha Nieminen <nospam@thanks.invalid> writes:
Bart <bc@freeuk.com> wrote:
Yes, because it is so peculiar. I wouldn't know how to create such a >>>>>> function, but it would have been a better way of presenting a print >>>>>> feature, and more conventional.
The basic idea with overloading a binary operator, rather than using a >>>>> function call syntax, is that the output can be expanded with your own >>>>> custom types (which is not really possible if it used a function call >>>>> syntax).
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
fprintf(stdout, "Value = %s\n" obj.to_string());
I don't know how well C++ can match even a simple scripting language in
capabilities. But there, you could do something like this:
x := (obj1, obj2, obj3) # list of 3 objects
All objects could be of different types, with their own to-string
methods. But even if all of the same type, you'd need this:
print x
to apply those custom to-string methods to the elements of x without
being told. Include x itself if that had its own to-string routine.
There should be no problem making a variadic template function "print"
that turns "print(a, b, c);" into "cout << a << b << c;", if someone
really dislikes the << syntax. It could also turn it into "cout <<
a.to_string() << ' ' << b.to_string() << ' ' << c.to_string();", or
whatever is the day's preference.
My guess is cout and << (don't ask me to explain the difference, except
one needs to go at the start!) are already implemented on top of a stack
of language-defining features.
Now you're saying that we need more templates on top of that to make the syntax palatable.
It's not surprising that people complain about C++ being slower to compile!
My view is that basic Print is a fundamental feature that needs to be natively supported by the core language. Then it can be kept streamlined without wasting too much compiler time on it.
On 20/09/2021 17:11, Bart wrote:
My guess is cout and << (don't ask me to explain the difference, except
one needs to go at the start!) are already implemented on top of a stack
of language-defining features.
If you want to learn C++, learn C++. Please stop giving opinions on everything you hate about it, or all the limitations and problems you
think it has, when you know so very little about the language.
My view is that basic Print is a fundamental feature that needs to be
natively supported by the core language. Then it can be kept streamlined
without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
<snip pointless repetition of how well your our personal language suits
your own personal preferences>
On 20/09/2021 19:39, Bart wrote:
On 20/09/2021 17:08, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:
My guess is cout and << (don't ask me to explain the difference, except >>>> one needs to go at the start!) are already implemented on top of a stack >>>> of language-defining features.
If you want to learn C++, learn C++. Please stop giving opinions on
everything you hate about it, or all the limitations and problems you
think it has, when you know so very little about the language.
You don't need to know C++ inside out to have an opinion about it or
about language design, or for it to help you in knowing which avenues
not to pursue, since you can see how it's ended up: in a vastly complex
and cumbersome language near-impossible for an individual to implement.
It's true that you don't need much knowledge about a subject to have an opinion. You only need to know what you are talking about to have an /informed/ opinion - one worth listening to and discussing.
On 20/09/2021 17:08, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:
My guess is cout and << (don't ask me to explain the difference, except
one needs to go at the start!) are already implemented on top of a stack >>> of language-defining features.
If you want to learn C++, learn C++. Please stop giving opinions on
everything you hate about it, or all the limitations and problems you
think it has, when you know so very little about the language.
You don't need to know C++ inside out to have an opinion about it or
about language design, or for it to help you in knowing which avenues
not to pursue, since you can see how it's ended up: in a vastly complex
and cumbersome language near-impossible for an individual to implement.
On 20/09/2021 18:49, David Brown wrote:
On 20/09/2021 19:39, Bart wrote:
On 20/09/2021 17:08, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:
My guess is cout and << (don't ask me to explain the difference,
except
one needs to go at the start!) are already implemented on top of a
stack
of language-defining features.
If you want to learn C++, learn C++. Please stop giving opinions on
everything you hate about it, or all the limitations and problems you
think it has, when you know so very little about the language.
You don't need to know C++ inside out to have an opinion about it or
about language design, or for it to help you in knowing which avenues
not to pursue, since you can see how it's ended up: in a vastly complex
and cumbersome language near-impossible for an individual to implement.
It's true that you don't need much knowledge about a subject to have an
opinion. You only need to know what you are talking about to have an
/informed/ opinion - one worth listening to and discussing.
You're right: someone who's only implemented PRINT in various languages
a few dozen times can't be expected to have an informed opinion about
how well cout or printf tackles the job.
On 20/09/2021 20:04, Bart wrote:
You're right: someone who's only implemented PRINT in various languages
a few dozen times can't be expected to have an informed opinion about
how well cout or printf tackles the job.
Implementing it doesn't give you anything here except an inflated view
of your own opinion. /Using/ print systems in various languages is
relevant.
in C++, it is pointless to compare it to anything else.
Any print system has its advantages and disadvantages. You should be
able to understand that. Instead, you'd rather assume that because it
is C++, it is necessarily all bad without any need for further thought
or knowledge.
You don't need to know C++ inside out to have an opinion about it or
about language design, or for it to help you in knowing which avenues
not to pursue, since you can see how it's ended up: in a vastly complex
and cumbersome language near-impossible for an individual to implement.
As I said above, people can make up their own minds. Personally I find
the first type considerably easier to write, and to read. The only
difficulty is having to go and find out how to suppress the automatic
space between items, and the newline at the end.
20.09.2021 20:39 Bart kirjutas:
You don't need to know C++ inside out to have an opinion about it or
about language design, or for it to help you in knowing which avenues
not to pursue, since you can see how it's ended up: in a vastly
complex and cumbersome language near-impossible for an individual to
implement.
Well, that's the point. A lot of complexity is packed away in the
language so that all programmers can make use of it and build upon it.
There are valid concerns about C++ becoming too cumbersome or too complicated, but these are in no way related to how many individuals it
takes to implement the language, that's just a non-goal.
How many
individuals it took to build the airplane you last used? Even your
bicycle was most probably built by more than one person.
So I'm judging how conveniently the language allows me to do that simple task. I don't care what else cout might do for me in that context.
Here, anyone can judge for themselves (although I doubt they'll be that
open minded in a C++ group):
20 print i, sqr(i)
std::cout << i << " " << sqrt(i) << std::endl;
The first line is from decades-old BASIC. The second line, which also
needs iostream and math.h includes, is from latest C++.
Any print system has its advantages and disadvantages. You should be
able to understand that. Instead, you'd rather assume that because it
is C++, it is necessarily all bad without any need for further thought
or knowledge.
As I said above, people can make up their own minds. Personally I find
the first type considerably easier to write, and to read. The only
difficulty is having to go and find out how to suppress the automatic
space between items, and the newline at the end.
On 20/09/2021 20:35, David Brown wrote:
On 20/09/2021 20:04, Bart wrote:
You're right: someone who's only implemented PRINT in various languages
a few dozen times can't be expected to have an informed opinion about
how well cout or printf tackles the job.
Implementing it doesn't give you anything here except an inflated view
of your own opinion. /Using/ print systems in various languages is
relevant.
Well, I've used print, of course, in 2-3 dozen languages I might have
played with.
But to talk with some knowledge about how Print might be better
implemented in any language, you really need to have tried implementing
Print within a language, and specifically implementing it as a built-in feature
But if you don't even know what "cout" is or how "<<" works
in C++, it is pointless to compare it to anything else.
It doesn't matter. I know what it is I'm trying to achieve: turn an expression into text and display it somewhere or send it somewhere.
So I'm judging how conveniently the language allows me to do that simple task. I don't care what else cout might do for me in that context.
Here, anyone can judge for themselves (although I doubt they'll be that
open minded in a C++ group):
20 print i, sqr(i)
std::cout << i << " " << sqrt(i) << std::endl;
The first line is from decades-old BASIC. The second line, which also
needs iostream and math.h includes, is from latest C++.
Any print system has its advantages and disadvantages. You should be
able to understand that. Instead, you'd rather assume that because it
is C++, it is necessarily all bad without any need for further thought
or knowledge.
As I said above, people can make up their own minds. Personally I find
the first type considerably easier to write, and to read. The only
difficulty is having to go and find out how to suppress the automatic
space between items, and the newline at the end.
On 20/09/2021 22:38, Bart wrote:
But to talk with some knowledge about how Print might be better
implemented in any language, you really need to have tried implementing
Print within a language, and specifically implementing it as a built-in
feature
No one cares about how easy or hard it is to implement.
A BASIC-style print statement is fine
for BASIC-style languages - typically designed to be quick and simple
for easy tasks, but unsuitable for bigger work or more complex work, or programs that don't fit into the simple sequence of start program, read
files and/or keyboard, print to screen and/or files, stop program.
But for a language that supports multiple types, formatting,
translations, redirected outputs, systems without a console, etc., then
a simple print statement won't do. It is both too much, and too little.
In fact, /no/ single solution will do everything.
When you think you
have "/the/ answer" to a coding or programming language problem, you are almost guaranteed to be wrong - and you, Bart, think you have all the answers.
So a good, serious programming language does not provide a "print"
statement.
Here, anyone can judge for themselves (although I doubt they'll be that
open minded in a C++ group):
20 print i, sqr(i)
std::cout << i << " " << sqrt(i) << std::endl;
The first line is from decades-old BASIC. The second line, which also
needs iostream and math.h includes, is from latest C++.
The first version is easist for a quick and dirty script.
The second
is better for more serious programming.
Oh, and if your "sqr" is a language built-in function for square roots,
then that demonstrates another reason why serious languages avoid
built-in functions. The name is wrong, and changing the library is
vastly easier than changing the language.
And there you have it.
With your personal language and tools, if you want to change the way the spacing or formatting works, you change the language and the compiler/interpreter. With real languages, the programmer changes the
code they write to change the formatting.
Contrary to some experts' views, I have nothing against BASIC. I
learned to program in BASIC, in several dialects - the "B" stands for "Beginners'". But then I grew up, and understood that while languages
like BASIC can undoubtedly be good for a few hundred line programs, they
are rarely a good choice for more serious work.
What can 'cout' or 'printf' do that an easier-to-use and better designed Print can't do? This is an example bit of C++ posted a couple of days ago:
CMT:
std::cout << sizeof(__int64) << "\n";
std::cout << sizeof(__m128) << "\n";
std::cout << foo_64.is_lock_free() << "\n";
std::cout << foo_128.is_lock_free() << "\n";
I might be missing something, but is there any reason why something like:
println sizeof(__int64);
println sizeof(__m128);
println foo_64.is_lock_free();
println foo_128.is_lock_free();
wouldn't cut it? Too sensible? Too uncluttered? Might leave too many
people thinking, where's the catch? Because all that extra crap in C++
must do something important, right?
On 21/09/2021 13:45, Paavo Helde wrote:
I virtually never use STDERR, mainly because I've no idea how to do so outside of C, or via fprintf from a FFI. Even when writing C, it's just
not a thing for me. STDOUT is already used for logging, error messages, everthing.
In C++, how do you conditionally output to either STDOUT or STDERR? This doesn't work:
auto F = (cond ? stdout : stderr);
F << "HELLO";
Printing to STDOUT seems to me a kind of niche facility which is used
pretty rarely during large parts of C++ development.
You can say that about lots of features.
One of my favourite features of
my own is Stop:
stop # equivalent to stop 0
stop N
which may be implemented via exit(N) or ProcessExit or whatever. It
might be used a tiny number of times in a program, or none at all.
That doesn't mean it shouldn't be user-friendly. Now apply that thinking
to more features...
21.09.2021 13:12 Bart kirjutas:
What can 'cout' or 'printf' do that an easier-to-use and better
designed Print can't do? This is an example bit of C++ posted a couple
of days ago:
CMT:
std::cout << sizeof(__int64) << "\n";
std::cout << sizeof(__m128) << "\n";
std::cout << foo_64.is_lock_free() << "\n";
std::cout << foo_128.is_lock_free() << "\n";
I might be missing something, but is there any reason why something like:
println sizeof(__int64);
println sizeof(__m128);
println foo_64.is_lock_free();
println foo_128.is_lock_free();
wouldn't cut it? Too sensible? Too uncluttered? Might leave too many
people thinking, where's the catch? Because all that extra crap in C++
must do something important, right?
In our codebase of hundreds of thousands lines of C++ code there are
very few outputs to STDOUT, mostly because it's all libraries used by
various client programs who would not like at all if a library polluted
the console with some unwanted messages. Also, when running in Windows
there typically is no console, so there is not much point in printing anything there. If I want to see the value of some variable during a
program run, I put a breakpoint there and hover the mouse over the name.
There are some messages to STDERR though, in critical conditions like
memory exhaustion. How do you write a message to STDERR with your
'println'? It's not obvious at all, unlike for std::cout vs std::cerr.
Printing to STDOUT seems to me a kind of niche facility which is used
pretty rarely during large parts of C++ development.
Why should such a
facility get some special short name and simplified syntax?
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like
memory exhaustion. How do you write a message to STDERR with your
'println'? It's not obvious at all, unlike for std::cout vs std::cerr.
I virtually never use STDERR, mainly because I've no idea how to do so >outside of C, or via fprintf from a FFI. Even when writing C, it's just
not a thing for me. STDOUT is already used for logging, error messages, >everthing.
21.09.2021 16:37 Bart kirjutas:
On 21/09/2021 13:45, Paavo Helde wrote:
I virtually never use STDERR, mainly because I've no idea how to do so
outside of C, or via fprintf from a FFI. Even when writing C, it's
just not a thing for me. STDOUT is already used for logging, error
messages, everthing.
Well that's just plain wrong.
In C++, how do you conditionally output to either STDOUT or STDERR?
This doesn't work:
auto F = (cond ? stdout : stderr);
F << "HELLO";
It works if you use C++ names and syntax:
#include <iostream>
int main() {
bool cond = false;
(cond ? std::cout : std::cerr) << "HELLO";
}
Or more commonly one defines function interfaces in terms of
std::ostream& references, which can be used for all kind of streams.
One of my favourite features of my own is Stop:
stop # equivalent to stop 0
stop N
Until someone wants to encode a nice loop like that:
stop = false;
while (!stop) {
// do something
}
Then it becomes clear you have hijacked a perfectly nice 4-letter name
so it cannot be used any more for other purposes.
21.09.2021 16:37 Bart kirjutas:
Until someone wants to encode a nice loop like that:
stop = false;
while (!stop) {
// do something
}
Then it becomes clear you have hijacked a perfectly nice 4-letter name
so it cannot be used any more for other purposes.
On 21/09/2021 15:09, Paavo Helde wrote:
21.09.2021 16:37 Bart kirjutas:
On 21/09/2021 13:45, Paavo Helde wrote:
I virtually never use STDERR, mainly because I've no idea how to do
so outside of C, or via fprintf from a FFI. Even when writing C, it's
just not a thing for me. STDOUT is already used for logging, error
messages, everthing.
Well that's just plain wrong.
In C++, how do you conditionally output to either STDOUT or STDERR?
This doesn't work:
auto F = (cond ? stdout : stderr);
F << "HELLO";
It works if you use C++ names and syntax:
#include <iostream>
int main() {
bool cond = false;
(cond ? std::cout : std::cerr) << "HELLO";
}
Or more commonly one defines function interfaces in terms of
std::ostream& references, which can be used for all kind of streams.
This is what I initially tried:
auto fred=std::cout;
fred << "Hello, world!\n";
}
The point was to end up with a variable that refers to STDOUT or STDERR,
that can be passed to functions for example.
Bart <bc@freeuk.com> writes:
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like
memory exhaustion. How do you write a message to STDERR with your
'println'? It's not obvious at all, unlike for std::cout vs std::cerr.
I virtually never use STDERR, mainly because I've no idea how to do so >>outside of C, or via fprintf from a FFI. Even when writing C, it's just
not a thing for me. STDOUT is already used for logging, error messages, >>everthing.
Another reason not to use your "language".
hint: 'fprintf(stderr, ...'
The utility guidelines require diagnostic messages go to stderr with >non-diagnostic output to stdout. This is been the case for a half
century for extremely good reasons.
On Tue, 21 Sep 2021 15:36:15 GMT
scott@slp53.sl.home (Scott Lurndal) wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like
memory exhaustion. How do you write a message to STDERR with your
'println'? It's not obvious at all, unlike for std::cout vs std::cerr.
I virtually never use STDERR, mainly because I've no idea how to do so >>>outside of C, or via fprintf from a FFI. Even when writing C, it's just >>>not a thing for me. STDOUT is already used for logging, error messages, >>>everthing.
Another reason not to use your "language".
hint: 'fprintf(stderr, ...'
The utility guidelines require diagnostic messages go to stderr with >>non-diagnostic output to stdout. This is been the case for a half
century for extremely good reasons.
He's probably spent too long in an academic ivory tower and doesn't understand >the use case for standard program output to go to one place while the error >stream is directed elsewhere.
Bart <bc@freeuk.com> writes:
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like
memory exhaustion. How do you write a message to STDERR with your
'println'? It's not obvious at all, unlike for std::cout vs std::cerr.
I virtually never use STDERR, mainly because I've no idea how to do so
outside of C, or via fprintf from a FFI. Even when writing C, it's just
not a thing for me. STDOUT is already used for logging, error messages,
everthing.
Another reason not to use your "language".
hint: 'fprintf(stderr, ...'
The utility guidelines require diagnostic messages go to stderr with non-diagnostic output to stdout. This is been the case for a half
century for extremely good reasons.
On 21/09/2021 08:39, David Brown wrote:
On 20/09/2021 22:38, Bart wrote:
But to talk with some knowledge about how Print might be better
implemented in any language, you really need to have tried implementing
Print within a language, and specifically implementing it as a built-in
feature
No one cares about how easy or hard it is to implement.
You're changing the goalposts. You said my opinion wasn't an informed
one, when I was talking about the deficiences of both cout and printf approaches.
A BASIC-style print statement is fine
for BASIC-style languages - typically designed to be quick and simple
for easy tasks, but unsuitable for bigger work or more complex work, or
programs that don't fit into the simple sequence of start program, read
files and/or keyboard, print to screen and/or files, stop program.
What can 'cout' or 'printf' do that an easier-to-use and better designed Print can't do? This is an example bit of C++ posted a couple of days ago:
CMT:
std::cout << sizeof(__int64) << "\n";
std::cout << sizeof(__m128) << "\n";
std::cout << foo_64.is_lock_free() << "\n";
std::cout << foo_128.is_lock_free() << "\n";
I might be missing something, but is there any reason why something like:
println sizeof(__int64);
println sizeof(__m128);
println foo_64.is_lock_free();
println foo_128.is_lock_free();
wouldn't cut it? Too sensible? Too uncluttered? Might leave too many
people thinking, where's the catch? Because all that extra crap in C++
must do something important, right?
But for a language that supports multiple types, formatting,
translations, redirected outputs, systems without a console, etc., then
a simple print statement won't do. It is both too much, and too little.
You're making this up aren't you?
Simple Print doesn't mean an inability to do anything. It means being
able to do most of it, but in a simpler manner with a lot less typing!
On 21/09/2021 16:36, Scott Lurndal wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like
memory exhaustion. How do you write a message to STDERR with your
'println'? It's not obvious at all, unlike for std::cout vs std::cerr.
I virtually never use STDERR, mainly because I've no idea how to do so
outside of C, or via fprintf from a FFI. Even when writing C, it's just
not a thing for me. STDOUT is already used for logging, error messages,
everthing.
Another reason not to use your "language".
hint: 'fprintf(stderr, ...'
The utility guidelines require diagnostic messages go to stderr with
non-diagnostic output to stdout. This is been the case for a half
century for extremely good reasons.
Somebody should tell Microsoft then.
On 21/09/2021 16:36, Scott Lurndal wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like
memory exhaustion. How do you write a message to STDERR with your
'println'? It's not obvious at all, unlike for std::cout vs std::cerr.
I virtually never use STDERR, mainly because I've no idea how to do so
outside of C, or via fprintf from a FFI. Even when writing C, it's just
not a thing for me. STDOUT is already used for logging, error messages,
everthing.
Another reason not to use your "language".
hint: 'fprintf(stderr, ...'
The utility guidelines require diagnostic messages go to stderr with
non-diagnostic output to stdout. This is been the case for a half
century for extremely good reasons.
Somebody should tell Microsoft then.
Their CL compiler shows error messages on stdout no stderr.
Bart <bc@freeuk.com> writes:
On 21/09/2021 16:36, Scott Lurndal wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like >>>>> memory exhaustion. How do you write a message to STDERR with yourI virtually never use STDERR, mainly because I've no idea how to do so >>>> outside of C, or via fprintf from a FFI. Even when writing C, it's just >>>> not a thing for me. STDOUT is already used for logging, error messages, >>>> everthing.
'println'? It's not obvious at all, unlike for std::cout vs std::cerr. >>>>
Another reason not to use your "language".
hint: 'fprintf(stderr, ...'
The utility guidelines require diagnostic messages go to stderr with
non-diagnostic output to stdout. This is been the case for a half
century for extremely good reasons.
Somebody should tell Microsoft then.
Feel free. stdout and stderr, and the rules for their usage predate
MSDOS and were in existence long before microsoft produced a C compiler.
https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05
"At program start-up, three streams are predefined and need not be
opened explicitly: standard input (for reading conventional input),
standard output (for writing conventional output), and standard error
(for writing diagnostic output). When opened, the standard error stream
is not fully buffered; the standard input and standard output streams
are fully buffered if and only if the stream can be determined not to
refer to an interactive device."
Feel free. stdout and stderr, and the rules for their usage predate
MSDOS and were in existence long before microsoft produced a C compiler.
21.09.2021 19:45 Bart kirjutas:
On 21/09/2021 16:36, Scott Lurndal wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like >>>>> memory exhaustion. How do you write a message to STDERR with yourI virtually never use STDERR, mainly because I've no idea how to do so >>>> outside of C, or via fprintf from a FFI. Even when writing C, it's just >>>> not a thing for me. STDOUT is already used for logging, error messages, >>>> everthing.
'println'? It's not obvious at all, unlike for std::cout vs std::cerr. >>>>
Another reason not to use your "language".
hint: 'fprintf(stderr, ...'
The utility guidelines require diagnostic messages go to stderr with
non-diagnostic output to stdout. This is been the case for a half
century for extremely good reasons.
Somebody should tell Microsoft then.
Their CL compiler shows error messages on stdout no stderr.
That's easy to check:
c:\tmp>"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29910\bin\Hostx64\x64\CL.exe"
/BLABLA >out.txt 2>err.txt
c:\tmp>type out.txt
c:\tmp>type err.txt
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29913 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
cl : Command line warning D9002 : ignoring unknown option '/BLABLA'
cl : Command line error D8003 : missing source filename
This shows CL compiler indeed reports errors to stderr, as it should. It
also reports its name and copyright message to stderr, to avoid
polluting stdout. This is common practice.
Maybe you are confusing the errors appearing in the compiler with the diagnostic messages reported about the compiled programs? The latters constitute the compiler output, so indeed should appear in stdout (and
they do).
Maybe you are confusing the errors appearing in the compiler with the diagnostic messages reported about the compiled programs? The latters constitute the compiler output, so indeed should appear in stdout (and
they do).
Two major compilers and /they/ don't know how to handle STDOUT and STDERR!
21.09.2021 20:33 Bart kirjutas:
Two major compilers and /they/ don't know how to handle STDOUT and
STDERR!
Hint: if everybody else seems to drive on the wrong side of the highway,
it might be a time for little self-contemplation.
On 21/09/2021 18:02, Scott Lurndal wrote:[...]
[...]Feel free. stdout and stderr, and the rules for their usage predate
MSDOS and were in existence long before microsoft produced a C compiler.
Well I've never heard of any such rules.
On 21/09/2021 18:43, Paavo Helde wrote:
21.09.2021 20:33 Bart kirjutas:
Two major compilers and /they/ don't know how to handle STDOUT and
STDERR!
Hint: if everybody else seems to drive on the wrong side of the highway,
it might be a time for little self-contemplation.
So to be clear:
* Copyright messages from CL belong in STDERR
* Informative messages from gcc belong in STDERR
* Program Error messages from CL belong in STDOUT
* Program Error messages from gcc belong in STDERR
You are saying this behaviour is correct, not crazy nor conflicting at
all, and it's time for ME to do self-comtemplation?
"auto fred = std::cout;" will make "fred" a copy of the value of
"std::cout".
What you want is a reference, so that you are referring to
the real output stream:
#include <iostream>
int main() {
bool cond = false;
auto& fred = (cond ? std::cout : std::cerr);
fred << "HELLO\n";
}
On 21/09/2021 18:43, Paavo Helde wrote:
21.09.2021 20:33 Bart kirjutas:
Two major compilers and /they/ don't know how to handle STDOUT and
STDERR!
Hint: if everybody else seems to drive on the wrong side of the
highway, it might be a time for little self-contemplation.
So to be clear:
* Copyright messages from CL belong in STDERR
* Informative messages from gcc belong in STDERR
* Program Error messages from CL belong in STDOUT
* Program Error messages from gcc belong in STDERR
You are saying this behaviour is correct, not crazy nor conflicting at
all, and it's time for ME to do self-comtemplation?
Bart <bc@freeuk.com> writes:
On 21/09/2021 18:02, Scott Lurndal wrote:[...]
[...]Feel free. stdout and stderr, and the rules for their usage predate
MSDOS and were in existence long before microsoft produced a C compiler.
Well I've never heard of any such rules.
So now you've learned something.
21.09.2021 20:59 Bart kirjutas:
On 21/09/2021 18:43, Paavo Helde wrote:
21.09.2021 20:33 Bart kirjutas:
Two major compilers and /they/ don't know how to handle STDOUT and
STDERR!
Hint: if everybody else seems to drive on the wrong side of the
highway, it might be a time for little self-contemplation.
So to be clear:
* Copyright messages from CL belong in STDERR
* Informative messages from gcc belong in STDERR
* Program Error messages from CL belong in STDOUT
* Program Error messages from gcc belong in STDERR
Error messages from compiler belong to STDERR. Diagnostic messages
(errors and warnings) about compiled programs can be either way,
depending on what is considered the main output from the compiler.
You are saying this behaviour is correct, not crazy nor conflicting at
all, and it's time for ME to do self-comtemplation?
Yes. These rules have a simple and sound reason: if the program is
producing some output which can be potentially post-processed programmatically by another program, then everything not belonging to
this output must be sent to stderr, to avoid garbling the output.
Gcc manpage contains examples how to send assembler or other output to stdout, so it makes sense for them to send all diagnostics to stderr to
avoid garbling.
I'm still not clear. Is what MS' CL is doing correct or not: sending
program error messages to STDOUT instead of STDERR as gcc does?
On 21/09/2021 19:53, Keith Thompson wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 18:02, Scott Lurndal wrote:[...]
[...]Feel free. stdout and stderr, and the rules for their usage predateWell I've never heard of any such rules.
MSDOS and were in existence long before microsoft produced a C compiler. >>>
So now you've learned something.
Not really. The rules apply to what, exactly: a specific OS, ALL OSes,
a specific language, ALL languages, some library.....
I think somebody is making a few assumptions.
The fact is, when I write an application then it does what I say. And
/I/ decide how any error handling is to be performed.
On 21/09/2021 19:53, Keith Thompson wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 18:02, Scott Lurndal wrote:[...]
[...]Feel free. stdout and stderr, and the rules for their usage predateWell I've never heard of any such rules.
MSDOS and were in existence long before microsoft produced a C compiler. >>>
So now you've learned something.
Not really. The rules apply to what, exactly: a specific OS, ALL OSes, a >specific language, ALL languages, some library.....
I think somebody is making a few assumptions.
The fact is, when I write an application then it does what I say. And
/I/ decide how any error handling is to be performed.
Bart <bc@freeuk.com> writes:
On 21/09/2021 19:53, Keith Thompson wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 18:02, Scott Lurndal wrote:[...]
[...]Feel free. stdout and stderr, and the rules for their usage predate >>>>> MSDOS and were in existence long before microsoft produced a C compiler. >>>>Well I've never heard of any such rules.
So now you've learned something.
Not really. The rules apply to what, exactly: a specific OS, ALL OSes, a
specific language, ALL languages, some library.....
I think somebody is making a few assumptions.
You should stop doing that.
The fact is, when I write an application then it does what I say. And
/I/ decide how any error handling is to be performed.
It has already been pointed out to you the reasoning behind
the rule. Specifically to support pipelining the output of
one command into another without interleaving diagnostic
messages.
$ cat /path/to/file | egrep -w '^fred|^joe|^sam' > list-of-lines-starting-with-fred-joe-or-sam
Any diagnostics from cat or grep will go to stderr, not to the pipeline.
Now you're saying that we need more templates on top of that to make the syntax palatable.
It's not surprising that people complain about C++ being slower to compile!
My print statements also come as the function-like sprint()/sfprint()
that just return a string anyway.
What doesn't make sense to you?
Having to overload "<<", as I assume you meant, as you seemed to imply
that was better/easier than doing whatever it was to obj to allow its
use in function syntax.
So if one of them is, say, a list of a thousand objects, and you want to
print that list like that, it will dynamically allocate and construct a
huge string, which gets printed, and then destroyed?
Instead of, you know, the object just printing every element individually, >> requiring no extra memory and no extra allocations. Something that
overloading operator<< easily achieves.
This is a drawback of having a 'tostring' method applied to an entire, complex object.
However, if the object is that complex, it will already be using
equivalent amounts of memory anyway.
David Brown <david.brown@hesbynett.no> writes:
[...]
"auto fred = std::cout;" will make "fred" a copy of the value of
"std::cout".
No it won't. There's no assignment operator for std::basic_ostream.
What you want is a reference, so that you are referring to
the real output stream:
#include <iostream>
int main() {
bool cond = false;
auto& fred = (cond ? std::cout : std::cerr);
fred << "HELLO\n";
}
Right. And if you want to change fred later, you can use a pointer
(smart or otherwise).
Bart <bc@freeuk.com> wrote:
Now you're saying that we need more templates on top of that to make the
syntax palatable.
It's not surprising that people complain about C++ being slower to compile!
So you want to trade runtime efficiency for compilation efficiency, essentially?
My print statements also come as the function-like sprint()/sfprint()
that just return a string anyway.
It seems to me that you come from a world of programming language design
that pays little to no attention to the efficiency of the resulting
program.
This is very typical of eg. scripting languages and many other
similar languages (usually interpreted, sometimes compiled). Dynamically allocated strings and objects are liberally created at every turn, things
are converted into strings and from strings all the time, and so on and
so forth, with exactly zero regard to how costly that may or may not be.
A rampant "as long as it works" mentality, with zero regard to efficiency.
That's not C++ (nor C for that matter). If you don't like the design of
the language, then don't use it. It's that simple.
HorseyWorsey@the_stables.com writes:
On Tue, 21 Sep 2021 15:36:15 GMT
scott@slp53.sl.home (Scott Lurndal) wrote:
Bart <bc@freeuk.com> writes:
On 21/09/2021 13:45, Paavo Helde wrote:
There are some messages to STDERR though, in critical conditions like >>>>> memory exhaustion. How do you write a message to STDERR with yourI virtually never use STDERR, mainly because I've no idea how to do so >>>>outside of C, or via fprintf from a FFI. Even when writing C, it's just >>>>not a thing for me. STDOUT is already used for logging, error messages, >>>>everthing.
'println'? It's not obvious at all, unlike for std::cout vs std::cerr. >>>>
Another reason not to use your "language".
hint: 'fprintf(stderr, ...'
The utility guidelines require diagnostic messages go to stderr with >>>non-diagnostic output to stdout. This is been the case for a half >>>century for extremely good reasons.
He's probably spent too long in an academic ivory tower and doesn't understand
the use case for standard program output to go to one place while the error >>stream is directed elsewhere.
People in the "academic ivory tower" are directly responsible for the
state of the art today. Djikstra, Wirth, Atanasoff, Patterson,
Diffie, Helman, Rivest, Shamir, Adelman, Aho, Ullman, the exceptional Leslie >Lamport
and thousands of others.
On Wed, 22 Sep 2021 10:51:23 +0100
Bart <bc@freeuk.com> wrote:
#include <iostream>
int main()
{ std::string s="";
char t[100];
for (int i=1; i<=10000000; ++i) {
s += itoa(i,t,10);
s += ' ';
}
std::cout << "S.size = " << s.size() << "\n";
}
You learn something new every day. I'd never heard of itoa(). Apparently its an ancient K&R function which didn't get included into the ANSI C standard.
#include <iostream>
int main()
{ std::string s="";
char t[100];
for (int i=1; i<=10000000; ++i) {
s += itoa(i,t,10);
s += ' ';
}
std::cout << "S.size = " << s.size() << "\n";
}
On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
On Wed, 22 Sep 2021 10:51:23 +0100
Bart <bc@freeuk.com> wrote:
#include <iostream>
int main()
{ std::string s="";
char t[100];
for (int i=1; i<=10000000; ++i) {
s += itoa(i,t,10);
s += ' ';
}
std::cout << "S.size = " << s.size() << "\n";
}
You learn something new every day. I'd never heard of itoa(). Apparently its >> an ancient K&R function which didn't get included into the ANSI C standard. >>
So what would be the shiny new alternative in C++?
I wanted to avoid sprintf which has extra overheads that would likely >dominate the timing.
Bart <bc@freeuk.com> wrote:
What doesn't make sense to you?
Having to overload "<<", as I assume you meant, as you seemed to imply
that was better/easier than doing whatever it was to obj to allow its
use in function syntax.
So what's the alternative that you suggest?
So if one of them is, say, a list of a thousand objects, and you want to >>> print that list like that, it will dynamically allocate and construct a
huge string, which gets printed, and then destroyed?
Instead of, you know, the object just printing every element individually, >>> requiring no extra memory and no extra allocations. Something that
overloading operator<< easily achieves.
This is a drawback of having a 'tostring' method applied to an entire,
complex object.
However, if the object is that complex, it will already be using
equivalent amounts of memory anyway.
The string will be constructed *in addition* to whatever memory the object may be taking, and it will be constructed solely for the printing process, and then immediately destroyed.
This even though there's no reason to construct such a string into RAM,
as each element could just be printed to the output individually by the object, without having to construct any strings.
OK, let's try it. Here's a program that writes 1 million lines of the
same 3 variables:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
long long int a = 0x7FFFFFFFFFFFFFFF;
double b = 3.14159265359;
const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
myfile.open ("output");
for (int i=0; i<1000000; ++i) {
myfile << a << " " << b << " " << c << "\n";
}
myfile.close();
return 0;
}
On my machine, that took 4 seconds.
On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
You learn something new every day. I'd never heard of itoa().
Apparently its
an ancient K&R function which didn't get included into the ANSI C
standard.
So what would be the shiny new alternative in C++?
On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
On Wed, 22 Sep 2021 10:51:23 +0100
Bart <bc@freeuk.com> wrote:
#include <iostream>
int main()
{ std::string s="";
char t[100];
for (int i=1; i<=10000000; ++i) {
s += itoa(i,t,10);
s += ' ';
}
std::cout << "S.size = " << s.size() << "\n";
}
You learn something new every day. I'd never heard of itoa().
Apparently its
an ancient K&R function which didn't get included into the ANSI C
standard.
So what would be the shiny new alternative in C++?
I wanted to avoid sprintf which has extra overheads that would likely dominate the timing.
On 22/09/2021 05:58, Juha Nieminen wrote:
Bart <bc@freeuk.com> wrote:
What doesn't make sense to you?
Having to overload "<<", as I assume you meant, as you seemed to imply
that was better/easier than doing whatever it was to obj to allow its
use in function syntax.
So what's the alternative that you suggest?
Overloading whatever 'tostring' operations that are implicitly used when printing.
So if one of them is, say, a list of a thousand objects, and you
want to
print that list like that, it will dynamically allocate and construct a >>>> huge string, which gets printed, and then destroyed?
Instead of, you know, the object just printing every element
individually,
requiring no extra memory and no extra allocations. Something that
overloading operator<< easily achieves.
This is a drawback of having a 'tostring' method applied to an entire,
complex object.
However, if the object is that complex, it will already be using
equivalent amounts of memory anyway.
The string will be constructed *in addition* to whatever memory the
object
may be taking, and it will be constructed solely for the printing
process,
and then immediately destroyed.
This even though there's no reason to construct such a string into RAM,
as each element could just be printed to the output individually by the
object, without having to construct any strings.
OK, let's try it. Here's a program that writes 1 million lines of the
same 3 variables:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
long long int a = 0x7FFFFFFFFFFFFFFF;
double b = 3.14159265359;
const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
myfile.open ("output");
for (int i=0; i<1000000; ++i) {
myfile << a << " " << b << " " << c << "\n";
}
myfile.close();
return 0;
}
On my machine, that took 4 seconds. But when I tried my script language, where each element has to be converted to a string object before being printed, it took only 3 seconds:
On 22/09/2021 22:26, Bart wrote:
OK, let's try it. Here's a program that writes 1 million lines of the
same 3 variables:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
long long int a = 0x7FFFFFFFFFFFFFFF;
double b = 3.14159265359;
const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
myfile.open ("output");
for (int i=0; i<1000000; ++i) {
myfile << a << " " << b << " " << c << "\n";
}
myfile.close();
return 0;
}
On my machine, that took 4 seconds.
This will take roughly the time it takes to perform the file writing
(0.4S on my machine). The time spend formatting the output is inconsequential in comparison.
On Wed, 22 Sep 2021 10:51:23 +0100
Bart <bc@freeuk.com> wrote:
#include <iostream>
int main()
{ std::string s="";
char t[100];
for (int i=1; i<=10000000; ++i) {
s += itoa(i,t,10);
s += ' ';
}
std::cout << "S.size = " << s.size() << "\n";
}
You learn something new every day. I'd never heard of itoa(). Apparently its >an ancient K&R function which didn't get included into the ANSI C standard.
#include <stddef.h> // ptrdiff_t
#include <stdio.h> // printf, for the final output
using Size = ptrdiff_t;
#include <charconv> // std::to_chars
#include <limits> // std::numeric_limits
#include <string> // std::string
#include <stdexcept> // std::runtime_error
using namespace std::string_literals;
void append_to( std::string& s, const int v )
{
static const int radix = 10;
static const int max_int_digits =
std::numeric_limits<int>::digits10 + 1;
const Size original_size = s.size();
s.resize( original_size + max_int_digits + 1 ); // 1 for possible sign.
using P_char = char*;
const P_char buffer_start = s.data() + original_size;
const P_char buffer_end = s.data() + s.size();
const std::to_chars_result tcr = std::to_chars( buffer_start, buffer_end, v, radix );
if( tcr.ec == std::errc() ) {
s.resize( tcr.ptr - s.data() );
} else {
throw std::runtime_error( ""s + __func__ + " - std::to_chars failed." );
}
}
auto main() -> int
{
const int n = 10'000'000;
std::string text;
text.reserve( 10*n ); // Avoid (most of the) repeated dynamic
allocations.
for( int i = 1; i <= n; ++i ) {
append_to( text, i );
text += ' ';
}
printf( "text.size = %d\n", int( text.size() ) );
}
On 22/09/2021 13:17, Alf P. Steinbach wrote:
#include <stddef.h> // ptrdiff_t
#include <stdio.h> // printf, for the final output
using Size = ptrdiff_t;
#include <charconv> // std::to_chars
#include <limits> // std::numeric_limits
#include <string> // std::string
#include <stdexcept> // std::runtime_error
using namespace std::string_literals;
void append_to( std::string& s, const int v )
{
static const int radix = 10;
static const int max_int_digits =
std::numeric_limits<int>::digits10 + 1;
const Size original_size = s.size();
s.resize( original_size + max_int_digits + 1 ); // 1 for
possible sign.
using P_char = char*;
const P_char buffer_start = s.data() + original_size; >> const P_char buffer_end = s.data() + s.size();
const std::to_chars_result tcr = std::to_chars( buffer_start,
buffer_end, v, radix );
if( tcr.ec == std::errc() ) {
s.resize( tcr.ptr - s.data() );
} else {
throw std::runtime_error( ""s + __func__ + " - std::to_chars
failed." );
}
}
auto main() -> int
{
const int n = 10'000'000;
std::string text;
text.reserve( 10*n ); // Avoid (most of the) repeated
dynamic allocations.
for( int i = 1; i <= n; ++i ) {
append_to( text, i );
text += ' ';
}
printf( "text.size = %d\n", int( text.size() ) );
}
This fails rextester.com (doesn't know charconv); and my
g++/mingw/10.3.0, doesn't like converting const char to P_char.
If I use '-fpermissive' to get around that, then I get a timing of 0.56;
more than twice as fast was my earlier time. I think about 5 times as
fast as my dynamic code.
However, if you are going to write custom code, then I can do the same...
This is my script:
s ::= "" # ::= makes a mutable copy
for i to 10 million do
s +:= tostr(i)
s +:= ' '
od
println s.len
(It uses 64-bit ints which impact the int-to-text conversion, which is
not optimised for base-10.)
22.09.2021 13:59 Bart kirjutas:
On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
You learn something new every day. I'd never heard of itoa().
Apparently its
an ancient K&R function which didn't get included into the ANSI C
standard.
So what would be the shiny new alternative in C++?
std::to_string()
https://en.cppreference.com/w/cpp/string/basic_string/to_string
#include <iostream>
int main()
{ std::string s="";
char t[100];
for (int i=1; i<=10000000; ++i) {
s += itoa(i,t,10);
s += ' ';
}
std::cout << "S.size = " << s.size() << "\n";
}
Compiled as g++ -O2, this runs in 1.3 seconds on my machine. My script language might take only twice as long, but is much simpler and
quicker to write.
On 22 Sep 2021 14:18, Paavo Helde wrote:
22.09.2021 13:59 Bart kirjutas:
On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
You learn something new every day. I'd never heard of itoa().
Apparently its
an ancient K&R function which didn't get included into the ANSI C
standard.
So what would be the shiny new alternative in C++?
std::to_string()
https://en.cppreference.com/w/cpp/string/basic_string/to_string
Not fast and not locale-independent (it uses the C library's locale).
Better use C++17 `to_chars`, <url: >https://en.cppreference.com/w/cpp/utility/to_chars>.
I gave a more or less full example in reply to the same posting you
replied to.
On 22 Sep 2021 17:15, HorseyWorsey@the_stables.com wrote:
On Wed, 22 Sep 2021 16:16:57 +0200
"Alf P. Steinbach" <alf.p.steinbach@gmail.com> wrote:
On 22 Sep 2021 14:18, Paavo Helde wrote:
22.09.2021 13:59 Bart kirjutas:
On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
You learn something new every day. I'd never heard of itoa().
Apparently its
an ancient K&R function which didn't get included into the ANSI C
standard.
So what would be the shiny new alternative in C++?
std::to_string()
https://en.cppreference.com/w/cpp/string/basic_string/to_string
Not fast and not locale-independent (it uses the C library's locale).
Better use C++17 `to_chars`, <url:
https://en.cppreference.com/w/cpp/utility/to_chars>.
I gave a more or less full example in reply to the same posting you
replied to.
Because a 20 line user function just to convert a number into a string is
soooo efficient.
But then someone who writes "auto main() -> int" instead of "int main()"
and then forgets the return value at the end anyway is probably not someone >> who writes sensible code.
Attempt to troll someone else, please.
On Wed, 22 Sep 2021 16:16:57 +0200
"Alf P. Steinbach" <alf.p.steinbach@gmail.com> wrote:
On 22 Sep 2021 14:18, Paavo Helde wrote:
22.09.2021 13:59 Bart kirjutas:
On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
You learn something new every day. I'd never heard of itoa().
Apparently its
an ancient K&R function which didn't get included into the ANSI C
standard.
So what would be the shiny new alternative in C++?
std::to_string()
https://en.cppreference.com/w/cpp/string/basic_string/to_string
Not fast and not locale-independent (it uses the C library's locale).
Better use C++17 `to_chars`, <url:
https://en.cppreference.com/w/cpp/utility/to_chars>.
I gave a more or less full example in reply to the same posting you
replied to.
Because a 20 line user function just to convert a number into a string is soooo efficient.
But then someone who writes "auto main() -> int" instead of "int main()"
and then forgets the return value at the end anyway is probably not someone who writes sensible code.
On 22 Sep 2021 14:18, Paavo Helde wrote:
22.09.2021 13:59 Bart kirjutas:
On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
You learn something new every day. I'd never heard of itoa().
Apparently its
an ancient K&R function which didn't get included into the ANSI C
standard.
So what would be the shiny new alternative in C++?
std::to_string()
https://en.cppreference.com/w/cpp/string/basic_string/to_string
Not fast and not locale-independent (it uses the C library's locale).
Better use C++17 `to_chars`, <url: https://en.cppreference.com/w/cpp/utility/to_chars>.
I gave a more or less full example in reply to the same posting you
replied to.
But then someone who writes "auto main() -> int" instead of "int main()"
and then forgets the return value at the end anyway is probably not someone who writes sensible code.
On 9/20/2021 6:08 PM, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be
natively supported by the core language. Then it can be kept streamlined >>> without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
Actually this view was (and still is) shared by the creators of C and of
C++.
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be
natively supported by the core language. Then it can be kept streamlined
without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
22.09.2021 13:59 Bart kirjutas:
So what would be the shiny new alternative in C++?std::to_string()
https://en.cppreference.com/w/cpp/string/basic_string/to_string
On 9/20/2021 6:08 PM, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be
natively supported by the core language. Then it can be kept streamlined >>> without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
Actually this view was (and still is) shared by the creators of C and of
C++.
In fact, that is the only reason (every language should have it as an unavoidable axiom) that I can see for C to have a function like printf:
as a systems language, you don't need formatting support, you just need
the ability to send chars to some device.
But, since it is such a widely spread convenience, they decided to put something in the standard library.
C++ tried to improve with iostreams, it was a genuine attempt, but the
result proved unpleasant.
(In other words, string formatting is properly a UI feature, so if you seriously need it, get some serious UI library, which has intentionally
been left out of C and C++; or, if you have specific and limited needs,
write it yourself)
The key point is the word "basic" in Bart's sentence - it is the same as "easy to use", what does it mean?
Definitions like this are obviously subjective, and they're a sure path
to disagreement.
On 22/09/2021 22:45, Manfred wrote:
On 9/20/2021 6:08 PM, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be
natively supported by the core language. Then it can be kept streamlined >>>> without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
Actually this view was (and still is) shared by the creators of C and of
C++.
In fact, that is the only reason (every language should have it as an
unavoidable axiom) that I can see for C to have a function like printf:
as a systems language, you don't need formatting support, you just need
the ability to send chars to some device.
But, since it is such a widely spread convenience, they decided to put
something in the standard library.
C++ tried to improve with iostreams, it was a genuine attempt, but the
result proved unpleasant.
(In other words, string formatting is properly a UI feature, so if you
seriously need it, get some serious UI library, which has intentionally
been left out of C and C++; or, if you have specific and limited needs,
write it yourself)
The key point is the word "basic" in Bart's sentence - it is the same as
"easy to use", what does it mean?
Definitions like this are obviously subjective, and they're a sure path
to disagreement.
The first languages I used all had a version of PRINT, needed as the
primary display device was a teletype or VDU, but you also needed to
write to text files (Algol, Fortran, Pascal; even assembly could do it!)
So I find it difficult to get away from the idea that PRINT is anything
but a fundamental feature of a language. Even though applications may
work primarily with a GUI, or without a UI at all. Such an app may still
need to write out a config file ...
... or read one in. Which brings me to something that hasn't been
discussed: basic READ.
This was something that was so easy in the 1970s, and now so hard;
except in my own languages where I keep it simple:
int a, b, c
print "Prompt> "
readln a, b, c
println a, b, c
I tried it in C++ to see how well it coped:
#include <iostream>
int main()
{ int a,b,c;
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
}
(Just look at that last line; 15 tokens and 35 sig. characters; compare
my 6 tokens and 12 characters...)
Anyway, this was quite poor:
* It doesn't like commas as separators as well as spaces
* If less than 3 numbers are present, it keeps waiting for me to enter
them on a subsequent line; very unfriendly
* If more than 3 are entered, those extra ones are not ignored; on the
next Prompt, those ones form the first part of the input of the new
line, very confusing. This input is supposed to be LINE ORIENTED.
* If I enter 12.34 56 78, it reads 12 for the first number, and zeros
for the next two, and apparently zeros also for all subsequent lines
None of those problems appear in mine:
* It reads at most 3 numbers from the line
* If fewer are present, it'll read them as zeros
* If more, they are ignored. Whatever is entered on one line NEVER/what if that is not desired behavior? it is not clear from code.
impinges on the next
* Numbers can be separated with commas or spaces
* Entering 12.34 56 78 is well behaved; it reads 12 56 78
There are some weaknesses in my static language version, but most are
fixed in my dynamic version (same code, but no 'int a,b,c'):
* A print item is read as int, float, string or bignum according to what
is entered
* Missing items are read as ""
* A type can be forced if needed
READ is intended as a casual feature to quickly and informally read such input from a console or file. But it's amazing how accomplished it is compared with major languages.
I'm sure C++ is also capable of the same things, but how much effort is
it? Do you have to do everything yourself? Maybe there's a Boost library
to do what used to be one line of code with Algol60.
My first programs were student exercises. Then, getting the 3 numbers
the task demanded was the easy bit!
On Wednesday, September 22, 2021 at 8:18:27 AM UTC-4, Paavo Helde wrote:
22.09.2021 13:59 Bart kirjutas:
std::to_string()
So what would be the shiny new alternative in C++?
https://en.cppreference.com/w/cpp/string/basic_string/to_string
Strange that in a language that's supposed to support genericity and
user provided allocators, we have these things that support neither genericity or user provided allocators.
It seems to me that you come from a world of programming language design
that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If you need to use sprintf() C, then that's when you might also consider using sprint() elsewhere.
Having to overload "<<", as I assume you meant, as you seemed to imply
that was better/easier than doing whatever it was to obj to allow its
use in function syntax.
So what's the alternative that you suggest?
Overloading whatever 'tostring' operations that are implicitly used when printing.
OK, let's try it. Here's a program that writes 1 million lines of the
same 3 variables:
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>> that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every
custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
[...]
But then someone who writes "auto main() -> int" instead of "int main()"
and then forgets the return value at the end anyway is probably not someone >> who writes sensible code.
Were you not aware that reaching the closing "}" of main() does an
implicit "return 0;"?
23.09.2021 10:31 Juha Nieminen kirjutas:
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>>> that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every
custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
And how is it better to force every custom type to add support for std::ostream streaming? At least one can easily add formatting
parameters to tostring() functions, with streams it becomes complicated
and hidden.
On 23/09/2021 03:03, Branimir Maksimovic wrote:
On 2021-09-22, Bart <bc@freeuk.com> wrote:
This was something that was so easy in the 1970s, and now so hard;Same thing.
except in my own languages where I keep it simple:
int a, b, c
print "Prompt> "
readln a, b, c
println a, b, c
I tried it in C++ to see how well it coped:
#include <iostream>
int main()
{ int a,b,c;
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
}
But there is bug if user enters more or less then three. How you handle
that case?
How do you handle it in C++? There, if the user enters less than 3,
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>> that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every
custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
If you need to use sprintf() C, then that's when you might also consider
using sprint() elsewhere.
sprintf() cannot be extended to support your own custom types.
On 2021-09-22, Bart <bc@freeuk.com> wrote:
This was something that was so easy in the 1970s, and now so hard;Same thing.
except in my own languages where I keep it simple:
int a, b, c
print "Prompt> "
readln a, b, c
println a, b, c
I tried it in C++ to see how well it coped:
#include <iostream>
int main()
{ int a,b,c;
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
}
But there is bug if user enters more or less then three. How you handle
that case?
In Swift:
let values = readLine()?.components(separatedBy: CharacterSet.whitespacesAndNewlines) ?? []
let valueOne = values.count > 0 ? Int(values[0]) : nil
let valueTwo = values.count > 1 ? Int(values[1]) : nil
so this handles correct.
* If more, they are ignored. Whatever is entered on one line NEVER/what if that is not desired behavior? it is not clear from code.
Don't do things behind peoples backs.
On 23/09/2021 03:03, Branimir Maksimovic wrote:
On 2021-09-22, Bart <bc@freeuk.com> wrote:
This was something that was so easy in the 1970s, and now so hard;Same thing.
except in my own languages where I keep it simple:
int a, b, c
print "Prompt> "
readln a, b, c
println a, b, c
I tried it in C++ to see how well it coped:
#include <iostream>
int main()
{ int a,b,c;
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
}
But there is bug if user enters more or less then three. How you handle
that case?
How do you handle it in C++? There, if the user enters less than 3,
nothing happens: the program apparenty hangs (waiting for more input).
If more than 3, it doesn't detect that either, until mysterious things
start happening on the next line.
If you put my example into a loop, then for inputs of:
10 20 30 40 50
100 200 300 400 500
where the user expects to see outputs of:
10 20 30
100 200 300
they will in fact see, after entering only 2 lines:
10 20 30
40 50 100
plus 200 300 400 as the output of a 3rd line that they haven't even
entered! Then '500' will figure as the first number of the next line.
It's missing an important thing: the ability to synchronise to each
fresh line of input.
In my version, there are a number of checks that can be made; missing
items are zero. Error flags are set and can be accessed by special reads:
read x:'E'
but which need to be done after item (I'd need to look into my code, as
I never bother for the casual use this is put to). In the dynamic
version, missing items are set to "", so you can check the type.
But you don't have to worry about input from multiple lines being
jumbled up an
On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
On Thu, 23 Sep 2021 11:18:02 +0100
Bart <bc@freeuk.com> wrote:
On 23/09/2021 03:03, Branimir Maksimovic wrote:
On 2021-09-22, Bart <bc@freeuk.com> wrote:
This was something that was so easy in the 1970s, and now so hard;Same thing.
except in my own languages where I keep it simple:
int a, b, c
print "Prompt> "
readln a, b, c
println a, b, c
I tried it in C++ to see how well it coped:
#include <iostream>
int main()
{ int a,b,c;
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
}
But there is bug if user enters more or less then three. How you handle >>>> that case?
How do you handle it in C++? There, if the user enters less than 3,
You read in the entire line then split it up into tokens using
whatever method
takes your fancy.
Example?
My original point was for a language to provide ready means to do /line-oriented/ input.
You're saying each programmer needs to reinvent this stuff?
I've tested my version some more (still trying to read 3 integers):
Input Output of my code Output of C++ code:
"10" 20 30 10 20 30 Continuous zeros
123'456 7 8 123456 7 8 123 then myriad zeros
123_456 7 8 123456 7 8 Same
.1234 5 6 0 5 6 Same
On Thu, 23 Sep 2021 11:18:02 +0100
Bart <bc@freeuk.com> wrote:
On 23/09/2021 03:03, Branimir Maksimovic wrote:
On 2021-09-22, Bart <bc@freeuk.com> wrote:
This was something that was so easy in the 1970s, and now so hard;Same thing.
except in my own languages where I keep it simple:
int a, b, c
print "Prompt> "
readln a, b, c
println a, b, c
I tried it in C++ to see how well it coped:
#include <iostream>
int main()
{ int a,b,c;
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
}
But there is bug if user enters more or less then three. How you handle
that case?
How do you handle it in C++? There, if the user enters less than 3,
You read in the entire line then split it up into tokens using whatever method
takes your fancy.
On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
On Thu, 23 Sep 2021 11:18:02 +0100
Bart <bc@freeuk.com> wrote:
On 23/09/2021 03:03, Branimir Maksimovic wrote:
On 2021-09-22, Bart <bc@freeuk.com> wrote:
This was something that was so easy in the 1970s, and now so hard;Same thing.
except in my own languages where I keep it simple:
int a, b, c
print "Prompt> "
readln a, b, c
println a, b, c
I tried it in C++ to see how well it coped:
#include <iostream>
int main()
{ int a,b,c;
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
}
But there is bug if user enters more or less then three. How you handle >>>> that case?
How do you handle it in C++? There, if the user enters less than 3,
You read in the entire line then split it up into tokens using
whatever method
takes your fancy.
Example?
My original point was for a language to provide ready means to do /line-oriented/ input.
You're saying each programmer needs to reinvent this stuff?
I've tested my version some more (still trying to read 3 integers):
Input Output of my code Output of C++ code:
"10" 20 30 10 20 30 Continuous zeros 123'456 7 8 123456 7 8 123 then myriad zeros
123_456 7 8 123456 7 8 Same
.1234 5 6 0 5 6 Same
-1234 5 6 -1234 5 6 -1234 5 6 (A miracle!)
123e4 5 6 123 5 6 Goes crazy like above
10,20,30 10 20 30 Goes crazy 10+20+30 10 0 0 10 20 30 10 10 0 0 Waits for more input
19000000000000000000 3 4
wrong val 3 4 i32.max then goes crazy
Mine could be improved; but the C++ definitely needs some attention.
7/10 and 3/10 respectively I think!
On 9/20/2021 6:08 PM, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be
natively supported by the core language. Then it can be kept streamlined >>> without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
Actually this view was (and still is) shared by the creators of C and of
C++.
In fact, that is the only reason (every language should have it as an >unavoidable axiom) that I can see for C to have a function like printf:
as a systems language, you don't need formatting support, you just need
the ability to send chars to some device.
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>> that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every
custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
If you need to use sprintf() C, then that's when you might also consider
using sprint() elsewhere.
sprintf() cannot be extended to support your own custom types.
On 9/23/21 7:21 AM, Bart wrote:
How do you handle it in C++? There, if the user enters less than 3,
You read in the entire line then split it up into tokens using
whatever method
takes your fancy.
Example?
My original point was for a language to provide ready means to do
/line-oriented/ input.
Then use line oriented processing. That would be gets (or maybe better
fgets to avoid overrun attacks) to get the line, and then parse with the method you want, sscanf if you can deal with the default error handling.
C++ has similar functions for streams.
On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
You read in the entire line then split it up into tokens using whatever >method
takes your fancy.
Example?
My original point was for a language to provide ready means to do >/line-oriented/ input.
You're saying each programmer needs to reinvent this stuff?
Input Output of my code Output of C++ code:
"10" 20 30 10 20 30 Continuous zeros
123'456 7 8 123456 7 8 123 then myriad zeros
123_456 7 8 123456 7 8 Same
.1234 5 6 0 5 6 Same
-1234 5 6 -1234 5 6 -1234 5 6 (A miracle!)
123e4 5 6 123 5 6 Goes crazy like above
10,20,30 10 20 30 Goes crazy
10+20+30 10 0 0 10 20 30
10 10 0 0 Waits for more input
19000000000000000000 3 4
wrong val 3 4 i32.max then goes crazy
Mine could be improved; but the C++ definitely needs some attention.
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
Juha Nieminen <nospam@thanks.invalid> writes:+1
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>>> that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every >>custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
If you need to use sprintf() C, then that's when you might also consider >>> using sprint() elsewhere.
sprintf() cannot be extended to support your own custom types.
Please. Competent C programmers eschew sprintf. It's dangerous and
should be deprecated.
snprintf is bounded and far safer than sprintf.
Manfred <noname@add.invalid> writes:
On 9/20/2021 6:08 PM, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be
natively supported by the core language. Then it can be kept streamlined >>>> without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
Actually this view was (and still is) shared by the creators of C and of
C++.
In fact, that is the only reason (every language should have it as an
unavoidable axiom) that I can see for C to have a function like printf:
as a systems language, you don't need formatting support, you just need
the ability to send chars to some device.
As someone who has been crafting operating systems for over forty
years from mainframes to 5G base stations, your assertion is complete nonsense.
On Thu, 23 Sep 2021 12:21:48 +0100
Bart <bc@freeuk.com> wrote:
On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
You read in the entire line then split it up into tokens using whatevermethod
takes your fancy.
Example?
My original point was for a language to provide ready means to do
/line-oriented/ input.
You're saying each programmer needs to reinvent this stuff?
Its not exactly rocket science. C++ isn't and isn't intended to be a hand holding scripting language, some things you have to know how to do yourself.
Input Output of my code Output of C++ code:
"10" 20 30 10 20 30 Continuous zeros
123'456 7 8 123456 7 8 123 then myriad zeros
123_456 7 8 123456 7 8 Same
.1234 5 6 0 5 6 Same
-1234 5 6 -1234 5 6 -1234 5 6 (A miracle!)
123e4 5 6 123 5 6 Goes crazy like above
10,20,30 10 20 30 Goes crazy
10+20+30 10 0 0 10 20 30
10 10 0 0 Waits for more input
19000000000000000000 3 4
wrong val 3 4 i32.max then goes crazy
Mine could be improved; but the C++ definitely needs some attention.
C++ cin is as useless as C's scanf() for doing actual real world stdin input processing. Unless the users follows the expected format then it all blows up.
As I said, you read in the entire string then parse it using std::string find()
and substr() or C's strtok() or even raw pointers. Either way an experienced programmer should take longer than 20 mins to come up with something.
On Wed, 22 Sep 2021 14:13:39 -0700...
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
That hasn't been true since C99, 22 years ago, and that's the sameWere you not aware that reaching the closing "}" of main() does an
implicit "return 0;"?
And in C function return types default to int ...
On 22/09/2021 23:45, Manfred wrote:
On 9/20/2021 6:08 PM, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be
natively supported by the core language. Then it can be kept streamlined >>>> without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
Actually this view was (and still is) shared by the creators of C and of
C++.
It is not part of the core language. It is part of the standard
library. That's a very different thing. In particular, the great
majority of printf implementations are written in C, the great majority
of iostream implementations are written in C++.
(Implementation-specific behaviour might be needed.) Printing is not a special statement in either language - it is handled by library
functions that are optional (small embedded systems often don't use
them, for example), and can be replaced by alternatives.
On 23/09/2021 15:58, HorseyWorsey@the_stables.com wrote:
Its not exactly rocket science. C++ isn't and isn't intended to be a hand
holding scripting language, some things you have to know how to do yourself.
I usually devise my own languages, including those for systems programming.
Is that the attitude here, that such fundamental features are to be
looked down upon because they would make life too easy?
As I said, you read in the entire string then parse it using std::string >find()
and substr() or C's strtok() or even raw pointers. Either way an experienced >> programmer should take longer than 20 mins to come up with something.
In other words, a million programmers have to keep reinventing the same >thing. Or a million variations of the same thing.
On 9/23/2021 4:04 PM, Scott Lurndal wrote:
Manfred <noname@add.invalid> writes:
On 9/20/2021 6:08 PM, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be >>>>> natively supported by the core language. Then it can be kept streamlined >>>>> without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of
many other people.
Actually this view was (and still is) shared by the creators of C and of >>> C++.
In fact, that is the only reason (every language should have it as an
unavoidable axiom) that I can see for C to have a function like printf:
as a systems language, you don't need formatting support, you just need
the ability to send chars to some device.
As someone who has been crafting operating systems for over forty
years from mainframes to 5G base stations, your assertion is complete nonsense.
Thanks for the "nonsense" label.
Just for the record, David Brown has just confirmed that printing (aka >formatting in this context) is an "optional" library feature, that is in
fact often /not/ used in some types of systems.
Will you please come to an agreement before insulting me?
On 9/23/2021 4:04 PM, Scott Lurndal wrote:
Manfred <noname@add.invalid> writes:
In fact, that is the only reason (every language should have it as an
unavoidable axiom) that I can see for C to have a function like printf:
as a systems language, you don't need formatting support, you just need
the ability to send chars to some device.
As someone who has been crafting operating systems for over forty
years from mainframes to 5G base stations, your assertion is complete nonsense.
Thanks for the "nonsense" label.
Just for the record, David Brown has just confirmed that printing (aka >formatting in this context) is an "optional" library feature, that is in
fact often /not/ used in some types of systems.
Manfred <noname@add.invalid> writes:
On 9/23/2021 4:04 PM, Scott Lurndal wrote:
Manfred <noname@add.invalid> writes:
In fact, that is the only reason (every language should have it as an
unavoidable axiom) that I can see for C to have a function like printf: >>>> as a systems language, you don't need formatting support, you just need >>>> the ability to send chars to some device.
As someone who has been crafting operating systems for over forty
years from mainframes to 5G base stations, your assertion is complete nonsense.
Thanks for the "nonsense" label.
Just for the record, David Brown has just confirmed that printing (aka
formatting in this context) is an "optional" library feature, that is in
fact often /not/ used in some types of systems.
You wrote:
as a systems language, you don't need formatting support
Which is complete nonsense. I stand by my assertion.
On Thu, 23 Sep 2021 17:02:36 +0100
Bart <bc@freeuk.com> wrote:
On 23/09/2021 15:58, HorseyWorsey@the_stables.com wrote:
Its not exactly rocket science. C++ isn't and isn't intended to be a hand >>> holding scripting language, some things you have to know how to do yourself.
I usually devise my own languages, including those for systems programming.
Clever you.
Is that the attitude here, that such fundamental features are to be
looked down upon because they would make life too easy?
Your attitude seems to be "C++ doesn't do what I want therefore its crap". C++ is what it is. If you don't like it use another language, you have plenty to choose from including your own.
As I said, you read in the entire string then parse it using std::stringfind()
and substr() or C's strtok() or even raw pointers. Either way an experienced
programmer should take longer than 20 mins to come up with something.
In other words, a million programmers have to keep reinventing the same
thing. Or a million variations of the same thing.
Since a basic line splitter is easy for any half competant programmer and anything more complex - ie a parser - is usually tuned for a particular need what would be the point? C++ has already had the kitchen sink thrown into it because of people like you yet you want even basic stuff done for you?
next , concatenation too hard? Perhaps a built in function that automatically concats a vector of strings for you? Maybe you'd be better off using javascript.
On Wed, 22 Sep 2021 14:13:39 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
HorseyWorsey@the_stables.com writes:
[...]
But then someone who writes "auto main() -> int" instead of "int main()" >>> and then forgets the return value at the end anyway is probably not someone >>> who writes sensible code.
Were you not aware that reaching the closing "}" of main() does an
implicit "return 0;"?
And in C function return types default to int so perhaps for int functions
we shouldn't bother to specify the types?
Whats your point? If he decides
to be a smartarse by using that syntax you'd think he'd dot all the i's etc.
On 9/22/2021 11:51 PM, David Brown wrote:
On 22/09/2021 23:45, Manfred wrote:
On 9/20/2021 6:08 PM, David Brown wrote:
On 20/09/2021 17:11, Bart wrote:<snip>
My view is that basic Print is a fundamental feature that needs to be >>>>> natively supported by the core language. Then it can be kept
streamlined
without wasting too much compiler time on it.
That's your view. It is not unique to you, but it is not the view of >>>> many other people.
Actually this view was (and still is) shared by the creators of C and of >>> C++.
It is not part of the core language. It is part of the standard
library. That's a very different thing. In particular, the great
majority of printf implementations are written in C, the great majority
of iostream implementations are written in C++.
(Implementation-specific behaviour might be needed.) Printing is not a
special statement in either language - it is handled by library
functions that are optional (small embedded systems often don't use
them, for example), and can be replaced by alternatives.
Agreed.
My point is about having it in the language as in the "language specification", which includes the standard library, a broader sense
than yours.
It appears that we agree that printing support (or formatting, as I
wrote afterwards) is not strictly needed from the language as long as it offers the means, if you need it, to build or integrate alternatives according to your needs.
On 23/09/2021 13:05, Richard Damon wrote:
On 9/23/21 7:21 AM, Bart wrote:
How do you handle it in C++? There, if the user enters less than 3,
You read in the entire line then split it up into tokens using
whatever method
takes your fancy.
Example?
My original point was for a language to provide ready means to do
/line-oriented/ input.
Then use line oriented processing. That would be gets (or maybe better
fgets to avoid overrun attacks) to get the line, and then parse with the
method you want, sscanf if you can deal with the default error handling.
C++ has similar functions for streams.
So it /doesn't/ support line-oriented input unless you implement it
yourself. /That/ is my complaint.
This is a similar example in Basic:
for i=1 to 3
print "Prompt> "; rem ";" suppresses the newline
input a,b,c rem I think this grabs a fresh line
print a,b,c
next i
It works better than the C++! And better than C's scanf which everyone
tries to avoid using.
On 9/23/2021 7:08 PM, Scott Lurndal wrote:
Manfred <noname@add.invalid> writes:
On 9/23/2021 4:04 PM, Scott Lurndal wrote:
Manfred <noname@add.invalid> writes:
In fact, that is the only reason (every language should have it as an >>>>> unavoidable axiom) that I can see for C to have a function like printf: >>>>> as a systems language, you don't need formatting support, you just need >>>>> the ability to send chars to some device.
As someone who has been crafting operating systems for over forty
years from mainframes to 5G base stations, your assertion is complete nonsense.
Thanks for the "nonsense" label.
Just for the record, David Brown has just confirmed that printing (aka
formatting in this context) is an "optional" library feature, that is in >>> fact often /not/ used in some types of systems.
You wrote:
as a systems language, you don't need formatting support
Which is complete nonsense. I stand by my assertion.
Maybe we refer to different meanings of formatting in this context, or whatever.
I find it really hard to try and reason with such an insulting attitude.
Have it your way.
Paavo Helde <myfirstname@osa.pri.ee> wrote:
23.09.2021 10:31 Juha Nieminen kirjutas:
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>>>> that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every
custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
And how is it better to force every custom type to add support for
std::ostream streaming? At least one can easily add formatting
parameters to tostring() functions, with streams it becomes complicated
and hidden.
So, what's *your* suggested alternative?
(One could suggest std::format(), but AFAIK that's not going to be enormously more efficient either. It's more of a convenience thing than an efficiency thing.)
Whatever your suggestion may be, it would be nice if it could be used in generic code, without much hassle. In other words, being able to do this
kind of thing:
template<typename T>
void foobar(int value, const T& obj)
{
std::cout << "With value " << value << " we got:\n" << obj << "\n";
}
Preferably whatever the solution is, it shouldn't require the type
to dynamically construct a string to be printed, and instead the
type should get an std::ostream (or FILE*, or whatever) that it
can use to directly write whatever it wants there.
On 24/09/2021 02:02, Bart wrote:
On 23/09/2021 13:05, Richard Damon wrote:
On 9/23/21 7:21 AM, Bart wrote:
How do you handle it in C++? There, if the user enters less than 3, >>>>>You read in the entire line then split it up into tokens using
whatever method
takes your fancy.
Example?
My original point was for a language to provide ready means to do
/line-oriented/ input.
Then use line oriented processing. That would be gets (or maybe better
fgets to avoid overrun attacks) to get the line, and then parse with the >>> method you want, sscanf if you can deal with the default error handling. >>>
C++ has similar functions for streams.
So it /doesn't/ support line-oriented input unless you implement it
yourself. /That/ is my complaint.
This is a similar example in Basic:
for i=1 to 3
print "Prompt> "; rem ";" suppresses the newline >> input a,b,c rem I think this grabs a fresh line
print a,b,c
next i
It works better than the C++! And better than C's scanf which everyone
tries to avoid using.
How is that fundamentally different from
for( int i = 0; i < 3; ++i )
{
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << ' ' << b << ' ' << c << '\n';
}
?
On 23/09/2021 21:48, Ian Collins wrote:[...]
On 24/09/2021 02:02, Bart wrote:
This is a similar example in Basic:How is that fundamentally different from
for i=1 to 3
print "Prompt> "; rem ";" suppresses the newline >>> input a,b,c rem I think this grabs a fresh line
print a,b,c
next i
It works better than the C++! And better than C's scanf which everyone
tries to avoid using.
for( int i = 0; i < 3; ++i )
{
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << ' ' << b << ' ' << c << '\n';
}
?
Haven't you followed the thread? A lot of things have been pointed
out. But here's a summary of issues with the C++ loop:
* It's not line-oriented; the new lines get out of sync with the data
being read
* If fewer than 3 items are present on a line, then it apparently
hangs, with no explanation, waiting for them on the next line
* If more than 3 items are present on a line, then those aren't
discarded, but are confusingly used as input for a, b, c for the
next line. So if 400 and 500 are extra items, and the user enters 10
20 30 on the next line, if will read '400 500 10', with 20 and 30
rolled over to the subsequent line
* If more than 3 extra items are present, then on the next iteration,
it doesn't wait for user input at all. If will not do so until
everything on that initial line is consumed
* Numeric separators within numbers such as "_" and "'" are not
recognised, and cause an error
* Numbers which are quoted are not recognised, and cause an error
* Separators between numbers other than white space are not
recognised, such as commas, and cause an error
* Floating point numbers (using "." and/or "e") are not recognised;
those characters cause an error
* When an out-of-range number is entered, it reads i32.max (etc) for
that number, but also generates an error
* I mentioned error a few times, when that happens, it goes crazy. I
think the internal pointer is not stepped past it, and it just reads
zeros, so it never consumes the rest of the line. So in a loop, it
just prints zeros over and over again without the user entering
anything.
On 23/09/2021 21:48, Ian Collins wrote:
On 24/09/2021 02:02, Bart wrote:
On 23/09/2021 13:05, Richard Damon wrote:
On 9/23/21 7:21 AM, Bart wrote:
How do you handle it in C++? There, if the user enters less than 3, >>>>>>You read in the entire line then split it up into tokens using
whatever method
takes your fancy.
Example?
My original point was for a language to provide ready means to do
/line-oriented/ input.
Then use line oriented processing. That would be gets (or maybe better >>>> fgets to avoid overrun attacks) to get the line, and then parse with the >>>> method you want, sscanf if you can deal with the default error handling. >>>>
C++ has similar functions for streams.
So it /doesn't/ support line-oriented input unless you implement it
yourself. /That/ is my complaint.
This is a similar example in Basic:
for i=1 to 3
print "Prompt> "; rem ";" suppresses the newline >>> input a,b,c rem I think this grabs a fresh line
print a,b,c
next i
It works better than the C++! And better than C's scanf which everyone
tries to avoid using.
How is that fundamentally different from
for( int i = 0; i < 3; ++i )
{
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << ' ' << b << ' ' << c << '\n';
}
?
Haven't you followed the thread? A lot of things have been pointed out.
But here's a summary of issues with the C++ loop:
* It's not line-oriented; the new lines get out of sync with the datastreams are for serialization, getline is for user input.
being read
* If fewer than 3 items are present on a line, then it apparently hangs,
with no explanation, waiting for them on the next line
* If more than 3 items are present on a line, then those aren't
discarded, but are confusingly used as input for a, b, c for the next
line. So if 400 and 500 are extra items, and the user enters 10 20 30 on
the next line, if will read '400 500 10', with 20 and 30 rolled over to
the subsequent line
* If more than 3 extra items are present, then on the next iteration, it doesn't wait for user input at all. If will not do so until everything
on that initial line is consumed
* Numeric separators within numbers such as "_" and "'" are not
recognised, and cause an error
* Numbers which are quoted are not recognised, and cause an error
* Separators between numbers other than white space are not recognised,
such as commas, and cause an error
* Floating point numbers (using "." and/or "e") are not recognised;
those characters cause an error
* When an out-of-range number is entered, it reads i32.max (etc) for
that number, but also genera
Bart <bc@freeuk.com> writes:
* It's not line-oriented; the new lines get out of sync with the data
being read
Right, it's not designed to be. For example:
int a, b, c;
std::cin >> a >> b >> c;
std::cout << "a=" << a << " b=" << b << " c=" << c << '\n';
The std::cin line reads integer values, skipping white space (which
includes newlines) before each. If you just want to skip white space
other than newlines, there's probably a way to do that.
If you want line-oriented input, read a line at a time using
std::getline() and then parse each line. It's not that hard.
std::string line;
std::getline(std::cin, line);
std::stringstream ss(line);
ss >> a >> b >> c;
* If fewer than 3 items are present on a line, then it apparently
hangs, with no explanation, waiting for them on the next line
Because it's not line-oriented.
Because it's not line-oriented.
Because it's not line-oriented.
* Numeric separators within numbers such as "_" and "'" are not
recognised, and cause an error
Right. Just how permissive do you think it should be?
* Numbers which are quoted are not recognised, and cause an error
Right. 123 is a number; "123", “123”, '123', and «123» are not.
* When an out-of-range number is entered, it reads i32.max (etc) for
that number, but also generates an error
Yes, and?
* I mentioned error a few times, when that happens, it goes crazy. I
think the internal pointer is not stepped past it, and it just reads
zeros, so it never consumes the rest of the line. So in a loop, it
just prints zeros over and over again without the user entering
anything.
It's difficult to respond to that without an example.
On 24/09/2021 00:56, Keith Thompson wrote:
Bart <bc@freeuk.com> writes:
* It's not line-oriented; the new lines get out of sync with the data
being read
Right, it's not designed to be. For example:
int a, b, c;
std::cin >> a >> b >> c;
std::cout << "a=" << a << " b=" << b << " c=" << c << '\n';
The std::cin line reads integer values, skipping white space (which
includes newlines) before each. If you just want to skip white space
other than newlines, there's probably a way to do that.
If you want line-oriented input, read a line at a time using
std::getline() and then parse each line. It's not that hard.
std::string line;
std::getline(std::cin, line);
std::stringstream ss(line);
ss >> a >> b >> c;
Thanks at last somebody posted some actual code instead of just saying
how easy it was. But a couple of things:
* (It needs #include <sstream>)
* If I put this in my loop, and type 10 20 30 on the first line, it
prints 10 20 30; that's fine.
* But if I type only 40 on the next line, it prints 40 20 30. So if
there are fewer entries than expected, it will not do '>> b >> c'; those values are unchanged from before.
* It's better behaved as it doesn't try to exhaust the same line over
again. But if the input is '10.2 11 12', the output is '10 0 999'. (The
999 is what I've now initialised a,b,c to at the start of each loop.)
* If fewer than 3 items are present on a line, then it apparently
hangs, with no explanation, waiting for them on the next line
Because it's not line-oriented.
Because it's not line-oriented.
Because it's not line-oriented.
Isn't that what I said?
* Numeric separators within numbers such as "_" and "'" are not
recognised, and cause an error
Right. Just how permissive do you think it should be?
For interactive user input - quite permissive. People are quite likely
to type in decimal points or do unexpected things. A full treatment is
hard, but if someone types "100." or 1e2 instead of "100", should that
be a hanging offence?
* Numbers which are quoted are not recognised, and cause an error
Right. 123 is a number; "123", “123”, '123', and «123» are not.
If you are reading CSV files and such, fields are sometimes enclosed in quotes, including numeric fields.
* When an out-of-range number is entered, it reads i32.max (etc) for
that number, but also generates an error
Yes, and?
That error is the problem.
* I mentioned error a few times, when that happens, it goes crazy. I
think the internal pointer is not stepped past it, and it just reads
zeros, so it never consumes the rest of the line. So in a loop, it
just prints zeros over and over again without the user entering
anything.
It's difficult to respond to that without an example.
I thought I posted it earlier. Here's the code:
#include <iostream>
int main()
{ int a,b,c;
int x=0;
do {
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
} while (++x<10);
}
And here it is in action; the only input I type in is the '10.2 11 12'
line, the rest just keeps going, and only stops because I cap the output
at 10 lines:
C:\c>a
Prompt> 10.2 11 12
10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
On 24/09/2021 00:56, Keith Thompson wrote:
Bart <bc@freeuk.com> writes:
* It's not line-oriented; the new lines get out of sync with the dataRight, it's not designed to be. For example:
being read
int a, b, c;
std::cin >> a >> b >> c;
std::cout << "a=" << a << " b=" << b << " c=" << c << '\n';
The std::cin line reads integer values, skipping white space (which
includes newlines) before each. If you just want to skip white space
other than newlines, there's probably a way to do that.
If you want line-oriented input, read a line at a time using
std::getline() and then parse each line. It's not that hard.
std::string line;
std::getline(std::cin, line);
std::stringstream ss(line);
ss >> a >> b >> c;
Thanks at last somebody posted some actual code instead of just saying
how easy it was. But a couple of things:
* (It needs #include <sstream>)
* If I put this in my loop, and type 10 20 30 on the first line, it
prints 10 20 30; that's fine.
* But if I type only 40 on the next line, it prints 40 20 30. So if
there are fewer entries than expected, it will not do '>> b >> c';
those values are unchanged from before.
* It's better behaved as it doesn't try to exhaust the same line over
again. But if the input is '10.2 11 12', the output is '10 0
999'. (The 999 is what I've now initialised a,b,c to at the start of
each loop.)
* If fewer than 3 items are present on a line, then it apparentlyBecause it's not line-oriented.
hangs, with no explanation, waiting for them on the next line
Because it's not line-oriented.
Because it's not line-oriented.
Isn't that what I said?
* Numeric separators within numbers such as "_" and "'" are notRight. Just how permissive do you think it should be?
recognised, and cause an error
For interactive user input - quite permissive. People are quite likely
to type in decimal points or do unexpected things. A full treatment is
hard, but if someone types "100." or 1e2 instead of "100", should that
be a hanging offence?
* Numbers which are quoted are not recognised, and cause an errorRight. 123 is a number; "123", “123”, '123', and «123» are not.
If you are reading CSV files and such, fields are sometimes enclosed
in quotes, including numeric fields.
* When an out-of-range number is entered, it reads i32.max (etc) forYes, and?
that number, but also generates an error
That error is the problem.
* I mentioned error a few times, when that happens, it goes crazy. IIt's difficult to respond to that without an example.
think the internal pointer is not stepped past it, and it just reads
zeros, so it never consumes the rest of the line. So in a loop, it
just prints zeros over and over again without the user entering
anything.
I thought I posted it earlier. Here's the code:
#include <iostream>
int main()
{ int a,b,c;
int x=0;
do {
std::cout << "Prompt> ";
std::cin >> a >> b >> c;
std::cout << a << " " << b << " " << c << "\n";
} while (++x<10);
}
And here it is in action; the only input I type in is the '10.2 11 12'
line, the rest just keeps going, and only stops because I cap the
output at 10 lines:
C:\c>a
Prompt> 10.2 11 12
10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Prompt> 10 0 0
Preferably whatever the solution is, it shouldn't require the type
to dynamically construct a string to be printed, and instead the
type should get an std::ostream (or FILE*, or whatever) that it
can use to directly write whatever it wants there.
Why? Is this just because of memory overhead concerns?
On 23/09/2021 08:31, Juha Nieminen wrote:
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>>> that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every
custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
I'm not forcing anything at all. Custom types can have dedicated
tostring routines; or use default ones; or have nothing.
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Preferably whatever the solution is, it shouldn't require the type
to dynamically construct a string to be printed, and instead the
type should get an std::ostream (or FILE*, or whatever) that it
can use to directly write whatever it wants there.
Why? Is this just because of memory overhead concerns?
What is this sudden strange attitude of "efficiency doesn't matter"?
This is C++ we are talking about, not Python, or JavaScript, or PHP,
or a shell script.
The very reason why std::ostream uses operator overloading to become extensible to custom types is that it allows these custom types to
output their data in any way they want, using the std::ostream
object. If the custom type in question is a list of a million
objects, you don't need to allocate and construct a string
containing the textual representation of these million objects
In article <shvf4c$ark$3@gioia.aioe.org>,
alessandro volturno <alessandro.volturno@libero.it> wrote:
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
I'm working on an extension for erratic numbers, double precision
that fills add/subtract loss of signficance with random bits.
That will form a basis for happy numbers, sad numbers, and angry
numbers, and more generally, emotional numbers.
Il 23/09/2021 16:38, Siri Cruise ha scritto:
In article <shvf4c$ark$3@gioia.aioe.org>,
alessandro volturno <alessandro.volturno@libero.it> wrote:
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
I'm working on an extension for erratic numbers, double precision
that fills add/subtract loss of signficance with random bits.
That will form a basis for happy numbers, sad numbers, and angry
numbers, and more generally, emotional numbers.
I've never heard about erratic or emotional numbers. Is it a joke or a strange application in mathematical field?
Could you please give me an example of use, so to make understanding easier?
Thank you
On 23/09/2021 17:21, HorseyWorsey@the_stables.com wrote:
Since a basic line splitter is easy for any half competant programmer and
anything more complex - ie a parser - is usually tuned for a particular need >> what would be the point? C++ has already had the kitchen sink thrown into it >> because of people like you yet you want even basic stuff done for you?
This is the paradox: C++ has a lot of hugely complicated but neglects
the basics.
And it's just C++ but a lot of current languages, because they have
their focus elsewhere. (I especially know about Python.)
An effective basic Print (and Read) needs language support otherwise it >becomes a pain to use.
The support needed is not significant. My proof-of-concept to add
automatic printf format codes to a C compiler (so you do "%?" for any
basic type instead of "%d" etc), was 50 lines of code.
concats a vector of strings for you? Maybe you'd be better off using >javascript.
So. why bother with even std::cout (I still don't know what that
actually is) or printf? Just have fgetc and fputc.
After all how hard can it be to knock up an int-to-string converter? The
Il 23/09/2021 16:38, Siri Cruise ha scritto:
In article <shvf4c$ark$3@gioia.aioe.org>,
alessandro volturno <alessandro.volturno@libero.it> wrote:
why not to introduce a way to handle rational numbers inside the C++
standard or better make it a built in type?
I'm working on an extension for erratic numbers, double precision
that fills add/subtract loss of signficance with random bits.
That will form a basis for happy numbers, sad numbers, and angry
numbers, and more generally, emotional numbers.
I've never heard about erratic or emotional numbers. Is it a joke or a strange application in mathematical field?
Could you please give me an example of use, so to make understanding
easier?
I'm working on an extension for erratic numbers, double precision
that fills add/subtract loss of signficance with random bits.
That will form a basis for happy numbers, sad numbers, and angry
numbers, and more generally, emotional numbers.
I've never heard about erratic or emotional numbers. Is it a joke or a strange application in mathematical field?
Could you please give me an example of use, so to make understanding easier?
It is a joke. There are lucky numbers, perfect numbers, practical
numbers, fortunate numbers, untouchable numbers, weird numbers, polite numbers, and extravagant numbers. But no emotional numbers, that I am
aware of.
Scott Lurndal <scott@slp53.sl.home> wrote:
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
fprintf(stdout, "Value = %s\n" obj.to_string());
I don't really know how exactly you expect that to be possible in all cases. The returned const char* has to point somewhere. To something that will outlive the to_string() function itself, but will, if necessary, be destroyed after use (because in many cases you will need to create a dynamically allocated string in order to contain the textual representation of the value of the object you are trying to print).
On 22/09/2021 12:13, Ian Collins wrote:
On 22/09/2021 22:26, Bart wrote:
OK, let's try it. Here's a program that writes 1 million lines of the
same 3 variables:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
long long int a = 0x7FFFFFFFFFFFFFFF;
double b = 3.14159265359;
const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
myfile.open ("output");
for (int i=0; i<1000000; ++i) {
myfile << a << " " << b << " " << c << "\n";
}
myfile.close();
return 0;
}
On my machine, that took 4 seconds.
This will take roughly the time it takes to perform the file writing
(0.4S on my machine). The time spend formatting the output is
inconsequential in comparison.
But you don't know that? On my machine, timing went from 4.3 seconds to
5.3 seconds if I changed the output file from "output" to "nul"
(Windows' version of a null device, not a very effective one!).
I don't know how to isolate the file i/o from the conversion in C++. If
I switch to C *printf functions, then going from fprintf to sprintf,
changes the timing from 4.3 seconds to 0.8 seconds; so more than 80% is writing via the file system.
I wanted to determine the overheads of using "<<" on each print item, especially as there are 3 extra arguments of " ", " " and "\n".
These latter overheads are irrelevant when using the format string of sprintf.
The question posed was whether turning into individual print items into
a string object, before sending that string to the output, was a
significant overhead.
I showed my /dynamic/ code wasn't significantly slower than C++
(actually it was faster) despite doing those conversions, plus a whole
bunch of other overheads that C++ will not have.
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Preferably whatever the solution is, it shouldn't require the type
to dynamically construct a string to be printed, and instead the
type should get an std::ostream (or FILE*, or whatever) that it
can use to directly write whatever it wants there.
Why? Is this just because of memory overhead concerns?
What is this sudden strange attitude of "efficiency doesn't matter"?
This is C++ we are talking about, not Python, or JavaScript, or PHP,
or a shell script.
On 24/09/2021 05:38, Juha Nieminen wrote:
Bart <bc@freeuk.com> wrote:
On 23/09/2021 08:31, Juha Nieminen wrote:
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>>>>> that pays little to no attention to the efficiency of the resulting >>>>>> program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every
custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
I'm not forcing anything at all. Custom types can have dedicated
tostring routines; or use default ones; or have nothing.
Then how exactly do you add support for your type into the standard
printing function, if not by forcing your type to have a "tostring"
method?
I've lost track of what you're asking.
But if there is really a need to convert of value of some abstract type
T into a sequenct of characters, then how else can be it done other than providing support functions which does that conversion?
If your quibble about having to do the whole conversion into some intermediate string before starting to output characters from that new string, rather than do it a character at a time?
I'm sure, it's possible to that that conversion incrementally, to
provide that conversion in the form of a generator function, which
yields the next character (not sure what C++ capabilities are here).
Or to provide a callback function to the translation function to tell it
what to do with each new generated character. Although both of sound a
lot less efficient to me.
Probably 99% of all print items would have an intermediate string less
than 100 characters along, so that a simple fixed buffer would suffice. That's a better idea than sending a character at time to some stream-processing function (like fputc).
Bart <bc@freeuk.com> wrote:
On 23/09/2021 08:31, Juha Nieminen wrote:
Bart <bc@freeuk.com> wrote:
It seems to me that you come from a world of programming language design >>>>> that pays little to no attention to the efficiency of the resulting
program.
Not at all. I used to write compilers and applications for 8-bit
computers; I know how to be efficient!
If that were the case, then you would abhor the idea of forcing every
custom type to have a "tostring" function which is the only way to
add support to the standard printing function for your type.
I'm not forcing anything at all. Custom types can have dedicated
tostring routines; or use default ones; or have nothing.
Then how exactly do you add support for your type into the standard
printing function, if not by forcing your type to have a "tostring"
method?
On Thu, 23 Sep 2021 18:31:34 +0100
Bart <bc@freeuk.com> wrote:
On 23/09/2021 17:21, HorseyWorsey@the_stables.com wrote:
Since a basic line splitter is easy for any half competant programmer and >>> anything more complex - ie a parser - is usually tuned for a particular need
what would be the point? C++ has already had the kitchen sink thrown into it
because of people like you yet you want even basic stuff done for you?
This is the paradox: C++ has a lot of hugely complicated but neglects
the basics.
And it's just C++ but a lot of current languages, because they have
their focus elsewhere. (I especially know about Python.)
An effective basic Print (and Read) needs language support otherwise it
becomes a pain to use.
The support needed is not significant. My proof-of-concept to add
automatic printf format codes to a C compiler (so you do "%?" for any
basic type instead of "%d" etc), was 50 lines of code.
And no doubt requires the resulting binary to store a boatload of RTTI in order
to do that which rather defeats the point of using C which is to create slimline efficient binaries.
It could have been done for C++ which has RTTI
anyway but stroustrup went with iostream instead.
concats a vector of strings for you? Maybe you'd be better off usingjavascript.
So. why bother with even std::cout (I still don't know what that
actually is) or printf? Just have fgetc and fputc.
As you well know the point of cout is to allow output of complex objects which have overloaded << without having to call a converter function first.
If all you're doing is outputting formatted strings then IMO *printf() is a better choice because its more expressive and compact.
After all how hard can it be to knock up an int-to-string converter? The
A universal number to string converter is actually quite complex as it has to deal with IEEE 754 floating point format not to mention negative numbers and formatting.
On 24/09/2021 10:12, HorseyWorsey@the_stables.com wrote:
On Thu, 23 Sep 2021 18:31:34 +0100
Bart <bc@freeuk.com> wrote:
On 23/09/2021 17:21, HorseyWorsey@the_stables.com wrote:
Since a basic line splitter is easy for any half competant programmer and >>>> anything more complex - ie a parser - is usually tuned for a particular need
what would be the point? C++ has already had the kitchen sink thrown into it
because of people like you yet you want even basic stuff done for you?
This is the paradox: C++ has a lot of hugely complicated but neglects
the basics.
And it's just C++ but a lot of current languages, because they have
their focus elsewhere. (I especially know about Python.)
An effective basic Print (and Read) needs language support otherwise it
becomes a pain to use.
The support needed is not significant. My proof-of-concept to add
automatic printf format cod
On 24/09/2021 10:12, HorseyWorsey@the_stables.com wrote:
And no doubt requires the resulting binary to store a boatload of RTTI in >order
to do that which rather defeats the point of using C which is to create
slimline efficient binaries.
Huh? This tweak to C means that when somebody writes:
printf("%? %?", i, f);
it converts the string to "%d %f". There is zero impact on any binaries.
As you well know the point of cout is to allow output of complex objects
which have overloaded << without having to call a converter function first.
Actually no I don't. I'm still not entirely clear how << works, other
than it is 100% unintuitive.
Virtually all output I want to do is of standard types. It would just be
nice to output A and B by writing:
... A, B ...
rather than:
... A << " " << B ...
A universal number to string converter is actually quite complex as it has to
deal with IEEE 754 floating point format not to mention negative numbers and >> formatting.
Negative numbers aren't that difficult actually...
I realy like to_string, to me it is *very usefull* and use it often
since then.
If you do something simple like `std::cin >> a >> b >> c`, it doesn't
give you a way to determine which input operation failed -- but you can
tell whether they were all successful or not. Sometimes that's good
enough. If it isn't, write different code.
If you are reading CSV files and such, fields are sometimes enclosed in quotes, including numeric fields.
On Fri, 24 Sep 2021 12:10:01 +0100
Bart <bc@freeuk.com> wrote:
On 24/09/2021 10:12, HorseyWorsey@the_stables.com wrote:
And no doubt requires the resulting binary to store a boatload of RTTI in >> order
to do that which rather defeats the point of using C which is to create
slimline efficient binaries.
Huh? This tweak to C means that when somebody writes:
printf("%? %?", i, f);
it converts the string to "%d %f". There is zero impact on any binaries.
And what happens if 'i' is a char? Do you want %c, %d or %u? What if its a pointer? Do you want %p, %x, %X, %lu etc?
So you're complaining about basic C++ functionality you don't even understand.
Got it.
Virtually all output I want to do is of standard types. It would just be
nice to output A and B by writing:
... A, B ...
rather than:
... A << " " << B ...
Whats special about a space?
What if someone wants 2 spaces as a seperator
or maybe a tab or comma? C++ is a professional language, its not BASIC for kiddies to output simple tabular results.
What if someone wants 2 spaces as a seperator
or maybe a tab or comma?
Plus a comma already has syntactic
meaning in C & C++.
Negative numbers aren't that difficult actually...
So long as you remember chars,ints etc are 2's complement whereas floating point uses a sign bit.
On Friday, September 24, 2021 at 3:46:49 AM UTC-4, Branimir Maksimovic wrote:
I realy like to_string, to me it is *very usefull* and use it often
since then.
It's inherently inefficient though, particularly as it's frequently used to append a
small piece of text to a larger string, repeated many times. Thus are many copies created.
On Friday, September 24, 2021 at 3:46:49 AM UTC-4, Branimir Maksimovic wrote:
I realy like to_string, to me it is *very usefull* and use it often
since then.
It's inherently inefficient though, particularly as it's frequently used to append a
small piece of text to a larger string, repeated many times. Thus are many copies created.
Daniel
On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
println a, b, c, d, e, f, g, h
And still totally unprofessional, of course. (Maybe a professional
wouldn't be able to claim so many hours' pay if the language was too easy!)
So you're complaining about basic C++ functionality you don't even >understand.
Got it.
Would understanding it make me happier about typing out all that <<
nonsense above?
Whats special about a space?
Have a look at the English written in these posts; what's the common >separator between words? Yep, it's a single space. Handy for stopping >alphanumeric entities from running into each other.
Because of course, when you generate human readable text from a
programming language, the most sensible default is to end up with:
12345678910
instead of:
1 2 3 4 5 6 7 8 9 10
What if someone wants 2 spaces as a seperator
or maybe a tab or comma? C++ is a professional language, its not BASIC for >> kiddies to output simple tabular results.
So 'professional' equals 'unnecessarily complicated and unintuitive'?
What if someone wants 2 spaces as a seperator
or maybe a tab or comma?
You make the most common, most useful and convenient requirement the
In programming languages it is very commonly used to separate the
elements of a list. So why not the list of expressions in a print
statement (or whatever std::cout << is classed as).
On Fri, 24 Sep 2021 17:25:24 +0100
Bart <bc@freeuk.com> wrote:
On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
println a, b, c, d, e, f, g, h
And still totally unprofessional, of course. (Maybe a professional
wouldn't be able to claim so many hours' pay if the language was too easy!)
If someone needs a nice easy scripting language they'll use Python. And they do.
So 'professional' equals 'unnecessarily complicated and unintuitive'?
No, it equals syntax able to do complex tasks easily. BASIC makes it easy to print stuff out but I wouldn't use it to write Fintech software in!
You make the most common, most useful and convenient requirement the
Where did you get the idea its the most common? I'm afraid thats BS. We're talking program output, not human writing.
In programming languages it is very commonly used to separate the
elements of a list. So why not the list of expressions in a print
statement (or whatever std::cout << is classed as).
face <- palm. Honestly, why don't you go play in comp.lang.basic
On 25/09/2021 10:27, HorseyWorsey@the_stables.com wrote:
Where did you get the idea its the most common? I'm afraid thats BS. We're >> talking program output, not human writing.
Program output as text? The intention is usually to keep it human
readable. Each machine readable text will need separators.
In programming languages it is very commonly used to separate the
elements of a list. So why not the list of expressions in a print
statement (or whatever std::cout << is classed as).
face <- palm. Honestly, why don't you go play in comp.lang.basic
/I/ should do the face-palm, given your completely irrational insistence >that:
A << " " << B
is miles better than:
A, " ", B
/and/ better than simply:
A, B
On Sat, 25 Sep 2021 11:07:16 +0100
Bart <bc@freeuk.com> wrote:
On 25/09/2021 10:27, HorseyWorsey@the_stables.com wrote:
Where did you get the idea its the most common? I'm afraid thats BS. We're >>> talking program output, not human writing.
Program output as text? The intention is usually to keep it human
readable. Each machine readable text will need separators.
And just how many C++ programs these days do you think return their output
to the console assuming human readable output is even their raison d'etre? C++ is usually used for huge backend systems that run in the background and any readable output will probably be formatted data written to a log that won't be simply words seperated by a space.
In programming languages it is very commonly used to separate the
elements of a list. So why not the list of expressions in a print
statement (or whatever std::cout << is classed as).
face <- palm. Honestly, why don't you go play in comp.lang.basic
/I/ should do the face-palm, given your completely irrational insistence
that:
A << " " << B
is miles better than:
A, " ", B
Where did I say that? Comma is already overloaded in C/C++, it doesn't need yet another meaning.
/and/ better than simply:
A, B
Because the use case of that for C++ is virtually non existent except in debugging.
On 25/09/2021 11:14, HorseyWorsey@the_stables.com wrote:
On Sat, 25 Sep 2021 11:07:16 +0100
Bart <bc@freeuk.com> wrote:
On 25/09/2021 10:27, HorseyWorsey@the_stables.com wrote:
Where did you get the idea its the most common? I'm afraid thats BS. We're >>>> talking program output, not human writing.
Program output as text? The intention is usually to keep it human
readable. Each machine readable text will need separators.
And just how many C++ programs these days do you think return their output >> to the console assuming human readable output is even their raison d'etre? >> C++ is usually used for huge backend systems that run in the background and >> any readable output will probably be formatted data written to a log that
won't be simply words seperated by a space.
According to Wikipedia, C++ is a general purpose language.
Where did I say that? Comma is already overloaded in C/C++, it doesn't need >> yet another meaning.
But, what on earth does that mean? Overloaded for what purpose? Last
time I looked, comma was still used to separate the arguments of a function.
Are you hung up on the fact that because "<<" is an operator (a very
strange one), then any replacement for that whole god-forsaken std::cout >scheme must be implemented as some kind of operator too?
Because the use case of that for C++ is virtually non existent except in
debugging.
So quite an important use-case.
On Fri, 24 Sep 2021 17:25:24 +0100
Bart <bc@freeuk.com> wrote:
On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
println a, b, c, d, e, f, g, h
And still totally unprofessional, of course. (Maybe a professional
wouldn't be able to claim so many hours' pay if the language was too easy!)
If someone needs a nice easy scripting language they'll use Python. And they do.
On Fri, 24 Sep 2021 17:25:24 +0100
If someone needs a nice easy scripting language they'll use Python. And they do.
On 20/09/2021 17:20, Juha Nieminen wrote:
Scott Lurndal <scott@slp53.sl.home> wrote:
In other words, you can achieve this:
MyClass obj;
std::cout << "Value = " << obj << "\n";
fprintf(stdout, "Value = %s\n" obj.to_string());
I don't really know how exactly you expect that to be possible in all
cases.
The returned const char* has to point somewhere. To something that will
outlive the to_string() function itself, but will, if necessary, be
destroyed
after use (because in many cases you will need to create a dynamically
allocated string in order to contain the textual representation of the
value
of the object you are trying to print).
The whole to_string() concept also falls apart if you are printing in a template. int.to_string() anyone?
25.09.2021 12:27 HorseyWorsey@the_stables.com kirjutas:
On Fri, 24 Sep 2021 17:25:24 +0100
Bart <bc@freeuk.com> wrote:
On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
println a, b, c, d, e, f, g, h
And still totally unprofessional, of course. (Maybe a professional
wouldn't be able to claim so many hours' pay if the language was too
easy!)
If someone needs a nice easy scripting language they'll use Python.
And they
do.
In Python they apparently thought printing was too simple, so in Python
3 they now require parens:
Python2: print 1, 2, 3
Python3: print(1, 2, 3)
BTW, in C++ one can easily define python3 style print:
#include <iostream>
inline void print() {
std::cout << "\n";
}
template<typename T, typename... Args>
void print(T x, Args... args) {
std::cout << x << ' ';
print(args...);
}
int main() {
print(1, 2, 3);
}
Note to Bart: the ellipses above are actual C++11 syntax, not some pseudocode. This is a running demo program. In your own C++ code just
put these print() definitions in sme common header file, and you can use python3 style print syntax for all built-in and other types which
support stream<<.
On 25/09/2021 13:37, Paavo Helde wrote:
25.09.2021 12:27 HorseyWorsey@the_stables.com kirjutas:
On Fri, 24 Sep 2021 17:25:24 +0100
Bart <bc@freeuk.com> wrote:
On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
println a, b, c, d, e, f, g, h
And still totally unprofessional, of course. (Maybe a professional
wouldn't be able to claim so many hours' pay if the language was too
easy!)
If someone needs a nice easy scripting language they'll use Python.
And they
do.
In Python they apparently thought printing was too simple, so in Python
3 they now require parens:
Python2: print 1, 2, 3
Python3: print(1, 2, 3)
That was one giant PITA. A lot of downloadable Python at one time was >Python2. So you had to convert all the uses of 'print'.
Python2: print 1, 2, 3
Python3: print(1, 2, 3)
That was one giant PITA. A lot of downloadable Python at one time was Python2. So you had to convert all the uses of 'print'.
The change was to turn 'print' from a statement into a function, because
it was 'better'.
Then how exactly do you add support for your type into the standard
printing function, if not by forcing your type to have a "tostring"
method?
I've lost track of what you're asking.
But if there is really a need to convert of value of some abstract type
T into a sequenct of characters, then how else can be it done other than providing support functions which does that conversion?
Probably 99% of all print items would have an intermediate string less
than 100 characters along, so that a simple fixed buffer would suffice.
Adding a stream adaptor for a class having only a to_string() is trivial:
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.to_string();
return os;
}
It appears we are both concerned about efficiency. Alas, we have
drastically different opinions about where the inefficiencies lure. Fortunately programming is strongly connected to reality, unlike some
other areas of human activity, so one can check the reality to see
what's really happening.
Here is a test program measuring the two different approaches to
streaming: (A) sending 100 million ints to std::ostream separately, and
(B) formatting them first into a huge std::string, then sending that to std::ostream in one go. My results are here:
Paavo Helde <myfirstname@osa.pri.ee> wrote:
It appears we are both concerned about efficiency. Alas, we have
drastically different opinions about where the inefficiencies lure.
Fortunately programming is strongly connected to reality, unlike some
other areas of human activity, so one can check the reality to see
what's really happening.
Here is a test program measuring the two different approaches to
streaming: (A) sending 100 million ints to std::ostream separately, and
(B) formatting them first into a huge std::string, then sending that to
std::ostream in one go. My results are here:
You are constructing a string with the contents of the data in both cases.
This is not what I'm talking about. It's quite obvious (and I have never
had any illusion otherwise) that std::ostringstream is extraordinarily inefficient. Obviously using other methods for constructing a string
are going to be a million times faster. (I myself pretty much never
use std::ostringstream if I can avoid it.)
But I am not talking about constructing a string from the content of
the data. In fact, I'm talking about the exact opposite: *Avoiding* constructing a string into memory with the data.
How do you add support to the standard output functions for custom
types without requiring those custom types to create strings from
their data, and being able to directly output the data?
Just substitute std::ostream with something more efficient.
The question remains: How do you add native support for custom
types to that output method, without requiring the custom types
to create dynamically allocated strings in memory, and instead
being able to directly use that output method to print their
contents (in whichever way they choose)?
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Adding a stream adaptor for a class having only a to_string() is trivial:
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.to_string();
return os;
}
While you are at it, why not just output the contents of that A object directly, rather than making it construct a string?
27.09.2021 08:36 Juha Nieminen kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Adding a stream adaptor for a class having only a to_string() is trivial: >>>
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.to_string();
return os;
}
While you are at it, why not just output the contents of that A object
directly, rather than making it construct a string?
Because of speed. I just showed elsethread that serializing a large
object into an in-memory string can be up to 10x faster than writing it
into a std::ostream piece-by-piece.
Also, because of better modularity and easier usage. A string is
basically just a raw memory buffer which is easy to transport and use. Streams are more complicated.
Say, I want to write my large data structure into a file in AWS cloud. AmazonStreamingWebServiceRequest::SetBody() takes a pointer to an input stream and reads data from it later when I call S3Object::PutObject().
Say, for my large data structure I have proper streaming support which
writes the data into an std::ostream. So now what? How do I connect this output stream to an input stream used by the AWS library so that they
would "flow together"? Sure it can be done, but seems not so easy.
Threads or coroutines come to mind.
The easiest way is to dump the data into a temporary file, then let the
AWS library to read it. We do not need a file on disk, so this ought to
be an in-memory file. And guess what is the fastest way to create an in-memory file? Answer: serializing the data into a raw memory buffer
such as std::string. IOW the dreaded to_string() method.
On 27/09/2021 21:19, Paavo Helde wrote:
27.09.2021 08:36 Juha Nieminen kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Adding a stream adaptor for a class having only a to_string() is
trivial:
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.to_string();
return os;
}
While you are at it, why not just output the contents of that A object
directly, rather than making it construct a string?
Because of speed. I just showed elsethread that serializing a large
object into an in-memory string can be up to 10x faster than writing it
into a std::ostream piece-by-piece.
Also, because of better modularity and easier usage. A string is
basically just a raw memory buffer which is easy to transport and use.
Streams are more complicated.
Say, I want to write my large data structure into a file in AWS cloud.
AmazonStreamingWebServiceRequest::SetBody() takes a pointer to an input
stream and reads data from it later when I call S3Object::PutObject().
Say, for my large data structure I have proper streaming support which
writes the data into an std::ostream. So now what? How do I connect this
output stream to an input stream used by the AWS library so that they
would "flow together"? Sure it can be done, but seems not so easy.
Threads or coroutines come to mind.
The easiest way is to dump the data into a temporary file, then let the
AWS library to read it. We do not need a file on disk, so this ought to
be an in-memory file. And guess what is the fastest way to create an
in-memory file? Answer: serializing the data into a raw memory buffer
such as std::string. IOW the dreaded to_string() method.
You can string it into an in memory straeam buffer.
I can't see how adding to a string can be any faster
convert each field to a string representation which is what streams do
for you.
In Python they apparently thought printing was too simple, so in Python
3 they now require parens:
Python2: print 1, 2, 3
Python3: print(1, 2, 3)
Am 25.09.21 um 14:37 schrieb Paavo Helde:
In Python they apparently thought printing was too simple, so in
Python 3 they now require parens:
Python2: print 1, 2, 3
Python3: print(1, 2, 3)
It wasn't "too simple", whatever that means, but in Python2, "print" was
a keyword and specially treated in the interpreter, whereas the core developers thought that it should not be set apart from regular
functions, because there is nothing that "print" can do that any other
old function could not do.
27.09.2021 08:36 Juha Nieminen kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Adding a stream adaptor for a class having only a to_string() is trivial: >>>
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.to_string();
return os;
}
While you are at it, why not just output the contents of that A object
directly, rather than making it construct a string?
Because of speed. I just showed elsethread that serializing a large
object into an in-memory string can be up to 10x faster than writing it
into a std::ostream piece-by-piece.
But I am not talking about constructing a string from the content of
the data. In fact, I'm talking about the exact opposite: *Avoiding*
constructing a string into memory with the data.
Why? In my practice this is a major usage scenario.
How do you add support to the standard output functions for custom
types without requiring those custom types to create strings from
their data, and being able to directly output the data?
Why? What's wrong with creating strings?
Just substitute std::ostream with something more efficient.
I just did. It's called to_string().
The question remains: How do you add native support for custom
types to that output method, without requiring the custom types
to create dynamically allocated strings in memory, and instead
being able to directly use that output method to print their
contents (in whichever way they choose)?
Why? A lot of data transfer mechanisms use internal memory buffers,
which often are dynamically allocated.
Paavo Helde <myfirstname@osa.pri.ee> wrote:
27.09.2021 08:36 Juha Nieminen kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Adding a stream adaptor for a class having only a to_string() is trivial: >>>>
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.to_string();
return os;
}
While you are at it, why not just output the contents of that A object
directly, rather than making it construct a string?
Because of speed. I just showed elsethread that serializing a large
object into an in-memory string can be up to 10x faster than writing it
into a std::ostream piece-by-piece.
Suppose that the 'a' object above consists of 2 large strings, and you
want to write them to 'os' concatenated.
Are you seriously telling me that it's more efficient to first create a
new dynamically allocated string, write the two strings from 'a' there,
write that string to 'os' and then destroy that temporary string, than
it would be to just write the two strings directly to 'os' one after
another?
Paavo Helde <myfirstname@osa.pri.ee> wrote:
27.09.2021 08:36 Juha Nieminen kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Adding a stream adaptor for a class having only a to_string() is trivial: >>>>
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.to_string();
return os;
}
While you are at it, why not just output the contents of that A object
directly, rather than making it construct a string?
Because of speed. I just showed elsethread that serializing a large
object into an in-memory string can be up to 10x faster than writing it
into a std::ostream piece-by-piece.
Suppose that the 'a' object above consists of 2 large strings, and you
want to write them to 'os' concatenated.
Are you seriously telling me that it's more efficient to first create a
new dynamically allocated string, write the two strings from 'a' there,
write that string to 'os' and then destroy that temporary string, than
it would be to just write the two strings directly to 'os' one after
another?
28.09.2021 07:53 Juha Nieminen kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> wrote:
27.09.2021 08:36 Juha Nieminen kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Adding a stream adaptor for a class having only a to_string() is trivial: >>>>>
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.to_string();
return os;
}
While you are at it, why not just output the contents of that A object >>>> directly, rather than making it construct a string?
Because of speed. I just showed elsethread that serializing a large
object into an in-memory string can be up to 10x faster than writing it
into a std::ostream piece-by-piece.
Suppose that the 'a' object above consists of 2 large strings, and you
want to write them to 'os' concatenated.
This is another task. If you already have data formatted into strings,
then of course these can be written directly to a file. But for that you don't need a C++ std::ostream interface, you can write directly into the
file descriptor, or C++ streambuf(). If there are only a handful of
strings, then you can of course write them to the stream as well, the overhead is insignificant.
What I'm talking is about outstreaming millions of small items
one-by-one, like advocated by ostream<< enthusiasts: just define a
proper operator<< overload and write everything in the ostream,
recursively, each number separately.
It's this formatting interface of C++ iostreams which is slow. With
MSVC++ I just stepped though an operator<<(std::ofstream&, int), this involved at least 2 virtual function calls, 4 locking/unlocking of
current locale, and consulting TLS about the number of uncaught
exceptions, not to speak about tens of non-virtual function calls (which hopefully get optimized away) and twiddling with the stream state. This
is all 100% unnecessary overhead for formatting an int in C locale. It
won't matter for a single debug printout line, but it will matter when exporting a 100,000 line table into a CSV file.
On 28/09/2021 23:23, Paavo Helde wrote:
It's this formatting interface of C++ iostreams which is slow. With
MSVC++ I just stepped though an operator<<(std::ofstream&, int), this
involved at least 2 virtual function calls, 4 locking/unlocking of
current locale, and consulting TLS about the number of uncaught
exceptions, not to speak about tens of non-virtual function calls (which
hopefully get optimized away) and twiddling with the stream state. This
is all 100% unnecessary overhead for formatting an int in C locale. It
won't matter for a single debug printout line, but it will matter when
exporting a 100,000 line table into a CSV file.
Ah, right so it's the overhead of locale based formatting that's the
real problem here. Presumably this would be the same for C printing functions as well. I can see why std::to_chars would have an advantage here.
I haven't seen such an high overhead on Unix/Linux, I wonder of the
Windows way of doing things is more burdensome? An example wit timings would be useful!
29.09.2021 00:34 Ian Collins kirjutas:
On 28/09/2021 23:23, Paavo Helde wrote:
It's this formatting interface of C++ iostreams which is slow. With
MSVC++ I just stepped though an operator<<(std::ofstream&, int), this
involved at least 2 virtual function calls, 4 locking/unlocking of
current locale, and consulting TLS about the number of uncaught
exceptions, not to speak about tens of non-virtual function calls (which >>> hopefully get optimized away) and twiddling with the stream state. This
is all 100% unnecessary overhead for formatting an int in C locale. It
won't matter for a single debug printout line, but it will matter when
exporting a 100,000 line table into a CSV file.
Ah, right so it's the overhead of locale based formatting that's the
real problem here. Presumably this would be the same for C printing
functions as well. I can see why std::to_chars would have an advantage
here.
Right. Actually it is not so important where the output is collected,
it's the formatting step what is the bottleneck. It is even possible to
use the standard stream for collecting the output, for those who repel
the idea of a string buffer. The trick is to ignore the stream part and
only use the streambuf part, see the test program below.
I haven't seen such an high overhead on Unix/Linux, I wonder of the
Windows way of doing things is more burdensome? An example wit timings
would be useful!
Here you are. These timings are for 50 million ints. You can try the
demo program out by yourself with your favorite compiler and hardware.
On my Windows the "traditional" streaming is ca 10 times slower than alternatives, on my Linux the difference is smaller, just ca 2 times.
MSVC++ 2019 on Windows, x64 Release build:
Traditional streaming: 16479 ms
Streaming with std::to_chars() directly into streambuf: 1612 ms
Collecting the content in a string buffer of 418 MB: 1126 ms
Writing the string buffer of 418 MB into a disk file: 796 ms
g++ 8.3 on Linux:
$ g++ -Wall -O3 -std=c++17 test6.cpp
$ ./a.out
Traditional streaming: 2080 ms
Streaming with std::to_chars() directly into streambuf: 903 ms
Collecting the content in a string buffer of 418 MB: 655 ms
Writing the string buffer of 418 MB into a disk file: 146 ms
It also gives me another argument for upgrading our embedded target
compiler to one which supports C++17!
Are you seriously telling me that it's more efficient to first create a
new dynamically allocated string, write the two strings from 'a' there,
write that string to 'os' and then destroy that temporary string, than
it would be to just write the two strings directly to 'os' one after
another?
Bizarrely, yes it could be faster!
Because, for most objects that are not already strings, assembling into
a local temporary string, then dumping the whole string at once, might
be faster than calling some external character-at-a-time routine.
Suppose that the 'a' object above consists of 2 large strings, and you
want to write them to 'os' concatenated.
This is another task.
If you already have data formatted into strings,
then of course these can be written directly to a file. But for that you don't need a C++ std::ostream interface, you can write directly into the
file descriptor, or C++ streambuf().
Bart <bc@freeuk.com> wrote:
Are you seriously telling me that it's more efficient to first create a
new dynamically allocated string, write the two strings from 'a' there,
write that string to 'os' and then destroy that temporary string, than
it would be to just write the two strings directly to 'os' one after
another?
Bizarrely, yes it could be faster!
Because, for most objects that are not already strings, assembling into
a local temporary string, then dumping the whole string at once, might
be faster than calling some external character-at-a-time routine.
I did not ask whether outputting one concatenated string is faster than outputting two strings one character at a time.
I asked if concatenating the two strings and then outputting the result
is faster than just outputting the two strings.
On 29/09/2021 13:10, Juha Nieminen wrote:
Bart <bc@freeuk.com> wrote:
Are you seriously telling me that it's more efficient to first create a >>>> new dynamically allocated string, write the two strings from 'a' there, >>>> write that string to 'os' and then destroy that temporary string, than >>>> it would be to just write the two strings directly to 'os' one after
another?
Bizarrely, yes it could be faster!
Because, for most objects that are not already strings, assembling into
a local temporary string, then dumping the whole string at once, might
be faster than calling some external character-at-a-time routine.
I did not ask whether outputting one concatenated string is faster than
outputting two strings one character at a time.
I asked if concatenating the two strings and then outputting the result
is faster than just outputting the two strings.
I was talking about the net effect when outputting lots of different
objects, since the gains can offset the losses.
But, OK, the answer to your specific question: I guess it depends. On
the overheads of calling the o/p routine, and the efficiency of string concatenation.
I asked if concatenating the two strings and then outputting the result
is faster than just outputting the two strings.
Paavo Helde <myfirstname@osa.pri.ee> wrote:
Suppose that the 'a' object above consists of 2 large strings, and you
want to write them to 'os' concatenated.
This is another task.
No, it isn't.
I just said "custom type" which wants to output its contents. I did not specify what the content exactly is. You seem to be assuming that I was talking about, for example, a data container containing numbers.
If you already have data formatted into strings,
then of course these can be written directly to a file. But for that you
don't need a C++ std::ostream interface, you can write directly into the
file descriptor, or C++ streambuf().
No you can't, if you don't have a reference to the ostream object (or FILE pointer).
Sure, you could just call a member function of the class giving it
that object, but then you cannot use that in generic code. You would
merely be trying to work your way around not overloading operator<<,
which does exactly that thing, in a way that allows it to be used in
generic code.
So my question is, once again: If overloading operator<< for this
is such a horrible thing, what exactly is your alternative?
I have nothing against operator<<, it just tends to be slow if
implemented as taught in the books. I believe it was you who stressed
the importance of efficiency in C++.
On 29/09/2021 22:18, Paavo Helde wrote:
Here you are. These timings are for 50 million ints. You can try the
demo program out by yourself with your favorite compiler and hardware.
On my Windows the "traditional" streaming is ca 10 times slower than
alternatives, on my Linux the difference is smaller, just ca 2 times.
MSVC++ 2019 on Windows, x64 Release build:
Traditional streaming: 16479 ms
Streaming with std::to_chars() directly into streambuf: 1612 ms
Collecting the content in a string buffer of 418 MB: 1126 ms
Writing the string buffer of 418 MB into a disk file: 796 ms
g++ 8.3 on Linux:
$ g++ -Wall -O3 -std=c++17 test6.cpp
$ ./a.out
Traditional streaming: 2080 ms
Streaming with std::to_chars() directly into streambuf: 903 ms
Collecting the content in a string buffer of 418 MB: 655 ms
Writing the string buffer of 418 MB into a disk file: 146 ms
Interesting, thanks for posting. It's a similar ratio on my machine. I can see that the Windows way of doing things is definitely more burdensome.
alessandro volturno <alessandro.volturno@libero.it> wrote:
Il 17/09/2021 07:36, Juha Nieminen ha scritto:
alessandro volturno <alessandro.volturno@libero.it> wrote:
printDescription() // prints a description of the number and its
// numerical value
This is not really something that belongs to a class that behaves
like an arithmetic numerical value.
At most what you could have is a separate
std::ostream& operator<<(std::ostream&, YourRationalClass);
function for outputting the value to a std::ostream.
if you read the two lines right before the one here reported you
can see I did that.
I wrote that function to give an extensive description of a
rational number in a way like this:
"4/16 reduces to 1/4 and evaluates to 0.25"
I still think that designwise such a function does not belong in
that class.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 113 |
Nodes: | 8 (0 / 8) |
Uptime: | 08:56:35 |
Calls: | 2,497 |
Calls today: | 14 |
Files: | 8,646 |
Messages: | 1,902,597 |