Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

rational numbers

233 views
Skip to first unread message

alessandro volturno

unread,
Sep 16, 2021, 9:00:13 AM9/16/21
to
Hello group,

I am writing some C++ code to implement a class that handles fractional
numbers.
C++11 has the Ratio facility, but it is not possible to instantiate
Ratio objects or pass them to functions (at least I was not able to do
that), so just for fun I started a simple rational class, adding the
following:

private members *num* and *den*

constructor;
destructor; // defaulted
copy assignment operator // defaulted
copy constructor // defaulted
move assignment operator // defaulted
move constructor // defaulted

operator+ ()
operator- ()
operator* ()
operator/ ()
operator== ()
operator!= ()

friend operator<= ()
friend operator< ()
friend operator> ()
friend operator>= ()

friend operator<< ()
friend operator>> ()

printDescription() // prints a description of the number and its

// numerical value

reduce() // simplifies a fraction using a static GCD function

reciprocal() // inverts a rational number


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?

Paavo Helde

unread,
Sep 16, 2021, 9:40:26 AM9/16/21
to
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

unread,
Sep 16, 2021, 12:25:45 PM9/16/21
to
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.

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'

> 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

The proposal you presented is quite dated, so I presume many talkings
have been made about it. I don't know the reason why, but it evidently
came out not to add this feature to the language.

Many computer languages are evolving and new ones are born every one or
two years. In my opinion, to keep a language competitive with respect to
the others around, that language should also permit basic number
manipulation as easier as possible.

I repeat myself, I'm a hobbyist, spare-time programmer, but as complex
numbers have been added to C++, so there should be some mechanics to
handle rationals.

> Meanwhile one can use the Boost Rational library.

I've heard about the Boost library but I've never made an attempt to
study it nor to use it.

My projects are small ones and I write them by scratch just for the sake
of knowing how I progress in this discipline (computer programming).

Thank you for your kind reply,

alessandro

Scott Lurndal

unread,
Sep 16, 2021, 1:05:20 PM9/16/21
to
alessandro volturno <alessandr...@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

Manfred

unread,
Sep 16, 2021, 1:58:28 PM9/16/21
to
It is true that numerical analysis is easier in Matlab than C++, but I
think the main point is that, if you know what you are doing, standard
floating point and integer types can cover the a lot of application use
even when writing C++ (as well as C) programs.

The main advantage of rational arithmetic is that it allows an exact
representation of a significant class of numbers, without rounding errors.
But in many practical applications (engineering, automation, ...) 16
significant digits (as offered by the 'double' type) yield rounding
errors that are small enough.
It is true, though, that specific knowledge is required - naive code can
easily yield garbage.

The limitation that I see with digital rationals, without having read
the linked proposal, is that they would still represent a limited subset
of the rational numbers, which is a limitation for theoretical analysis
- in addition, output results can be exact only if inputs are exact
rationals numbers, which rules out all physical quantities, a limitation
of the advantage over floating point math.

In short, it is understandable that there is not enough motivation to
include this as a native type in the language, compared to what is
already available through libraries.

David Brown

unread,
Sep 16, 2021, 2:42:13 PM9/16/21
to
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.

Bart

unread,
Sep 16, 2021, 4:12:15 PM9/16/21
to
On 16/09/2021 19:41, David Brown wrote:
> 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.)

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.

It's worse with divide: just do 1.0/3.0, and it will be calculating
0.3333.... forever (the theoretical limit in mine is 36 billion digits,
but it will be aborted, long before).

At least with rationals, this can be deferred, or cancelled out if the
next thing is to multiply by 3 again.


> 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.

I've often reserved a rational type in the languages I create, but have
never got round to implementing them. They will usually need a
big-integer type for a start.

But as you say they are not that practical. How would they be displayed
for example; as proper and improper fractions? I get enough grief when
my Casio gets stuck in fraction mode and I can't remember how to fix it.


Paavo Helde

unread,
Sep 16, 2021, 4:13:15 PM9/16/21
to
16.09.2021 19:24 alessandro volturno kirjutas:
> 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.

Of course numerical programming is important. It's done mostly in
floating-point (64-bit and 32-bit; in recent years also 16-bit on
GPU-s). In some cases it can be done in integers, for more speed, but
it's not so simple and the speedups are not very large any more nowadays.

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).

>
>> 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.

Long long int probably means 64 bits, which is not so much. The smallest
positive rational would be 1/2^64, i.e. ca 10^-61. Meanwhile, the
smallest positive double is ca 10^-308, with the same number of bits.
Ditto for the largest values. IOW, floating-point can approximate values
with much more precision, and there is much less danger of overflows
during 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.

Sure, with floating-point algorithms one must take care to not lose too
much precision in intermediate results. However, I suspect that with
rational number algorithms even more care is needed, to avoid numeric
overflows in intermediate results.

[...]
> Thank you for your kind reply,

Thanks!


Ben Bacarisse

unread,
Sep 16, 2021, 4:26:36 PM9/16/21
to
Bart <b...@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?

--
Ben.

Bart

unread,
Sep 16, 2021, 4:55:10 PM9/16/21
to
(My library is decimal, but there will be the same issues with binary.)

I think I meant M+N, not M*N! And that's approximate. Squaring a single
digit 1-9 will result in 1-81, which is 1 or 2 digits. (M*N applies to
exponentiation.)

In any case, it will increase the number of digits when chaining a lot
of multiplications, when you have no upper limit on precision.

There is some confusion since digits or bits don't usually exist by
themselves, but grouped into words or 'limbs'. Squaring 31 bits of value
contained within a 64-bit type yields something that still fits into 64
bits, but may need 61/62 of those bits to represent.

But this is about arbitrary precision with multiple words to store results.

Alf P. Steinbach

unread,
Sep 16, 2021, 5:08:18 PM9/16/21
to
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).


- Alf

Alf P. Steinbach

unread,
Sep 16, 2021, 5:27:51 PM9/16/21
to
I evidently meant to write "Bart", not "Ben".

Oh well.


- Alf


Juha Nieminen

unread,
Sep 17, 2021, 1:37:14 AM9/17/21
to
alessandro volturno <alessandr...@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.

Christian Gollwitzer

unread,
Sep 17, 2021, 3:21:22 AM9/17/21
to

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.

Christian

alessandro volturno

unread,
Sep 17, 2021, 3:52:05 AM9/17/21
to
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


alessandro volturno

unread,
Sep 17, 2021, 3:56:16 AM9/17/21
to
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"

thank you,

alessandro

David Brown

unread,
Sep 17, 2021, 4:35:16 AM9/17/21
to
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.


David Brown

unread,
Sep 17, 2021, 5:16:07 AM9/17/21
to
On 17/09/2021 09:50, alessandro volturno wrote:
> 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.
>

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.

> 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.
>

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. As I mentioned earlier,
there is a lot of fun and learning from making classes to support these,
but little practical use - therefore no point in having them in the
standard library. (The C++ standard library has support for
compile-time rational arithmetic, mainly as a convenient way to handle
magnitudes of SI units.)

So for useful rationals, you need arbitrary precision integers. And
that is a whole different ballgame from fixed sizes - you are now
talking about memory management, big complicated algorithms, and all
sorts of trade-offs in the implementation. For some languages, it's
okay to pick one "reasonable" implementation. It might be big and
incorporate a range of algorithms for different sizes - that's fine for
a language like Python that already has huge libraries. It might be
small and simple, and do a reasonable job for smaller sizes but be less
optimal for huge values - that made sense for Bart in his language.

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. 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 agree with those aims. And a C++ standard library for rational
numbers would be completely against that aim - how could you learn about
making good classes and abstractions using rational numbers if the
library already supported them? Make it yourself - that's how you will
learn.

> 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
>

The proposal for adding gui facilities to the C++ standard is /highly/
controversial. Some people think it would be nice to have in the
standard because "everyone" needs graphics and a gui. Others think it
is a terrible idea because there are several dozen popular gui
libraries, with wildly varying pros and cons, and making a "standard C++
gui library" would be as bad an idea as a country's roads department
picking a standard car.

Ian Collins

unread,
Sep 17, 2021, 6:07:32 AM9/17/21
to
Matlab does have one advantage (at least in our environment); it can
convert models into C++ code!

--
Ian.

Juha Nieminen

unread,
Sep 17, 2021, 7:16:34 AM9/17/21
to
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.

Even when you do implement something like an operator<<(std::ostream&)
for the class, its output should just be an ascii representation of the
number itself, and nothing else.

If you want to provide such printing functions for convenience, you could
implement them as separate functions (maybe even declared in their own
separate header file). Note, however, that you will be fixing the
format (and language) of such messages, which is one of the reasons
why it's not something you usually want to do. Let the user of the
class decide how such things are printed, rather than the library
forcing a particular format (and language). (After all, it's not such
a huge amount of work to write a simple printing line which uses
values from the instance of the class.)

David Brown

unread,
Sep 17, 2021, 7:32:56 AM9/17/21
to
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.

Christian Gollwitzer

unread,
Sep 17, 2021, 9:55:42 AM9/17/21
to
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.

Christian




Scott Lurndal

unread,
Sep 17, 2021, 10:03:19 AM9/17/21
to
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).

Scott Lurndal

unread,
Sep 17, 2021, 10:07:00 AM9/17/21
to
One of my colleagues wrote a tool (verilator) to convert Verilog
into C++ code. Quite useful.

https://en.wikipedia.org/wiki/Verilator

Christian Gollwitzer

unread,
Sep 17, 2021, 11:13:21 AM9/17/21
to
Am 17.09.21 um 16:03 schrieb Scott Lurndal:
> Juha Nieminen <nos...@thanks.invalid> writes:
>> alessandro volturno <alessandr...@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

Christian Gollwitzer

unread,
Sep 17, 2021, 11:17:23 AM9/17/21
to
Am 17.09.21 um 17:12 schrieb Christian Gollwitzer:
Quick test on compiler explorer shows a much more reasonable code:
https://godbolt.org/z/5MzscK95W

with gcc 11.

Christian

David Brown

unread,
Sep 17, 2021, 11:50:15 AM9/17/21
to
Lua, Julia, Ruby, etc., are also free. But Python was there first, and
I think momentum has a lot to do with it. It's also a higher level
language than, say, Lua, and while there are some mixed opinions on some
aspects of Python's syntax, it is generally regarded as a easier to
read, write and learn than Ruby and many alternatives.

> 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.
>

Tcl is okay as a "tool control language", but it is far too weak for
more advanced work. Python was considered too "heavy" for simple
scripting in many areas - but as everything else (disks, memory, cpus,
etc.) has got bigger, the relative cost of Python has dropped.

Christian Gollwitzer

unread,
Sep 17, 2021, 12:23:06 PM9/17/21
to
Am 17.09.21 um 17:49 schrieb David Brown:
> 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.

To be fair, one must say "has been". Tcl has improved since the days
back then and acquired many modern things like coroutines, built-in
object orientation etc. but the development went on a very slow path
after the support from Sun was dropped. I'm one of the inhabitants of a
small Gallic village ;) this is one of my projects realized in modern Tcl:

https://github.com/BessyHDFViewer/BessyHDFViewer


But the world has moved on, and now I'm recommending Pyton to everyone
who needs a programming language as the first pick. C++ comes second, if
speed is required or special hardware control etc. Of course, as a
scientist my environment is data analysis and lab hardware control. On
embedded devices the ranking would be different.

Christian

alessandro volturno

unread,
Sep 17, 2021, 12:34:28 PM9/17/21
to
Il 17/09/2021 13:16, Juha Nieminen ha scritto:

> I still think that designwise such a function does not belong in that class.

You are right, but the project started as a game and it is not
intentended to leave my PC :-)

> 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.

you were perfectly clear, thank you for that.

alessandro

Manfred

unread,
Sep 17, 2021, 1:00:12 PM9/17/21
to
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).

Scott Lurndal

unread,
Sep 17, 2021, 1:14:05 PM9/17/21
to
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.

alessandro volturno

unread,
Sep 17, 2021, 1:20:30 PM9/17/21
to
Il 17/09/2021 11:15, David Brown ha scritto:

> 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.

A tool is crafted for a certain scope, you could but don't want to peel
an apple with a cutter. If a tool is present in a computer language's
library that doesn't mean every one has ever to use it.

> 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.

> 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.

If something is in the standard library that doesn't mean everyone has
to use it. Your argument is valid if it were made a built in facility,
but in Common Lisp you have the usual fixed sized numerical types as
well as the wider and heavier ratios or numbers of arbitrary precision.
it's at your discretion use those things or not.

> 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.

Libraries are a bless, but there are so many of them all around you get
confused, and one has to spend many weeks studying one of them to obtain
something you could do inside your favourite programming language.

I have written, some years ago, a silly game in C++, quite similar to
Amiga's Colors. The platform used to develop it was linux. and well, to
paint on the screen I had to use an external library (Allegro 4).

Another toy program that I wrote uses FLTK's GUI facility. If I had the
opportunity of a graphics library inside C++, my program could just be
recompiled on Windows to work, without having to compile the library
using tools like cygwin to make it working in Windows.

>>> 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 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

Why?

- how could you learn about
> making good classes and abstractions using rational numbers if the
> library already supported them? Make it yourself - that's how you will
> learn.

You could just try to reinvent the wheel, thinking about how it could be
implemented. But that doesn't mean having rationals in the language
hinder you to mimic its functionality.

Thank you,

alessandro

Ian Collins

unread,
Sep 17, 2021, 5:15:41 PM9/17/21
to
The generated code isn't great, but with a little care in the model, it
isn't too bad either. I liken the process to the hand optimisations we
used to do in C to get the best from 80's vintage compilers!

--
Ian.

Ian Collins

unread,
Sep 17, 2021, 5:34:43 PM9/17/21
to
Maybe a better compiler would help? With clang++ and -O2:

_Z1av: # @_Z1av
.cfi_startproc
# %bb.0:
pushq %rbx
.cfi_def_cfa_offset 16
subq $32, %rsp
.cfi_def_cfa_offset 48
.cfi_offset %rbx, -16
leaq 16(%rsp), %rbx
movq %rbx, (%rsp)
movabsq $2338328219631577204, %rax # imm = 0x2073692073696874
movq %rax, 16(%rsp)
movabsq $8391162080155213939, %rax # imm = 0x7473657420612073
movq %rax, 22(%rsp)
movq $14, 8(%rsp)
movb $0, 30(%rsp)
movl $.L.str.1, %edi
movq %rbx, %rsi
xorl %eax, %eax
callq printf
movq (%rsp), %rdi
cmpq %rbx, %rdi
je .LBB0_2
# %bb.1:
callq _ZdlPv
.LBB0_2:
addq $32, %rsp
.cfi_def_cfa_offset 16
popq %rbx
.cfi_def_cfa_offset 8
retq

--
Ian.

James Kuyper

unread,
Sep 17, 2021, 7:00:45 PM9/17/21
to
On 9/17/21 1:19 PM, alessandro volturno wrote:
> 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

Yes, but exactly rational numbers that are an accurate reflection of
something in reality remain rare in all of the sciences.

David Brown

unread,
Sep 18, 2021, 5:39:36 AM9/18/21
to
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).

alessandro volturno

unread,
Sep 18, 2021, 5:56:46 AM9/18/21
to
But as you say, can have some advantage from them.
Anyway I now have a clear picture of the scenario about rational numbers
and C++ standard.

I can consider the question closed.

Thank you to all who took part in this thread.

alessandro

David Brown

unread,
Sep 18, 2021, 6:00:30 AM9/18/21
to
On 17/09/2021 23:34, Ian Collins wrote:
> On 18/09/2021 02:03, Scott Lurndal wrote:
>> Juha Nieminen <nos...@thanks.invalid> writes:
>>> alessandro volturno <alessandr...@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:
>
Or pretty much any version of gcc with -O2, at least according to my
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.

Bart

unread,
Sep 18, 2021, 6:02:32 AM9/18/21
to
So where does big integer arithemetic turn up?

With big integers, I can see that sometimes you want (A/B)*B to result in A.

With integer divide, that might not be the case.

Using floating point divide with finite precision, you can lose
information (and perversely end up with too much useless precision; if I
do (1/3)*3, with 100M digits, I get 100M digits of 0.9999....).

Letting A/B (perhaps with a special divide op) yield a rational type
would work.

In that case, I can see this being of value with i64 and i128 types too,
for the two parts of a rational number.


Scott Lurndal

unread,
Sep 18, 2021, 10:54:52 AM9/18/21
to
David Brown <david...@hesbynett.no> writes:
>On 17/09/2021 23:34, Ian Collins wrote:

>>
>> Maybe a better compiler would help?  With clang++ and -O2:
>>
>Or pretty much any version of gcc with -O2, at least according to my
>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. Custom classes can use 'to_string' functions
rather than overloading the << operator.

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).

Bart

unread,
Sep 18, 2021, 12:37:35 PM9/18/21
to
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).

The C has the big problem of needing to tell the compiler the types of
the expressions you're printing, something it already knows perfectly
well, since it can warn you when they're wrong!

You might not even know yourself, with a complex expression, or one
involving opaque types. And they need maintenance as code changes.

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.

Or, possibly you can use a feature such as this in my C compiler:

C (bcc): printf("%=? %=? %=?\n", a, b, c);

where it fills in the format codes. Note the the C example above is ONLY
valid when a has an int type, b is double or float, and c is char*,
otherwise those need adjusting. If I reverse the order in my C version:

printf("%=? %=? %=?\n", c, b, a);

It still works fine. If I try the same in the standard C version,
without fixing the formats, it crashes. gcc might warn, /if/ you specify
-Wformat. And then you still need to fix it.


> 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).

You don't want to make the emulation too good or people won't buy the
hardware...


Christian Gollwitzer

unread,
Sep 18, 2021, 5:30:05 PM9/18/21
to
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='Hallo'
>>> print(f'a={a} b={b} c={c}')
a=3 b=4 c=Hallo
>>>

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

>>> f'input_{a:03}.png'
'input_003.png'
>>>

...and, surprise:

Christian

Scott Lurndal

unread,
Sep 18, 2021, 6:49:09 PM9/18/21
to
Bart <b...@freeuk.com> writes:
>On 18/09/2021 15:54, Scott Lurndal wrote:
>> David Brown <david...@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.

Ian Collins

unread,
Sep 18, 2021, 7:04:14 PM9/18/21
to
On 19/09/2021 02:54, Scott Lurndal wrote:
> David Brown <david...@hesbynett.no> writes:
>> On 17/09/2021 23:34, Ian Collins wrote:
>
>>>
>>> Maybe a better compiler would help?  With clang++ and -O2:
>>>
>> Or pretty much any version of gcc with -O2, at least according to my
>> 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.

But you still used it to back up an exaggerated claim regarding the
performance of std::string! If you are using such an old compiler for
production code, you have made a rod for your own back.

>> 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.

Until you need to stream non-trivial objects, or anything in a template...

>> 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.

This is certainly true.

--
Ian

Bart

unread,
Sep 18, 2021, 7:47:06 PM9/18/21
to
You're just picking holes, aren't you?

I don't see the problem with field widths. While internationalisation is
a separate aspect that is not a problem I've ever had in 99.999% of my
uses of printf.

But grappling with the correct format codes has ALWAYS been a problem,
and needs a solution, not nit-picking ideas because you're trying to put
someone down.

(I used a different approach to locale-specific printing decades ago, so
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.)



Bart

unread,
Sep 18, 2021, 8:09:51 PM9/18/21
to
Simple Print is one of the most diverse features in program languages
(just take a look through Rosetta Code).

Scripting languages tend to do better, although most seem to want to do
it via functions in libraries, sometimes requiring special features of
the language (in C, it's variadic functions and parameters).

One of the best IMV was BASIC:

PRINT A, B, C ' 1960s and 70s

and I can do the same:

print A, B, C

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.

(The "=" feature of mine adds a label; invaluable for debugging code,
but elsewhere you usually have to either repeat the expression as a
string, or knock up some C macro to avoid the duplication.)

>
>> 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
>
> >>> f'input_{a:03}.png'
> 'input_003.png'
> >>>
>
> ...and, surprise:

If you have string processing anyway, then there are many more
possibilities to getting formatted results. But sticking with formatted
Print, this becomes in my languages:

fprint "input_#.png", a:"z3" # statement-style

s := sfprint("input_#.png", a:"z3") # expression-style

I like the format string to be clean, and free of clutter, so that I can
more easily see what it's supposed to look like!

Christian Gollwitzer

unread,
Sep 19, 2021, 2:06:26 AM9/19/21
to
Am 19.09.21 um 01:46 schrieb Bart:
> On 18/09/2021 23:48, Scott Lurndal wrote:
>> Bart <b...@freeuk.com> writes:
>>> On 18/09/2021 15:54, Scott Lurndal wrote:
>>>> David Brown <david...@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).

Christian

red floyd

unread,
Sep 19, 2021, 2:45:24 AM9/19/21
to
On 9/18/2021 5:09 PM, Bart wrote:

> 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.
>

boost::format? Or C++20 std::format?

Bart

unread,
Sep 19, 2021, 5:27:26 AM9/19/21
to
But this is not what printf does? That has n$ positional codes, which is
not affected by my suggestion to use, for example, "?" instead of "d",
"f", "s" etc to denote the type of the result.

(And if a format string ends in a list outside the program, it's better
that "?" was in there, than "d" "lld" etc, which now become extra
program code to maintain.)

My point, again, was that this stuff is not the problem with Print in C
and C++ that I was addressing.

(Does C++ have keyword arguments yet? A vastly more useful feature in
everyday coding. If not, then implement those and then we'll talk about
positional print items, which can trivially be dealt with in user-code.)

>
> "The {animal} bites {name}"
> into
> "{name} gets bitten by the {animal}"
>

That seems a reasonable way of doing that, except that the second line
will be translated into the target language; you need to ensure that
'name' and 'animal', identifiers in the source code, are not translated too!

(I would still prefer that those names, which are really expressions,
were outside the string, with a positional scheme like printf's applied
if necessary.

Being expressions, they can presumably include embedded format strings too?)

Anyway, in many applications I've seen, people don't really bother
getting things right even in English: in Windows I often see "1 Files"
being shown (now improved to "1 File(s)"!), when the program /knows/ the
quantity and can easy display either "1 File" or "5 Files".

This is an example of my code from last century (here using string
processing not formatted print):

smcmd((nfiles=0|/"No Files"|(nfiles=1|"1 " + /"File"|str(nfiles) +
/"Files")))

It shows 'No files' or '1 File' or 'N Files'. In Dutch, it would show
'Geen bestanden' or '1 Bestand' or 'N Bestanden'. (I supported German
and French too.)

I can't remember the details, but if there were differences in word
order, then the whole phrase was translated when there were no variable
parts.

Juha Nieminen

unread,
Sep 19, 2021, 6:12:26 AM9/19/21
to
Scott Lurndal <sc...@slp53.sl.home> wrote:
> 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.

While not super rare, it's nevertheless relatively uncommon to need maximum
I/O throughput in most applications that, for example, use this kind of
class as discussed in this thread. In the vast majority of situations,
even in very CPU-intensive number-crunching applications, the I/O speed
is largely irrelevant (because the amount of data to be printed isn't
that great, nor requires maximum speed).

Even in the cases where one *does* need maximum efficiency in I/O
(this would often be some kind of program that handles enormous
amounts of input and/or output data, eg. in some kind of server
or other similar application, requiring the program to read and/or
write gigabytes and gigabytes of data as fast as possible), any
experienced C++ programmer will know that std::ostream and
dynamically allocated strings will not be appropriate for this,
and will use something else. However, even in this case it's not
like having the operator<<() there is going to hurt something.
If it's not suitable for the task at hand, simply don't use it.

There are some situations where having a suitable operator<<()
overload for a particular type is very practical and handy.
Such as, for example, when using Google Test (which has extensive
support for adding additional information to an error message
via operator<< overloads.)

Juha Nieminen

unread,
Sep 19, 2021, 6:17:52 AM9/19/21
to
Scott Lurndal <sc...@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.

It kind of has taken the mantle of gcc 2, which likewise was in very
wide use years and years after it had become completely obsolete and
antiquated (as, IIRC, it didn't even support 100% of C++98.)
The difference is that gcc 4 has persisted for a *lot* longer than
gcc 2 did.

I blame certain Linux distros for this.

Juha Nieminen

unread,
Sep 19, 2021, 6:23:23 AM9/19/21
to
Bart <b...@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 <<?

Bart

unread,
Sep 19, 2021, 7:04:41 AM9/19/21
to
On 19/09/2021 11:23, Juha Nieminen wrote:
> Bart <b...@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?

It prints the whole expression not just the name, and is primarily for
debugging prints where large numbers of such temporary statements will
be added and removed. With C, it would make my RSI worse.

C allows you to define a macro to reduce that duplication, example:

#define EQ(x) #x "=",x

where the expression is an exact copy of what's in the source (although
I prefer them in upper case for emphasis). But if I plug that into my C
example:

printf("%s%d %s%f %s%s\n", EQ(a), EQ(b), EQ(c));

you find you're doing even more typing!

Of course for permanent print statements and more precise control, you
add those annotations more conventionally.

> 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 <<?
>

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.

Scott Lurndal

unread,
Sep 19, 2021, 10:08:05 AM9/19/21
to
Juha Nieminen <nos...@thanks.invalid> writes:
>Scott Lurndal <sc...@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.

It is the default compiler for Redhat 6 and Redhat 7 (and thus
the deriviations such as CentOS) which are widely used.

>
>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.

Juha Nieminen

unread,
Sep 19, 2021, 11:58:18 AM9/19/21
to
Scott Lurndal <sc...@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.

Juha Nieminen

unread,
Sep 19, 2021, 12:01:41 PM9/19/21
to
Bart <b...@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.

Bart

unread,
Sep 19, 2021, 12:40:07 PM9/19/21
to
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.

There is a default handler for the types known to the language, but a
user defined handler can be applied to a user type.

Example (the overloading syntax is crude, but it works):

record date=(var day,month,year)

function tostr_date(a,fmt)=
return sfprint("#/#/# CE", a.day, a.month, a.year)
end

d:=date(19,9,2021)

println d # default tostr shows '(19,9,2021)'

$setoverload(($tostr),date,tostr_date)

println d # custom tostr shows '19/9/2021 CE'


No binary overloads of some mysterious "<<" operator needed, although
'tostr' is really a binary operator; the second operand provides
optional format info, ignored in my example. If I write:

println d:"..."

then that "..." string appears as the fmt parameter, and it can be used
in any manner.

Scott Lurndal

unread,
Sep 19, 2021, 5:53:50 PM9/19/21
to
That is correct. As the worldwide data centers migrate to newer RHEL
releases, we're planning on GCC 7.3 as the baseline, which should
open up _some_ limited C++11 feature use (e.g. static_assert would be
useful to elimate some unnecessary runtime assertion checks).

Scott Lurndal

unread,
Sep 19, 2021, 5:54:35 PM9/19/21
to
Juha Nieminen <nos...@thanks.invalid> writes:
>Bart <b...@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());


Bart

unread,
Sep 19, 2021, 7:32:00 PM9/19/21
to
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.





Juha Nieminen

unread,
Sep 20, 2021, 1:21:09 AM9/20/21
to
Scott Lurndal <sc...@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).

You could have it like obj.to_string().c_str(), but that's not only awkward
to write, the entire idea of having to dynamically allocate a string, populate
it with the text you want to print (somehow) and then have it deleted is
needlessly inefficient, when overloading operator<<() avoids doing all that.

After all, you are probably thinking of very small objects with a very small
textual representation, with a known maximum length. That's not always the
case. Suppose your object contains a list of items, for example, and you want
the output to be the textual representation of the entire list. Are you going
to build up a std::string with this content and return it by value? Suppose
the list is so large that the std::string takes megabytes of RAM. Is this
supposed to be efficient and smart?

Using an operator<<() overload you don't need to do any of that. You can just
output every individual element to the std::ostream, one at a time, no matter
how many of them there are, requiring no dynamic memory allocations, requiring
pretty much no extra memory.

Juha Nieminen

unread,
Sep 20, 2021, 1:26:11 AM9/20/21
to
Bart <b...@freeuk.com> wrote:
>> 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.

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.

David Brown

unread,
Sep 20, 2021, 2:34:04 AM9/20/21
to
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.



Bart

unread,
Sep 20, 2021, 5:37:25 AM9/20/21
to
On 20/09/2021 06:25, Juha Nieminen wrote:
> Bart <b...@freeuk.com> wrote:
>>> 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.
>
> 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.

> 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.


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.

Plus some formatting options will require that you know the full string,
or at least its width, before you can start outputting the first characters.

The point of being able to do:

print x

for any object x is for convenience. If that's likely to be a problem,
then user-code can choose a different approach.

If there is no formatting involved or it is simple (can be done as it
goes), then the output can be optimised: instead of of building a single
large string, it can directly send it to the destination if it knows
what it is (eg. to some file handle).

I haven't yet done such an optimisation in the print handler of my
dynamic language.

Bart

unread,
Sep 20, 2021, 11:11:31 AM9/20/21
to
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.

(I would also separate the main job of Print - serialising values into
text - from doing any output.

My print statements also come as the function-like sprint()/sfprint()
that just return a string anyway.

While normal Print statements can take a optional destination that tell
it what to do with the text representation it creates:

print x # to console
print @f, x # to a file handle
print @s, x # to a string buffer
print @w, x # (old versions) to a GUI window
print @b, x # to an image buffer

Unlike streams, these are easy to get your head around.)

David Brown

unread,
Sep 20, 2021, 12:08:38 PM9/20/21
to
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.

>
> Now you're saying that we need more templates on top of that to make the
> syntax palatable.

No. I am saying that /if/ you really want to have the syntax "print(a,
b, c)", or /if/ you really want to have printing based on "to_string()"
methods, then you can do so.

The std::cout and iostream system has its limitations - we are all aware
of that. The C++ standards committee is aware of that, and there is a
new system in the works that is more modern. I'm sure plenty of people
will find things they like about the new system, and plenty will find
things they don't like - that is the nature of /every/ programming
language except perhaps ones written by a single person, and used by
that same single person.

>
> 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.

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>

Bart

unread,
Sep 20, 2021, 1:39:17 PM9/20/21
to
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.

Most of what C++ can do, can be done much more simply in any scripting
language, and much more quickly; it just won't run as fast.

Any new features, C++ also seems to delight in making as comprehensive
and complicated as possible (perhaps in keeping with the spirit of the
language!). My job tends to be the opposite.

>> 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>

Simple Print would suit a lot of people (ie. genuinely simple not just
piling on more layers in order to emulate 'simple')

Separating text conversions from i/o is also useful; 'cout' seems to
conflate those operations. My examples should have made it clear; I'm
sorry if I had to use my own language, since suitable alternatives are
thin on the ground.

Just pretend they are hypothetical pseudo-code; after all 'print x'
could be from anywhere (mostly from the 1970s unfortunately).


David Brown

unread,
Sep 20, 2021, 1:49:56 PM9/20/21
to
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.

Bart

unread,
Sep 20, 2021, 2:04:51 PM9/20/21
to
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.

(I think I first had PRINT going in a toy BASIC interpreter I knocked up
one bored afternoon, running on a PDP11. Although the expressions it
could deal with were very limited, it could still do:

20 PRINT X

so was still better than cout or printf 40+ years later!)



David Brown

unread,
Sep 20, 2021, 3:35:26 PM9/20/21
to
On 20/09/2021 20:04, Bart wrote:
> 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.

Implementing it doesn't give you anything here except an inflated view
of your own opinion. /Using/ print systems in various languages is
relevant. But if you don't even know what "cout" is or how "<<" works
in C++, it is pointless to compare it to anything else. And since your
experience of C++ appears mostly to be "What can I find to complain
about today?", rather than trying to actually /use/ it, I don't see you
as being in a position to judge.

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.

I've nothing against opinions about things that people have tried and
disliked, or found inferior in some ways - it's the knee-jerk blind
prejudice that bugs me.

(And in case you think I am biased in the other direction, you can read
some of my opinions on C++ iostreams in other posts here.)

Bart

unread,
Sep 20, 2021, 4:38:24 PM9/20/21
to
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.

Paavo Helde

unread,
Sep 20, 2021, 6:16:16 PM9/20/21
to
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.





Ian Collins

unread,
Sep 20, 2021, 6:29:08 PM9/20/21
to
On 21/09/2021 08:38, Bart wrote:

> 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.

You have hit the nail squarely on the head there. Simple prints are
great so long as the designers defaults match your needs. Things get
ugly fast once you need something different!

A search for "python print no newline" is a good illustration :)

--
Ian,

Bart

unread,
Sep 20, 2021, 7:39:19 PM9/20/21
to
Well, the pencil on my desk was probably also made by more than one
person! While the bike probably /could/ be made by an individual.

If the equivalent of my everyday Print task is going to the shops to buy
some milk, then you will find a bicycle more apt for that purpose than
an airplane.

I just don't see the need for a programming language to be so complex
that it takes many man-years to implement it. I like my tools lightweight.

This is not just about Print either; everything in C++ seems designed to
be the opposite of simple. That's why I said I look at C++ to find out
how /not/ to do things.

Bo Persson

unread,
Sep 21, 2021, 3:08:26 AM9/21/21
to
On 2021-09-20 at 22:38, Bart wrote:

> 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.
>

Yes, the BASIC print works well for built in types, but how do you
extend it to works with user defined types? Wait, in BASIC that is not a
problem (you just don't allow user defined types :-).

I have seen the same feature in Pascal, where READ and WRITE worked
similarly well, for the built in types. I looked long and hard for the
way to output one of my records - only to find that you could not.

Still remember how disappointed I was - a nice language feature that
only worked for some simple types, but not for the types I actually used
in the program. See "useless".

David Brown

unread,
Sep 21, 2021, 3:40:04 AM9/21/21
to
On 20/09/2021 22:38, Bart wrote:
> 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

No one cares about how easy or hard it is to implement. Seriously.
Rounded to the nearest 0.01% of programmers, /no one/ cares. The
important thing is how people can /use/ the feature in the language, not
how it is implemented!

And how you want to /use/ your print features depends on the language
and what you want to do with it. 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. It does not even provide a "print" function as part of the
language itself. It provides ways to make printing functionality. Then
it can have one or more printing implementation as part of the standard
library, for the convenience of users - while letting them make their
own systems to suit more specialised needs, with their own balance of
pros and cons.

Thus C++ has printf that works reasonably for translations and
formatting, but not for different types, and it has std::cout that works
well for different types, but not for translations and formatting. And
there is a new (C++20) formatting library that should work well for
translations, formatting /and/ different types, but is sure to have
other disadvantages (I haven't used it myself as yet). And in my own
code I often use my own system because I have different needs from those
of most C++ programmers.

>
>   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++.
>

The first version is easiest for a quick and dirty script. The second
is better for more serious programming. (I am not mocking quick and
dirty coding - that is suitable for a great deal of work, but it is
certainly not suitable for everything.)

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.

>> 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.
>

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.

Bart

unread,
Sep 21, 2021, 6:12:24 AM9/21/21
to
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!

> In fact, /no/ single solution will do everything.

But it might do 90% of it.

> 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.

Some things are just no-brainers.

> So a good, serious programming language does not provide a "print"
> statement.

Yeah. And the better ones also do away with mutability. And global
variables (see new 'pen' language). And loops. And of course goto.

>> 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.

Most of my uses of Print are quick and dirty:

* Because I add and remove such statements extensively for debugging, so
the total number of Prints written are much greater than than the number
of static Print statements in a finished program

* I also use it a lot for large numbers of throwaway programs, test
programs, code posted on forums, etc, in a variety of languages.

C's printf is poor in that regard, but I think C++'s cout might just pip
it. However Zig's print facilities I think are even worse; once you've
figured out how to do it once, you have to keep that example locked away
for future reference!


> The second
> is better for more serious programming.

So give me an example of serious programming where:

println X

is no good at all, and you're better off with:

std::cout << X << "\n";

> 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.

SQR comes from BASIC (most languages use 'sqrt'). Many also have such
abilities built-in, because it's convenient.

In mine, sqrt is an operator. You don't need to include or import
anything; it's just there. And usually mapped to an x64 'sqrtsd'
instruction, but that's up to the backend.

Now look at the abs() function, and you realise why it is BETTER to have
such things properly built-in, and not just a bunch of templates. In C,
you have these variations:

abs(x) // these need stdlib.h
labs(x)
llabs(x)
fabs(x) // these need math.h
fabsf(x)

Maybe there's some more, I don't know. I just have 'abs', and it works
on any suitable type, because it's a unary operator like 'negate'.

> 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.

You say you like Python.

Python also injects implicit spaces and implicit new lines. But that's
OK, even though it is a PITA to figure out how to suppress them.

But C++, where it is a PITA to have to add explicit spaces and newlines,
is also fine.

The only place it isn't fine, apparently, is my language, where I have
implicit spaces and explicit newlines!

There /is/ a simple way to suppress spaces, but if you don't know what
it is, then instead of writing:

print "ABC","DEF" # ABC DEF

you have the option to just split the print into two:

print "ABC"; print "DEF" # ABCDEF

Because of how it works. In Python, you HAVE to go and look this up, as
splitting a print will just insert a newline instead of a space.

(Space suppression between my print items uses: ",," instead of ",".
When that gets too ugly, then you use formatted print.)


> 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.

I want to port an algorithm which is expressed in both language A and
language B, into a new language.

Suppose A and B were C++ and BASIC; which do you think would be simplest
to work from?

The chances are that it will be BASIC, since most of its features exist
also in many other languages.

With C++, especially if written by Bonita Montero, it would likely mean
first implementing a dozen C++ libraries that it will depend on, and
disentangling a mess of arcane syntax.

You shouldn't really write off a language for language for being too simple.

It actuality, that simpler language, more likely to use mostly simple,
universal features, might be something like Lua or Python. Or even C,
provided the author hasn't gone mad with macros.

Paavo Helde

unread,
Sep 21, 2021, 8:45:28 AM9/21/21
to
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?

Bart

unread,
Sep 21, 2021, 9:38:00 AM9/21/21
to
A variety of Print is in pretty much every language; it's a fundamental
feature. Why try to justify a naff implementation of it? But at least
C++'s version is different! If little copied...

It doesn't necessary mean writing to STDOUT either. Most runtime calls
to Print are likely to be to a file, or will captured by redirection.

Others might be to a string.

(My biggest use of C's *printf routines via a FFI was to sprintf, to
assemble strings. But hardcoding format codes /outside of C/, which
varied across OSes anyway, was problematical. I now have my own
formatted print.)

> 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.

However, in /my language/ (I'm not going to do a survey of a dozen
others) you define a destination like this:

print @dest, x
print @con, x # same as print x

Until you mentioned it, I didn't know about cerr at all. I guess there's
a different syntax again for a file.

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...


> Why should such a
> facility get some special short name and simplified syntax?

I explained why in my post. Because printing to the console is used
extensively during debugging.

Paavo Helde

unread,
Sep 21, 2021, 10:09:16 AM9/21/21
to
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.

>
>> 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.

Yes I can. C++ has lots and 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...

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.

Bart

unread,
Sep 21, 2021, 11:26:20 AM9/21/21
to
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.


>> 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.

You mean, like 'exit'?! 'exit' in my languages is used for loop break.

It causes problems when I want to use C's exit() as portable way to
terminate my program. "exit" is exported by the C library.

(I have to define it as `exit instead, which allows the use of reserved
words or case-sensitive names.)

Your example can be dealt with using a different tense (actual code):

repeat
khandlertable[pcptr^]^()
until stopped

Scott Lurndal

unread,
Sep 21, 2021, 11:36:25 AM9/21/21
to
Bart <b...@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.

Scott Lurndal

unread,
Sep 21, 2021, 11:38:12 AM9/21/21
to
He could resurrect COBOL's "STOP RUN" instead of Fortran's "STOP". :-)

Horsey...@the_stables.com

unread,
Sep 21, 2021, 11:50:08 AM9/21/21
to
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.

David Brown

unread,
Sep 21, 2021, 12:04:53 PM9/21/21
to
"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";
}

Scott Lurndal

unread,
Sep 21, 2021, 12:21:27 PM9/21/21
to
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.

Bart has never even been _close_ to an ivory tower.

Bo Persson

unread,
Sep 21, 2021, 12:34:15 PM9/21/21
to
Yes, it makes it extendable to new types. My types specifically.

>
>
>> 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!
>

So now we get one more way to do the exact same thing, just a bit shorter.

I can already see the next post saying that C++ is now even bigger and
harder too learn. And when I change a typedef, suddenly all my print
statements stop working. Why?

Bart

unread,
Sep 21, 2021, 12:46:07 PM9/21/21
to
Somebody should tell Microsoft then.

Their CL compiler shows error messages on stdout no stderr.

So does DMC, Walter Bright's C compiler.

As does mine, since I consider the console the error device. However
getting STDERR on Windows, if you're not using C, is not actually that easy.

The WinAPI provides GetStdHandle to retrieve a suitable error handler,
but that only works if also using WinAPI for all console output, using
that handle.

I like to do console output via printf in msvcrt.dll, but that doesn't
provide a means that I can see, to get a compatible value of its stderr
through its DLL interface.

(Other than using non-portable means to directly access the FILE
structures via __iob_func(), since on Windows, stdout etc are not just
small integers.)

However, this is not specifically about my language nor about Windows.

Somebody asked, how to do STDERR output via a syntax based on 'print
a,b,c'; and I showed how - same as doing output to a file.

Scott Lurndal

unread,
Sep 21, 2021, 1:02:47 PM9/21/21
to
Bart <b...@freeuk.com> writes:
>On 21/09/2021 16:36, Scott Lurndal wrote:
>> Bart <b...@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.

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."

C Standard, while not explicitly stating such, implies it.

n1256.pdf:

void error(char *function_name, char *format, ...)
{

va_list args;

va_start(args, format);
// print out name of function causing error
fprintf(stderr, "ERROR in %s: ", function_name);
// print out remainder of message
vfprintf(stderr, format, args);
va_end(args);
}

Paavo Helde

unread,
Sep 21, 2021, 1:11:49 PM9/21/21
to
21.09.2021 19:45 Bart kirjutas:
> On 21/09/2021 16:36, Scott Lurndal wrote:
>> Bart <b...@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.

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).


Bart

unread,
Sep 21, 2021, 1:16:56 PM9/21/21
to
It's not clear what that document is about, but seems to refer to a lot
of C headers.

In case of a C (or C++) compiler and where it writes its output, who's
to say what language it might be written in. It might even be a
cross-compiler running on a system where your document has no jurisdiction.

> 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. They probably emanated from the
same place that inflicted case-sensivity and 0-baseness on everyone.

Bart

unread,
Sep 21, 2021, 1:33:21 PM9/21/21
to
Here's what I get:

C:\c>type c.c
int main(void) {
print a,b,c;
}

C:\c>cl c.c >out.txt 2>err.txt

C:\c>type out.txt
c.c
c.c(2): error C2065: 'print': undeclared identifier
c.c(2): error C2146: syntax error: missing ';' before identifier 'a'
c.c(2): error C2065: 'a': undeclared identifier
c.c(2): error C2065: 'b': undeclared identifier
c.c(2): error C2065: 'c': undeclared identifier

C:\c>type err.txt
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29337 for x64
Copyright (C) Microsoft Corporation. All rights reserved.


> 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).

So what you are saying is that CL is doing the right thing? The
copyright messages go to STDERR, while actual program *error messages*
go to STDOUT?

Which is the opposite to what happens with gcc:

C:\c>gcc c.c --verbose >out.txt 2>err.txt

C:\c>type out.txt

C:\c>type err.txt
Using built-in specs.
COLLECT_GCC=gcc
.... <snip long output>
c.c: In function 'main':
c.c:2:5: error: unknown type name 'print'; did you mean 'int'?
2 | print a,b,c;
| ^~~~~
| int

Although that doesn't quite get it right either: it sends ALL its output
to STDERR, even informative messages, and nothing at all to STDOUT.

Two major compilers and /they/ don't know how to handle STDOUT and STDERR!

I said I'm not interested in separate output streams (when running GUI
programs I used a console for special messages; I didn't need two
consoles!), but if I was to use both STDOUT and STDERR, at least I would
get it right.

Paavo Helde

unread,
Sep 21, 2021, 1:44:07 PM9/21/21
to
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.

Bart

unread,
Sep 21, 2021, 1:59:21 PM9/21/21
to
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?

Just checking...


Paavo Helde

unread,
Sep 21, 2021, 2:20:58 PM9/21/21
to
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.


Keith Thompson

unread,
Sep 21, 2021, 2:51:11 PM9/21/21
to
David Brown <david...@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).

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

Scott Lurndal

unread,
Sep 21, 2021, 2:52:44 PM9/21/21
to
The output of GCC is an object file. Any other output is
diagnostic output and rightly belongs on stderr.

Keith Thompson

unread,
Sep 21, 2021, 2:53:29 PM9/21/21
to
Bart <b...@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.

Bart

unread,
Sep 21, 2021, 3:33:05 PM9/21/21
to
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?

Because I don't understand how they can both be right if they are doing
opposite things; ONE of them must be wrong!

I'm getting the feeling that someone here is winding me up...

Bart

unread,
Sep 21, 2021, 3:49:02 PM9/21/21
to
On 21/09/2021 19:53, Keith Thompson wrote:
> Bart <b...@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.

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 is loading more messages.
0 new messages