• rational numbers

    From alessandro volturno@21:1/5 to All on Thu Sep 16 14:59:13 2021
    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?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Thu Sep 16 16:40:09 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to alessandro volturno on Thu Sep 16 17:05:03 2021
    alessandro volturno <alessandro.volturno@libero.it> writes:
    Il 16/09/2021 15:40, Paavo Helde ha scritto:
    16.09.2021 15:59 alessandro volturno kirjutas:

    Maybe my question is stupid, but
    why not to introduce a way to handle rational numbers inside the C++
    standard or better make it a built in type?

    I speak as a non-competent, hobbyist programmer and computer-user.

    What are the use cases for rationals? If something is not in the
    standard, then often there are different use cases which cannot be
    easily covered by a common "standard" implementation.

    Computers were born to manipulate numbers and the languages for doing
    that, at that time, were mainly two: FORTRAN, and LISP. I have noticed
    that C++ (that I presume it could be thought of as a descendant of
    FORTRAN, is shifting towards Functional programming language facilities,
    like that offered by the LISP family. That's good, but numerical
    programming is still important nowadays.

    I suspect that the vast majority of people use existing
    software packages like Matlab or R (for statistics) than write C++ code
    for numerical software nowadays. It's really hard to get it
    right when using binary floating point, hence standard numerical
    libraries (LINPACK, et alia).

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From alessandro volturno@21:1/5 to All on Thu Sep 16 18:24:46 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to Scott Lurndal on Thu Sep 16 19:58:10 2021
    On 9/16/2021 7:05 PM, Scott Lurndal wrote:
    alessandro volturno <alessandro.volturno@libero.it> writes:
    Il 16/09/2021 15:40, Paavo Helde ha scritto:
    16.09.2021 15:59 alessandro volturno kirjutas:

    Maybe my question is stupid, but
    why not to introduce a way to handle rational numbers inside the C++
    standard or better make it a built in type?

    I speak as a non-competent, hobbyist programmer and computer-user.

    What are the use cases for rationals? If something is not in the
    standard, then often there are different use cases which cannot be
    easily covered by a common "standard" implementation.

    Computers were born to manipulate numbers and the languages for doing
    that, at that time, were mainly two: FORTRAN, and LISP. I have noticed
    that C++ (that I presume it could be thought of as a descendant of
    FORTRAN, is shifting towards Functional programming language facilities,
    like that offered by the LISP family. That's good, but numerical
    programming is still important nowadays.

    I suspect that the vast majority of people use existing
    software packages like Matlab or R (for statistics) than write C++ code
    for numerical software nowadays. It's really hard to get it
    right when using binary floating point, hence standard numerical
    libraries (LINPACK, et alia).

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


    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to alessandro volturno on Thu Sep 16 20:41:55 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Thu Sep 16 23:12:59 2021
    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!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Thu Sep 16 21:11:31 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben Bacarisse@21:1/5 to Bart on Thu Sep 16 21:26:19 2021
    Bart <bc@freeuk.com> writes:

    You get a similar problem with arbitrary precision floats. (At least,
    in my library. I don't know how others deal with it; I use upper
    limits on precision).

    Multiply two numbers with M and N digits of precision respectively,
    and the result will have M*N digits of precision, without the
    magnitude necessarily getting bigger.

    That sounds odd. If it's binary FP, multiplying 2 by 2 need not result
    in a result with more digits than the already exact operands. Do you
    always widen the mantissa in a multiplication?

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Ben Bacarisse on Thu Sep 16 21:54:26 2021
    On 16/09/2021 21:26, Ben Bacarisse wrote:
    Bart <bc@freeuk.com> writes:

    You get a similar problem with arbitrary precision floats. (At least,
    in my library. I don't know how others deal with it; I use upper
    limits on precision).

    Multiply two numbers with M and N digits of precision respectively,
    and the result will have M*N digits of precision, without the
    magnitude necessarily getting bigger.

    That sounds odd. If it's binary FP, multiplying 2 by 2 need not result
    in a result with more digits than the already exact operands. Do you
    always widen the mantissa in a multiplication?

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to Ben Bacarisse on Thu Sep 16 23:07:39 2021
    On 16 Sep 2021 22:26, Ben Bacarisse wrote:
    Bart <bc@freeuk.com> writes:

    You get a similar problem with arbitrary precision floats. (At least,
    in my library. I don't know how others deal with it; I use upper
    limits on precision).

    Multiply two numbers with M and N digits of precision respectively,
    and the result will have M*N digits of precision, without the
    magnitude necessarily getting bigger.

    That sounds odd. If it's binary FP, multiplying 2 by 2 need not result
    in a result with more digits than the already exact operands. Do you
    always widen the mantissa in a multiplication?

    I think Ben meant to write M + N, not M*N. :-o

    Consider the product of A = a*r^n and B = b*r^m, where a and b are
    integers and r is the numeral system radix.

    You get a result C = A*B = a*b*r^(n+m), where the number of digits of C
    is roughly (the number of digits of a) + (the number of digits of b).


    - Alf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to Alf P. Steinbach on Thu Sep 16 23:27:30 2021
    On 16 Sep 2021 23:07, Alf P. Steinbach wrote:
    On 16 Sep 2021 22:26, Ben Bacarisse wrote:
    Bart <bc@freeuk.com> writes:

    You get a similar problem with arbitrary precision floats. (At least,
    in my library. I don't know how others deal with it; I use upper
    limits on precision).

    Multiply two numbers with M and N digits of precision respectively,
    and the result will have M*N digits of precision, without the
    magnitude necessarily getting bigger.

    That sounds odd.  If it's binary FP, multiplying 2 by 2 need not result
    in a result with more digits than the already exact operands.  Do you
    always widen the mantissa in a multiplication?

    I think Ben meant to write M + N, not M*N. :-o

    Consider the product of A = a*r^n and B = b*r^m, where a and b are
    integers and r is the numeral system radix.

    You get a result C = A*B = a*b*r^(n+m), where the number of digits of C
    is roughly (the number of digits of a) + (the number of digits of b).

    I evidently meant to write "Bart", not "Ben".

    Oh well.


    - Alf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to alessandro volturno on Fri Sep 17 05:36:56 2021
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
    // numerical value

    This is not really something that belongs to a class that behaves like an arithmetic numerical value.

    At most what you could have is a separate

    std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From alessandro volturno@21:1/5 to All on Fri Sep 17 09:50:58 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From alessandro volturno@21:1/5 to All on Fri Sep 17 09:55:18 2021
    Il 17/09/2021 07:36, Juha Nieminen ha scritto:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
    // numerical value

    This is not really something that belongs to a class that behaves like an arithmetic numerical value.

    At most what you could have is a separate

    std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.


    if you read the two lines right before the one here reported you can see
    I did that.

    I wrote that function to give an extensive description of a rational
    number in a way like this:

    "4/16 reduces to 1/4 and evaluates to 0.25"

    thank you,

    alessandro

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Fri Sep 17 09:21:06 2021

    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Christian Gollwitzer on Fri Sep 17 10:34:57 2021
    On 17/09/2021 09:21, Christian Gollwitzer wrote:
        
    Am 16.09.21 um 19:05 schrieb Scott Lurndal:
    I suspect that the vast majority of people use existing
    software packages like Matlab or R (for statistics) than write C++ code
    for numerical software nowadays.  It's really hard to get it
    right when using binary floating point, hence standard numerical
    libraries (LINPACK, et alia).

    I am a scientist, and Matlab and R are popular, but slowly they give way
    to Python. With the "numpy" package wrapping LAPACK and "scipy", which
    is based on it, Python code almost looks like Matlab, but it's
    completely open source. To my understanding, that and the machine
    learning libs are the reasons why Python gained so much in the last
    years. The language on its own is not that much better than other modern scripting languages, it's the libraries with a large user base.


    Python might not be much better than Matlab as a language for the
    numerical bits (I haven't done Matlab programming to compare), but as a
    general purpose language it is vastly more powerful for everything else
    than highly specialised and consequently limited tools like Matlab. All
    the extra capabilities from Python, such sending emails when your
    calculations are done, interacting with databases, generating pdf
    reports from the results, etc., are going to make it a lot more
    attractive if it can handle the maths you need.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Christian Gollwitzer on Fri Sep 17 22:07:14 2021
    On 17/09/2021 19:21, Christian Gollwitzer wrote:

    Am 16.09.21 um 19:05 schrieb Scott Lurndal:
    I suspect that the vast majority of people use existing
    software packages like Matlab or R (for statistics) than write C++ code
    for numerical software nowadays. It's really hard to get it
    right when using binary floating point, hence standard numerical
    libraries (LINPACK, et alia).

    I am a scientist, and Matlab and R are popular, but slowly they give way
    to Python. With the "numpy" package wrapping LAPACK and "scipy", which
    is based on it, Python code almost looks like Matlab, but it's
    completely open source. To my understanding, that and the machine
    learning libs are the reasons why Python gained so much in the last
    years. The language on its own is not that much better than other modern scripting languages, it's the libraries with a large user base.

    Matlab does have one advantage (at least in our environment); it can
    convert models into C++ code!

    --
    Ian.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to alessandro volturno on Fri Sep 17 11:15:48 2021
    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.


    Thank you again for the opportunity of this discussion.

    alessandro



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Ian Collins on Fri Sep 17 13:32:39 2021
    On 17/09/2021 12:07, Ian Collins wrote:
    On 17/09/2021 19:21, Christian Gollwitzer wrote:
        
    Am 16.09.21 um 19:05 schrieb Scott Lurndal:
    I suspect that the vast majority of people use existing
    software packages like Matlab or R (for statistics) than write C++ code
    for numerical software nowadays.  It's really hard to get it
    right when using binary floating point, hence standard numerical
    libraries (LINPACK, et alia).

    I am a scientist, and Matlab and R are popular, but slowly they give way
    to Python. With the "numpy" package wrapping LAPACK and "scipy", which
    is based on it, Python code almost looks like Matlab, but it's
    completely open source. To my understanding, that and the machine
    learning libs are the reasons why Python gained so much in the last
    years. The language on its own is not that much better than other modern
    scripting languages, it's the libraries with a large user base.

    Matlab does have one advantage (at least in our environment); it can
    convert models into C++ code!


    A few times in the past, I've seen C code generated by Matlab, produced
    by researchers who then wanted the whole think running in a little microcontroller. The generated code was utterly hideous - vastly
    over-complex, and ridiculous inefficiencies (malloc allocation for
    things that should be local stack variables, multiplying integers by 0.5 instead of dividing by 2, using strings and strcmp() instead of enums,
    etc.). But perhaps it was the user rather than the software that was at
    fault - it's not a tool I use myself. I just know that for use on a
    small microcontroller, I'd rather hand-translate some well-written
    Python than clear up the vomit that Matlab produced.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to alessandro volturno on Fri Sep 17 11:16:17 2021
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    Il 17/09/2021 07:36, Juha Nieminen ha scritto:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
    // numerical value

    This is not really something that belongs to a class that behaves like an
    arithmetic numerical value.

    At most what you could have is a separate

    std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.


    if you read the two lines right before the one here reported you can see
    I did that.

    I wrote that function to give an extensive description of a rational
    number in a way like this:

    "4/16 reduces to 1/4 and evaluates to 0.25"

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

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Fri Sep 17 15:55:15 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Ian Collins on Fri Sep 17 14:06:42 2021
    Ian Collins <ian-news@hotmail.com> writes:
    On 17/09/2021 19:21, Christian Gollwitzer wrote:

    Am 16.09.21 um 19:05 schrieb Scott Lurndal:
    I suspect that the vast majority of people use existing
    software packages like Matlab or R (for statistics) than write C++ code
    for numerical software nowadays. It's really hard to get it
    right when using binary floating point, hence standard numerical
    libraries (LINPACK, et alia).

    I am a scientist, and Matlab and R are popular, but slowly they give way
    to Python. With the "numpy" package wrapping LAPACK and "scipy", which
    is based on it, Python code almost looks like Matlab, but it's
    completely open source. To my understanding, that and the machine
    learning libs are the reasons why Python gained so much in the last
    years. The language on its own is not that much better than other modern
    scripting languages, it's the libraries with a large user base.

    Matlab does have one advantage (at least in our environment); it can
    convert models into C++ code!

    One of my colleagues wrote a tool (verilator) to convert Verilog
    into C++ code. Quite useful.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Juha Nieminen on Fri Sep 17 14:03:02 2021
    Juha Nieminen <nospam@thanks.invalid> writes:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
    // numerical value

    This is not really something that belongs to a class that behaves like an >arithmetic numerical value.

    At most what you could have is a separate

    std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    I could rant for hours on the unsuitability of the silly
    C++ output stream crap in real applications.

    But I've got too much on my plate right now. Much of which
    is making performance improvements to a large CPU-bound
    C++ application; primarily by getting rid of all outputstringstream
    crap (replacing with snprintf) and eliminating most trivial
    run-time (vs. startup time) uses of std::string.

    void
    a(void)
    {
    std::string fred = "this is a test";
    printf("%s", fred.c_str());
    }

    0000000000400970 <a()>:
    400970: 53 push %rbx
    400971: be 50 0b 40 00 mov $0x400b50,%esi
    400976: 48 83 ec 20 sub $0x20,%rsp
    40097a: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
    40097f: 48 8d 54 24 0f lea 0xf(%rsp),%rdx
    400984: e8 97 fe ff ff callq 400820 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)@plt>
    400989: 48 8b 74 24 10 mov 0x10(%rsp),%rsi
    40098e: bf 5f 0b 40 00 mov $0x400b5f,%edi
    400993: 31 c0 xor %eax,%eax
    400995: e8 36 fe ff ff callq 4007d0 <printf@plt>
    40099a: 48 8b 44 24 10 mov 0x10(%rsp),%rax
    40099f: 48 8d 78 e8 lea -0x18(%rax),%rdi
    4009a3: 48 81 ff 80 10 60 00 cmp $0x601080,%rdi
    4009aa: 75 06 jne 4009b2 <a()+0x42>
    4009ac: 48 83 c4 20 add $0x20,%rsp
    4009b0: 5b pop %rbx
    4009b1: c3 retq
    4009b2: b9 00 00 00 00 mov $0x0,%ecx
    4009b7: 48 8d 57 10 lea 0x10(%rdi),%rdx
    4009bb: 48 85 c9 test %rcx,%rcx
    4009be: 74 35 je 4009f5 <a()+0x85>
    4009c0: 83 c8 ff or $0xffffffff,%eax
    4009c3: f0 0f c1 02 lock xadd %eax,(%rdx)
    4009c7: 85 c0 test %eax,%eax
    4009c9: 7f e1 jg 4009ac <a()+0x3c>
    4009cb: 48 8d 74 24 0f lea 0xf(%rsp),%rsi
    4009d0: e8 3b fe ff ff callq 400810 <std::string::_Rep::_M_destroy(std::allocator<char> const&)@plt>
    4009d5: eb d5 jmp 4009ac <a()+0x3c>
    4009d7: 48 89 c3 mov %rax,%rbx
    4009da: 48 8b 44 24 10 mov 0x10(%rsp),%rax
    4009df: 48 8d 74 24 0f lea 0xf(%rsp),%rsi
    4009e4: 48 8d 78 e8 lea -0x18(%rax),%rdi
    4009e8: e8 03 fe ff ff callq 4007f0 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    4009ed: 48 89 df mov %rbx,%rdi
    4009f0: e8 5b fe ff ff callq 400850 <_Unwind_Resume@plt>
    4009f5: 8b 50 f8 mov -0x8(%rax),%edx
    4009f8: 8d 4a ff lea -0x1(%rdx),%ecx
    4009fb: 89 48 f8 mov %ecx,-0x8(%rax)
    4009fe: 89 d0 mov %edx,%eax
    400a00: eb c5 jmp 4009c7 <a()+0x57>
    400a02: 66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
    400a09: 1f 84 00 00 00 00 00

    (and that's _with_ -O3).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Fri Sep 17 17:12:34 2021
    Am 17.09.21 um 16:03 schrieb Scott Lurndal:
    Juha Nieminen <nospam@thanks.invalid> writes:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
    // numerical value

    This is not really something that belongs to a class that behaves like an
    arithmetic numerical value.

    At most what you could have is a separate

    std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    I could rant for hours on the unsuitability of the silly
    C++ output stream crap in real applications.

    But I've got too much on my plate right now. Much of which
    is making performance improvements to a large CPU-bound
    C++ application; primarily by getting rid of all outputstringstream
    crap (replacing with snprintf) and eliminating most trivial
    run-time (vs. startup time) uses of std::string.

    void
    a(void)
    {
    std::string fred = "this is a test";
    printf("%s", fred.c_str());
    }

    [...long assembly...]

    Wow, thats an awful lot of code. Does it improve if you do const
    std::string or constexpr or the like?

    Christian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Fri Sep 17 17:16:37 2021
    Am 17.09.21 um 17:12 schrieb Christian Gollwitzer:
    Am 17.09.21 um 16:03 schrieb Scott Lurndal:
    Juha Nieminen <nospam@thanks.invalid> writes:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
                        // numerical value

    This is not really something that belongs to a class that behaves
    like an
    arithmetic numerical value.

    At most what you could have is a separate

      std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    I could rant for hours on the unsuitability of the silly
    C++ output stream crap in real applications.

    But I've got too much on my plate right now. Much of which
    is making performance improvements to a large CPU-bound
    C++ application;  primarily by getting rid of all outputstringstream
    crap (replacing with snprintf) and eliminating most trivial
    run-time (vs. startup time) uses of std::string.

    void
    a(void)
    {
         std::string fred = "this is a test";
         printf("%s", fred.c_str());
    }

    [...long assembly...]

    Wow, thats an awful lot of code. Does it improve if you do const
    std::string or constexpr or the like?

        Christian

    Quick test on compiler explorer shows a much more reasonable code: https://godbolt.org/z/5MzscK95W

    with gcc 11.

    Christian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Christian Gollwitzer on Fri Sep 17 17:49:58 2021
    On 17/09/2021 15:55, Christian Gollwitzer wrote:
    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.


    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From alessandro volturno@21:1/5 to All on Fri Sep 17 18:33:28 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Fri Sep 17 18:22:09 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to Christian Gollwitzer on Fri Sep 17 18:59:54 2021
    On 9/17/2021 5:16 PM, Christian Gollwitzer wrote:
    Am 17.09.21 um 17:12 schrieb Christian Gollwitzer:
    Am 17.09.21 um 16:03 schrieb Scott Lurndal:
    Juha Nieminen <nospam@thanks.invalid> writes:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
                        // numerical value

    This is not really something that belongs to a class that behaves
    like an
    arithmetic numerical value.

    At most what you could have is a separate

      std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    I could rant for hours on the unsuitability of the silly
    C++ output stream crap in real applications.

    But I've got too much on my plate right now. Much of which
    is making performance improvements to a large CPU-bound
    C++ application;  primarily by getting rid of all outputstringstream
    crap (replacing with snprintf) and eliminating most trivial
    run-time (vs. startup time) uses of std::string.

    void
    a(void)
    {
         std::string fred = "this is a test";
         printf("%s", fred.c_str());
    }

    [...long assembly...]

    Wow, thats an awful lot of code. Does it improve if you do const
    std::string or constexpr or the like?

         Christian

    Quick test on compiler explorer shows a much more reasonable code: https://godbolt.org/z/5MzscK95W

    with gcc 11.

        Christian

    Still,

    Feeding a C string to a std::string to be fed to printf() /is/ masochism
    (or sadism, depending on which side you are on).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Manfred on Fri Sep 17 17:13:45 2021
    Manfred <noname@add.invalid> writes:
    On 9/17/2021 5:16 PM, Christian Gollwitzer wrote:
    Am 17.09.21 um 17:12 schrieb Christian Gollwitzer:
    Am 17.09.21 um 16:03 schrieb Scott Lurndal:
    Juha Nieminen <nospam@thanks.invalid> writes:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
                        // numerical value

    This is not really something that belongs to a class that behaves
    like an
    arithmetic numerical value.

    At most what you could have is a separate

      std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    I could rant for hours on the unsuitability of the silly
    C++ output stream crap in real applications.

    But I've got too much on my plate right now. Much of which
    is making performance improvements to a large CPU-bound
    C++ application;  primarily by getting rid of all outputstringstream
    crap (replacing with snprintf) and eliminating most trivial
    run-time (vs. startup time) uses of std::string.

    void
    a(void)
    {
         std::string fred = "this is a test";
         printf("%s", fred.c_str());
    }

    [...long assembly...]

    Wow, thats an awful lot of code. Does it improve if you do const
    std::string or constexpr or the like?

         Christian

    Quick test on compiler explorer shows a much more reasonable code:
    https://godbolt.org/z/5MzscK95W

    with gcc 11.

        Christian

    Still,

    Feeding a C string to a std::string to be fed to printf() /is/ masochism
    (or sadism, depending on which side you are on).

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From alessandro volturno@21:1/5 to All on Fri Sep 17 19:19:32 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to David Brown on Sat Sep 18 09:15:22 2021
    On 17/09/2021 23:32, David Brown wrote:
    On 17/09/2021 12:07, Ian Collins wrote:
    On 17/09/2021 19:21, Christian Gollwitzer wrote:

    Am 16.09.21 um 19:05 schrieb Scott Lurndal:
    I suspect that the vast majority of people use existing
    software packages like Matlab or R (for statistics) than write C++ code >>>> for numerical software nowadays.  It's really hard to get it
    right when using binary floating point, hence standard numerical
    libraries (LINPACK, et alia).

    I am a scientist, and Matlab and R are popular, but slowly they give way >>> to Python. With the "numpy" package wrapping LAPACK and "scipy", which
    is based on it, Python code almost looks like Matlab, but it's
    completely open source. To my understanding, that and the machine
    learning libs are the reasons why Python gained so much in the last
    years. The language on its own is not that much better than other modern >>> scripting languages, it's the libraries with a large user base.

    Matlab does have one advantage (at least in our environment); it can
    convert models into C++ code!


    A few times in the past, I've seen C code generated by Matlab, produced
    by researchers who then wanted the whole think running in a little microcontroller. The generated code was utterly hideous - vastly over-complex, and ridiculous inefficiencies (malloc allocation for
    things that should be local stack variables, multiplying integers by 0.5 instead of dividing by 2, using strings and strcmp() instead of enums,
    etc.). But perhaps it was the user rather than the software that was at fault - it's not a tool I use myself. I just know that for use on a
    small microcontroller, I'd rather hand-translate some well-written
    Python than clear up the vomit that Matlab produced.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Scott Lurndal on Sat Sep 18 09:34:25 2021
    On 18/09/2021 02:03, Scott Lurndal wrote:
    Juha Nieminen <nospam@thanks.invalid> writes:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
    // numerical value

    This is not really something that belongs to a class that behaves like an
    arithmetic numerical value.

    At most what you could have is a separate

    std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    I could rant for hours on the unsuitability of the silly
    C++ output stream crap in real applications.

    But I've got too much on my plate right now. Much of which
    is making performance improvements to a large CPU-bound
    C++ application; primarily by getting rid of all outputstringstream
    crap (replacing with snprintf) and eliminating most trivial
    run-time (vs. startup time) uses of std::string.

    void
    a(void)
    {
    std::string fred = "this is a test";
    printf("%s", fred.c_str());
    }

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

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to alessandro volturno on Fri Sep 17 19:00:29 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to alessandro volturno on Sat Sep 18 11:39:18 2021
    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).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From alessandro volturno@21:1/5 to All on Sat Sep 18 11:56:26 2021
    Il 18/09/2021 11:39, David Brown ha scritto:
    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).

    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Sat Sep 18 11:01:43 2021
    On 18/09/2021 10:39, David Brown wrote:
    On 17/09/2021 19:19, alessandro volturno wrote:


    The only advantage what rationals offer above floating-point is that >>>>> the calculation results are always exact. However, in numeric
    programming the input data often comes from a physical measurement,
    meaning that it already contains measurement inaccuracies.

    Physics is not the only Science out there


    You were the one that brought up physics ("I am not a mathematician or a physicist"). /All/ sciences - to be worthy of the name "science" -
    involve measurements of real things. Almost always, these are inexact measurements, with the exceptions being relatively small whole number
    counts. Rational numbers turn up very rarely in science of any kind. Probably the only science in which they /do/ turn up is quantum
    mechanics in physics, and even there we are talking about small and
    specific values (half-integer spin, third or two-third charges on
    quarks, that kind of thing).

    Rational arithmetic does not really turn up anywhere outside pure
    mathematics and certain direct applications (such as in cryptography).

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Ian Collins on Sat Sep 18 12:00:03 2021
    On 17/09/2021 23:34, Ian Collins wrote:
    On 18/09/2021 02:03, Scott Lurndal wrote:
    Juha Nieminen <nospam@thanks.invalid> writes:
    alessandro volturno <alessandro.volturno@libero.it> wrote:
    printDescription() // prints a description of the number and its
                        // numerical value

    This is not really something that belongs to a class that behaves
    like an
    arithmetic numerical value.

    At most what you could have is a separate

      std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    I could rant for hours on the unsuitability of the silly
    C++ output stream crap in real applications.

    But I've got too much on my plate right now. Much of which
    is making performance improvements to a large CPU-bound
    C++ application;  primarily by getting rid of all outputstringstream
    crap (replacing with snprintf) and eliminating most trivial
    run-time (vs. startup time) uses of std::string.

    void
    a(void)
    {
         std::string fred = "this is a test";
         printf("%s", fred.c_str());
    }


    (and that's _with_ -O3).

    Maybe a better compiler would help?  With clang++ and -O2:

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to David Brown on Sat Sep 18 14:54:33 2021
    David Brown <david.brown@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).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Scott Lurndal on Sat Sep 18 17:36:45 2021
    On 18/09/2021 15:54, Scott Lurndal wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 17/09/2021 23:34, Ian Collins wrote:


    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.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Sat Sep 18 23:29:47 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Scott Lurndal on Sun Sep 19 11:03:57 2021
    On 19/09/2021 02:54, Scott Lurndal wrote:
    David Brown <david.brown@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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bart on Sat Sep 18 22:48:54 2021
    Bart <bc@freeuk.com> writes:
    On 18/09/2021 15:54, Scott Lurndal wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 17/09/2021 23:34, Ian Collins wrote:

    snprintf makes a single pass over the formatting string. It's a single
    function call.

    C: printf("A=%d B=%f C=%s\n", a, b, c);

    A trivially useless format string. Try adding field widths and
    re-ordering the arguments within the format string for i18n/l10n
    purposes.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Christian Gollwitzer on Sun Sep 19 01:09:03 2021
    On 18/09/2021 22:29, Christian Gollwitzer wrote:
    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
    %

    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!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Scott Lurndal on Sun Sep 19 00:46:15 2021
    On 18/09/2021 23:48, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 18/09/2021 15:54, Scott Lurndal wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 17/09/2021 23:34, Ian Collins wrote:

    snprintf makes a single pass over the formatting string. It's a single
    function call.

    C: printf("A=%d B=%f C=%s\n", a, b, c);

    A trivially useless format string. Try adding field widths and
    re-ordering the arguments within the format string for i18n/l10n
    purposes.


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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Sun Sep 19 08:06:08 2021
    Am 19.09.21 um 01:46 schrieb Bart:
    On 18/09/2021 23:48, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 18/09/2021 15:54, Scott Lurndal wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 17/09/2021 23:34, Ian Collins wrote:

    snprintf makes a single pass over the formatting string.  It's a single >>>> function call.

    C:     printf("A=%d B=%f C=%s\n", a, b, c);

    A trivially useless format string.  Try adding field widths and
    re-ordering the arguments within the format string for i18n/l10n
    purposes.

    that I would write:

        println /"Serial number:", sn

    in my code, but at the customer site, it might output:

        Serie nummer: 1234

    if they spoke Dutch. "/" is a translation operator.)


    You didn't get the problem Scott was talking about. If you have more
    than 1 variable in a sentence, in the translation the word order might
    be changed. E.g.


    "The $animal bites $name"

    could be tranlsated as

    "$name gets bitten by the $animal"

    in some language.

    Therefore, if you do

    printf("The %s bites %s", "dog", "Harry")

    and the translator does

    "%s gets bitten by the %s"

    you will end up with

    "dog gets bitten by the Harry"

    If, however, there is proper string interpolation like in Python format strings, then the translator would translatate the string as above, changing

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

    and it would come out correctly. Obviously, there are still problems
    with inflections; in most languages the dog, Harry etc. are adapted
    depending on the function in the sentence (grammatical cases).

    Christian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From red floyd@21:1/5 to Bart on Sat Sep 18 23:45:03 2021
    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?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Scott Lurndal on Sun Sep 19 10:12:09 2021
    Scott Lurndal <scott@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.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Christian Gollwitzer on Sun Sep 19 10:26:35 2021
    On 19/09/2021 07:06, Christian Gollwitzer wrote:
    Am 19.09.21 um 01:46 schrieb Bart:
    On 18/09/2021 23:48, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 18/09/2021 15:54, Scott Lurndal wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 17/09/2021 23:34, Ian Collins wrote:

    snprintf makes a single pass over the formatting string.  It's a
    single
    function call.

    C:     printf("A=%d B=%f C=%s\n", a, b, c);

    A trivially useless format string.  Try adding field widths and
    re-ordering the arguments within the format string for i18n/l10n
    purposes.

    that I would write:

         println /"Serial number:", sn

    in my code, but at the customer site, it might output:

         Serie nummer: 1234

    if they spoke Dutch. "/" is a translation operator.)


    You didn't get the problem Scott was talking about. If you have more
    than 1 variable in a sentence, in the translation the word order might
    be changed. E.g.


        "The $animal bites $name"

    could be tranlsated as

        "$name gets bitten by the $animal"

    in some language.

    Therefore, if you do

    printf("The %s bites %s", "dog", "Harry")

    and the translator does

        "%s gets bitten by the %s"

    you will end up with

        "dog gets bitten by the Harry"

    If, however, there is proper string interpolation like in Python format strings, then the translator would translatate the string as above,
    changing

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

    and it would come out correctly. Obviously, there are still problems
    with inflections; in most languages the dog, Harry etc. are adapted
    depending on the function in the sentence (grammatical cases).

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Scott Lurndal on Sun Sep 19 10:17:37 2021
    Scott Lurndal <scott@slp53.sl.home> wrote:
    One quite often runs across C++ purists (or new grads) who falsly eschew
    C constructs as "not C++".

    My response to them is that "if it's in the C++ standard, then it's C++, through and through. Use the tools that are best for the task at hand."

    Just because something is "inherited" from C (so to speak) doesn't mean
    it's not suitable and perfectly valid to use in C++. After all, keywords
    like 'for' and 'if' are inherited from C. Does that mean they shouldn't
    be used in C++? Why is using those ok, but eg. using std::printf() is not? What's the difference?

    Unfortunately, we need to support GCC4 through GCC11 efficiently.

    I find it fascinating how common gcc 4 is still out there in the wild,
    even to this day.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Sun Sep 19 10:23:05 2021
    Bart <bc@freeuk.com> wrote:
    Both approaches are terrible in my opinion:

    C++: std::cout << "A=" << a << " B=" << b << " C=" << c << std::endl;

    C: printf("A=%d B=%f C=%s\n", a, b, c);

    Compared with the equivalent in any of my languages:

    M: println =a, =b, =c

    Uh... println in your languages will automatically print "name=" before printing the value of a variable? What if you want to use spaces around
    the '='? What if you want to use another character instead, like ':',
    and have a space only after that character but not before it?

    Anyway, it's relatively easy in C++ to implement a function that behaves
    like std::ostream, but uses a function call syntax instead, like:

    myprint("a=", a, ", b=", b, ", c=", c, "\n");

    The C++ just looks dreadful (and I keep forgetting the << or writing
    commas instead).

    It's C++'s fault that you keep forgetting the <<?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Sun Sep 19 12:04:23 2021
    On 19/09/2021 11:23, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    Both approaches are terrible in my opinion:

    C++: std::cout << "A=" << a << " B=" << b << " C=" << c << std::endl;

    C: printf("A=%d B=%f C=%s\n", a, b, c);

    Compared with the equivalent in any of my languages:

    M: println =a, =b, =c

    Uh... println in your languages will automatically print "name=" before printing the value of a variable? What if you want to use spaces around
    the '='? What if you want to use another character instead, like ':',
    and have a space only after that character but not before it?

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Juha Nieminen on Sun Sep 19 14:07:47 2021
    Juha Nieminen <nospam@thanks.invalid> writes:
    Scott Lurndal <scott@slp53.sl.home> wrote:
    One quite often runs across C++ purists (or new grads) who falsly eschew
    C constructs as "not C++".

    My response to them is that "if it's in the C++ standard, then it's C++, >through and through. Use the tools that are best for the task at hand."

    Just because something is "inherited" from C (so to speak) doesn't mean
    it's not suitable and perfectly valid to use in C++. After all, keywords
    like 'for' and 'if' are inherited from C. Does that mean they shouldn't
    be used in C++? Why is using those ok, but eg. using std::printf() is not? >What's the difference?

    Unfortunately, we need to support GCC4 through GCC11 efficiently.

    I find it fascinating how common gcc 4 is still out there in the wild,
    even to this day.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Sun Sep 19 16:01:26 2021
    Bart <bc@freeuk.com> wrote:
    Yes, because it is so peculiar. I wouldn't know how to create such a function, but it would have been a better way of presenting a print
    feature, and more conventional.

    The basic idea with overloading a binary operator, rather than using a
    function call syntax, is that the output can be expanded with your own
    custom types (which is not really possible if it used a function call
    syntax).

    In other words, you can achieve this:

    MyClass obj;
    std::cout << "Value = " << obj << "\n";

    I suppose there could be a contrived way of achieving the same thing
    with a function call syntax, ie. that you could write

    std::cout("Value = ", obj, "\n");

    but I'm not sure how simple that could be made to be. Especially in C++98.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Scott Lurndal on Sun Sep 19 15:58:03 2021
    Scott Lurndal <scott@slp53.sl.home> wrote:
    I blame certain Linux distros for this.

    I wouldn't use the verb "blame" here. Most programmers don't
    particularly care about the version of the compiler, so long as
    it works.

    Yeah, the problem with gcc 4 is that it doesn't support fully C++11
    (if I remember correctly), much less newer versions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Sun Sep 19 17:39:50 2021
    On 19/09/2021 17:01, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    Yes, because it is so peculiar. I wouldn't know how to create such a
    function, but it would have been a better way of presenting a print
    feature, and more conventional.

    The basic idea with overloading a binary operator, rather than using a function call syntax, is that the output can be expanded with your own
    custom types (which is not really possible if it used a function call syntax).

    In other words, you can achieve this:

    MyClass obj;
    std::cout << "Value = " << obj << "\n";

    I suppose there could be a contrived way of achieving the same thing
    with a function call syntax, ie. that you could write

    std::cout("Value = ", obj, "\n");

    but I'm not sure how simple that could be made to be. Especially in C++98.


    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Juha Nieminen on Sun Sep 19 21:53:34 2021
    Juha Nieminen <nospam@thanks.invalid> writes:
    Scott Lurndal <scott@slp53.sl.home> wrote:
    I blame certain Linux distros for this.

    I wouldn't use the verb "blame" here. Most programmers don't
    particularly care about the version of the compiler, so long as
    it works.

    Yeah, the problem with gcc 4 is that it doesn't support fully C++11
    (if I remember correctly), much less newer versions.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Juha Nieminen on Sun Sep 19 21:54:20 2021
    Juha Nieminen <nospam@thanks.invalid> writes:
    Bart <bc@freeuk.com> wrote:
    Yes, because it is so peculiar. I wouldn't know how to create such a
    function, but it would have been a better way of presenting a print
    feature, and more conventional.

    The basic idea with overloading a binary operator, rather than using a >function call syntax, is that the output can be expanded with your own
    custom types (which is not really possible if it used a function call >syntax).

    In other words, you can achieve this:

    MyClass obj;
    std::cout << "Value = " << obj << "\n";

    fprintf(stdout, "Value = %s\n" obj.to_string());

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Scott Lurndal on Mon Sep 20 00:31:42 2021
    On 19/09/2021 22:54, Scott Lurndal wrote:
    Juha Nieminen <nospam@thanks.invalid> writes:
    Bart <bc@freeuk.com> wrote:
    Yes, because it is so peculiar. I wouldn't know how to create such a
    function, but it would have been a better way of presenting a print
    feature, and more conventional.

    The basic idea with overloading a binary operator, rather than using a
    function call syntax, is that the output can be expanded with your own
    custom types (which is not really possible if it used a function call
    syntax).

    In other words, you can achieve this:

    MyClass obj;
    std::cout << "Value = " << obj << "\n";

    fprintf(stdout, "Value = %s\n" obj.to_string());


    I don't know how well C++ can match even a simple scripting language in capabilities. But there, you could do something like this:

    x := (obj1, obj2, obj3) # list of 3 objects

    All objects could be of different types, with their own to-string
    methods. But even if all of the same type, you'd need this:

    print x

    to apply those custom to-string methods to the elements of x without
    being told. Include x itself if that had its own to-string routine.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Mon Sep 20 05:25:55 2021
    Bart <bc@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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Scott Lurndal on Mon Sep 20 05:20:53 2021
    Scott Lurndal <scott@slp53.sl.home> wrote:
    In other words, you can achieve this:

    MyClass obj;
    std::cout << "Value = " << obj << "\n";

    fprintf(stdout, "Value = %s\n" obj.to_string());

    I don't really know how exactly you expect that to be possible in all cases. The returned const char* has to point somewhere. To something that will
    outlive the to_string() function itself, but will, if necessary, be destroyed after use (because in many cases you will need to create a dynamically allocated string in order to contain the textual representation of the value
    of the object you are trying to print).

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bart on Mon Sep 20 08:33:46 2021
    On 20/09/2021 01:31, Bart wrote:
    On 19/09/2021 22:54, Scott Lurndal wrote:
    Juha Nieminen <nospam@thanks.invalid> writes:
    Bart <bc@freeuk.com> wrote:
    Yes, because it is so peculiar. I wouldn't know how to create such a
    function, but it would have been a better way of presenting a print
    feature, and more conventional.

    The basic idea with overloading a binary operator, rather than using a
    function call syntax, is that the output can be expanded with your own
    custom types (which is not really possible if it used a function call
    syntax).

    In other words, you can achieve this:

      MyClass obj;
      std::cout << "Value = " << obj << "\n";

       fprintf(stdout, "Value = %s\n" obj.to_string());


    I don't know how well C++ can match even a simple scripting language in capabilities. But there, you could do something like this:

      x := (obj1, obj2, obj3)       # list of 3 objects

    All objects could be of different types, with their own to-string
    methods. But even if all of the same type, you'd need this:

      print x

    to apply those custom to-string methods to the elements of x without
    being told. Include x itself if that had its own to-string routine.


    There should be no problem making a variadic template function "print"
    that turns "print(a, b, c);" into "cout << a << b << c;", if someone
    really dislikes the << syntax. It could also turn it into "cout << a.to_string() << ' ' << b.to_string() << ' ' << c.to_string();", or
    whatever is the day's preference.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Mon Sep 20 10:37:07 2021
    On 20/09/2021 06:25, Juha Nieminen wrote:
    Bart <bc@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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Mon Sep 20 16:11:18 2021
    On 20/09/2021 07:33, David Brown wrote:
    On 20/09/2021 01:31, Bart wrote:
    On 19/09/2021 22:54, Scott Lurndal wrote:
    Juha Nieminen <nospam@thanks.invalid> writes:
    Bart <bc@freeuk.com> wrote:
    Yes, because it is so peculiar. I wouldn't know how to create such a >>>>> function, but it would have been a better way of presenting a print
    feature, and more conventional.

    The basic idea with overloading a binary operator, rather than using a >>>> function call syntax, is that the output can be expanded with your own >>>> custom types (which is not really possible if it used a function call
    syntax).

    In other words, you can achieve this:

      MyClass obj;
      std::cout << "Value = " << obj << "\n";

       fprintf(stdout, "Value = %s\n" obj.to_string());


    I don't know how well C++ can match even a simple scripting language in
    capabilities. But there, you could do something like this:

      x := (obj1, obj2, obj3)       # list of 3 objects

    All objects could be of different types, with their own to-string
    methods. But even if all of the same type, you'd need this:

      print x

    to apply those custom to-string methods to the elements of x without
    being told. Include x itself if that had its own to-string routine.


    There should be no problem making a variadic template function "print"
    that turns "print(a, b, c);" into "cout << a << b << c;", if someone
    really dislikes the << syntax. It could also turn it into "cout << a.to_string() << ' ' << b.to_string() << ' ' << c.to_string();", or
    whatever is the day's preference.




    My guess is cout and << (don't ask me to explain the difference, except
    one needs to go at the start!) are already implemented on top of a stack
    of language-defining features.

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

    It's not surprising that people complain about C++ being slower to compile!

    My view is that basic Print is a fundamental feature that needs to be
    natively supported by the core language. Then it can be kept streamlined without wasting too much compiler time on it.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bart on Mon Sep 20 18:08:28 2021
    On 20/09/2021 17:11, Bart wrote:
    On 20/09/2021 07:33, David Brown wrote:
    On 20/09/2021 01:31, Bart wrote:
    On 19/09/2021 22:54, Scott Lurndal wrote:
    Juha Nieminen <nospam@thanks.invalid> writes:
    Bart <bc@freeuk.com> wrote:
    Yes, because it is so peculiar. I wouldn't know how to create such a >>>>>> function, but it would have been a better way of presenting a print >>>>>> feature, and more conventional.

    The basic idea with overloading a binary operator, rather than using a >>>>> function call syntax, is that the output can be expanded with your own >>>>> custom types (which is not really possible if it used a function call >>>>> syntax).

    In other words, you can achieve this:

       MyClass obj;
       std::cout << "Value = " << obj << "\n";

        fprintf(stdout, "Value = %s\n" obj.to_string());


    I don't know how well C++ can match even a simple scripting language in
    capabilities. But there, you could do something like this:

       x := (obj1, obj2, obj3)       # list of 3 objects

    All objects could be of different types, with their own to-string
    methods. But even if all of the same type, you'd need this:

       print x

    to apply those custom to-string methods to the elements of x without
    being told. Include x itself if that had its own to-string routine.


    There should be no problem making a variadic template function "print"
    that turns "print(a, b, c);" into "cout << a << b << c;", if someone
    really dislikes the << syntax.  It could also turn it into "cout <<
    a.to_string() << ' ' << b.to_string() << ' ' << c.to_string();", or
    whatever is the day's preference.




    My guess is cout and << (don't ask me to explain the difference, except
    one needs to go at the start!) are already implemented on top of a stack
    of language-defining features.

    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>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Mon Sep 20 18:39:04 2021
    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).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Mon Sep 20 19:04:39 2021
    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.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bart on Mon Sep 20 19:49:45 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bart on Mon Sep 20 21:35:16 2021
    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.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Mon Sep 20 21:38:12 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Tue Sep 21 01:16:04 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Bart on Tue Sep 21 10:28:56 2021
    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,

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Paavo Helde on Tue Sep 21 00:39:06 2021
    On 20/09/2021 23:16, Paavo Helde wrote:
    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.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bo Persson@21:1/5 to Bart on Tue Sep 21 09:08:14 2021
    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".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bart on Tue Sep 21 09:39:55 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Tue Sep 21 11:12:11 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Tue Sep 21 15:45:18 2021
    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?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Tue Sep 21 17:09:04 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Paavo Helde on Tue Sep 21 14:37:44 2021
    On 21/09/2021 13:45, Paavo Helde wrote:
    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.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bart on Tue Sep 21 15:36:15 2021
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like
    memory exhaustion. How do you write a message to STDERR with your
    'println'? It's not obvious at all, unlike for std::cout vs std::cerr.

    I virtually never use STDERR, mainly because I've no idea how to do so >outside of C, or via fprintf from a FFI. Even when writing C, it's just
    not a thing for me. STDOUT is already used for logging, error messages, >everthing.

    Another reason not to use your "language".

    hint: 'fprintf(stderr, ...'

    The utility guidelines require diagnostic messages go to stderr with non-diagnostic output to stdout. This is been the case for a half
    century for extremely good reasons.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Paavo Helde on Tue Sep 21 16:26:05 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Paavo Helde on Tue Sep 21 15:38:03 2021
    Paavo Helde <myfirstname@osa.pri.ee> writes:
    21.09.2021 16:37 Bart kirjutas:

    Until someone wants to encode a nice loop like that:

    stop = false;
    while (!stop) {
    // do something
    }

    Then it becomes clear you have hijacked a perfectly nice 4-letter name
    so it cannot be used any more for other purposes.


    He could resurrect COBOL's "STOP RUN" instead of Fortran's "STOP". :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bart on Tue Sep 21 18:04:42 2021
    On 21/09/2021 17:26, Bart wrote:
    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.


    "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";
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Scott Lurndal on Tue Sep 21 15:49:57 2021
    On Tue, 21 Sep 2021 15:36:15 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like
    memory exhaustion. How do you write a message to STDERR with your
    'println'? It's not obvious at all, unlike for std::cout vs std::cerr.

    I virtually never use STDERR, mainly because I've no idea how to do so >>outside of C, or via fprintf from a FFI. Even when writing C, it's just
    not a thing for me. STDOUT is already used for logging, error messages, >>everthing.

    Another reason not to use your "language".

    hint: 'fprintf(stderr, ...'

    The utility guidelines require diagnostic messages go to stderr with >non-diagnostic output to stdout. This is been the case for a half
    century for extremely good reasons.

    He's probably spent too long in an academic ivory tower and doesn't understand the use case for standard program output to go to one place while the error stream is directed elsewhere.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to HorseyWorsey@the_stables.com on Tue Sep 21 16:21:16 2021
    HorseyWorsey@the_stables.com writes:
    On Tue, 21 Sep 2021 15:36:15 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like
    memory exhaustion. How do you write a message to STDERR with your
    'println'? It's not obvious at all, unlike for std::cout vs std::cerr.

    I virtually never use STDERR, mainly because I've no idea how to do so >>>outside of C, or via fprintf from a FFI. Even when writing C, it's just >>>not a thing for me. STDOUT is already used for logging, error messages, >>>everthing.

    Another reason not to use your "language".

    hint: 'fprintf(stderr, ...'

    The utility guidelines require diagnostic messages go to stderr with >>non-diagnostic output to stdout. This is been the case for a half
    century for extremely good reasons.

    He's probably spent too long in an academic ivory tower and doesn't understand >the use case for standard program output to go to one place while the error >stream is directed elsewhere.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Scott Lurndal on Tue Sep 21 17:45:52 2021
    On 21/09/2021 16:36, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like
    memory exhaustion. How do you write a message to STDERR with your
    'println'? It's not obvious at all, unlike for std::cout vs std::cerr.

    I virtually never use STDERR, mainly because I've no idea how to do so
    outside of C, or via fprintf from a FFI. Even when writing C, it's just
    not a thing for me. STDOUT is already used for logging, error messages,
    everthing.

    Another reason not to use your "language".

    hint: 'fprintf(stderr, ...'

    The utility guidelines require diagnostic messages go to stderr with non-diagnostic output to stdout. This is been the case for a half
    century for extremely good reasons.


    Somebody should tell Microsoft then.

    Their CL compiler shows error messages on stdout no stderr.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bo Persson@21:1/5 to Bart on Tue Sep 21 18:34:05 2021
    On 2021-09-21 at 12:12, Bart wrote:
    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?

    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?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bart on Tue Sep 21 17:02:37 2021
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 16:36, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like
    memory exhaustion. How do you write a message to STDERR with 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);
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Tue Sep 21 20:11:37 2021
    21.09.2021 19:45 Bart kirjutas:
    On 21/09/2021 16:36, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like
    memory exhaustion. How do you write a message to STDERR with 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).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Scott Lurndal on Tue Sep 21 18:16:41 2021
    On 21/09/2021 18:02, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 16:36, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like >>>>> memory exhaustion. How do you write a message to STDERR with 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."

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Paavo Helde on Tue Sep 21 18:33:05 2021
    On 21/09/2021 18:11, Paavo Helde wrote:
    21.09.2021 19:45 Bart kirjutas:
    On 21/09/2021 16:36, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like >>>>> memory exhaustion. How do you write a message to STDERR with 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).

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Tue Sep 21 20:43:57 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Paavo Helde on Tue Sep 21 18:59:06 2021
    On 21/09/2021 18:43, Paavo Helde wrote:
    21.09.2021 20:33 Bart kirjutas:

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

    Hint: if everybody else seems to drive on the wrong side of the highway,
    it might be a time for little self-contemplation.


    So to be clear:

    * Copyright messages from CL belong in STDERR

    * Informative messages from gcc belong in STDERR

    * Program Error messages from CL belong in STDOUT

    * Program Error messages from gcc belong in STDERR

    You are saying this behaviour is correct, not crazy nor conflicting at
    all, and it's time for ME to do self-comtemplation?

    Just checking...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to Bart on Tue Sep 21 11:53:20 2021
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 18:02, Scott Lurndal wrote:
    [...]
    Feel free. stdout and stderr, and the rules for their usage predate
    MSDOS and were in existence long before microsoft produced a C compiler.

    Well I've never heard of any such rules.
    [...]

    So now you've learned something.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bart on Tue Sep 21 18:52:34 2021
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 18:43, Paavo Helde wrote:
    21.09.2021 20:33 Bart kirjutas:

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

    Hint: if everybody else seems to drive on the wrong side of the highway,
    it might be a time for little self-contemplation.


    So to be clear:

    * Copyright messages from CL belong in STDERR

    * Informative messages from gcc belong in STDERR

    * Program Error messages from CL belong in STDOUT

    * Program Error messages from gcc belong in STDERR

    You are saying this behaviour is correct, not crazy nor conflicting at
    all, and it's time for ME to do self-comtemplation?

    The output of GCC is an object file. Any other output is
    diagnostic output and rightly belongs on stderr.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to David Brown on Tue Sep 21 11:51:01 2021
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    "auto fred = std::cout;" will make "fred" a copy of the value of
    "std::cout".

    No it won't. There's no assignment operator for std::basic_ostream.

    What you want is a reference, so that you are referring to
    the real output stream:

    #include <iostream>
    int main() {
    bool cond = false;
    auto& fred = (cond ? std::cout : std::cerr);
    fred << "HELLO\n";
    }

    Right. And if you want to change fred later, you can use a pointer
    (smart or otherwise).

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Tue Sep 21 21:20:48 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Keith Thompson on Tue Sep 21 20:48:48 2021
    On 21/09/2021 19:53, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 18:02, Scott Lurndal wrote:
    [...]
    Feel free. stdout and stderr, and the rules for their usage predate
    MSDOS and were in existence long before microsoft produced a C compiler.

    Well I've never heard of any such rules.
    [...]

    So now you've learned something.



    Not really. The rules apply to what, exactly: a specific OS, ALL OSes, a specific language, ALL languages, some library.....

    I think somebody is making a few assumptions.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Paavo Helde on Tue Sep 21 20:32:48 2021
    On 21/09/2021 19:20, Paavo Helde wrote:
    21.09.2021 20:59 Bart kirjutas:
    On 21/09/2021 18:43, Paavo Helde wrote:
    21.09.2021 20:33 Bart kirjutas:

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

    Hint: if everybody else seems to drive on the wrong side of the
    highway, it might be a time for little self-contemplation.


    So to be clear:

       * Copyright messages from CL belong in STDERR

       * Informative messages from gcc belong in STDERR

       * Program Error messages from CL belong in STDOUT

       * Program Error messages from gcc belong in STDERR

    Error messages from compiler belong to STDERR. Diagnostic messages
    (errors and warnings) about compiled programs can be either way,
    depending on what is considered the main output from the compiler.


    You are saying this behaviour is correct, not crazy nor conflicting at
    all, and it's time for ME to do self-comtemplation?

    Yes. These rules have a simple and sound reason: if the program is
    producing some output which can be potentially post-processed programmatically by another program, then everything not belonging to
    this output must be sent to stderr, to avoid garbling the output.

    Gcc manpage contains examples how to send assembler or other output to stdout, so it makes sense for them to send all diagnostics to stderr to
    avoid garbling.



    I'm still not clear. Is what MS' CL is doing correct or not: sending
    program error messages to STDOUT instead of STDERR as gcc does?

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bart on Tue Sep 21 20:24:40 2021
    Bart <bc@freeuk.com> writes:


    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?

    As with most microsoft software, CL is broken if it behaves as you
    describe.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to Bart on Tue Sep 21 13:47:31 2021
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 19:53, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 18:02, Scott Lurndal wrote:
    [...]
    Feel free. stdout and stderr, and the rules for their usage predate
    MSDOS and were in existence long before microsoft produced a C compiler. >>>
    Well I've never heard of any such rules.
    [...]
    So now you've learned something.

    Not really. The rules apply to what, exactly: a specific OS, ALL OSes,
    a specific language, ALL languages, some library.....

    Right, I shouldn't have assumed that you've learned something.

    I think somebody is making a few assumptions.

    The distinction between standard output and standard error (stdout and
    stderr in C, std::cout and std::cerr in C++) has been well established
    for decades. It's not specific to C++, and therefore not specific to
    this newsgroup. It originated in early UNIX, and possibly from
    Fortran before that, and has been adopted by some other operating
    systems including Windows, though Windows programs often don't make as
    much use of either stdout or stderr as typical Unix/Linux programs do.

    The distinction isn't always 100% clear. I would certainly call
    printing error messages to stdout incorrect behavior. Usage messages
    (the output of `some_command -h` or `some_command --help`, for example)
    are sometimes a corner case, especially if they can be printed either as
    the result of a specific request or because an option name was
    misspelled.

    I suggest you go off and do some research before telling us that we're
    wrong about something we've been using for decades and you've only
    recently learned about. There are even Wikipedia articles.

    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.

    Yes, and if you don't care about following long established conventions,
    you can certainly do that.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bart on Tue Sep 21 20:23:46 2021
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 19:53, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 18:02, Scott Lurndal wrote:
    [...]
    Feel free. stdout and stderr, and the rules for their usage predate
    MSDOS and were in existence long before microsoft produced a C compiler. >>>
    Well I've never heard of any such rules.
    [...]

    So now you've learned something.



    Not really. The rules apply to what, exactly: a specific OS, ALL OSes, a >specific language, ALL languages, some library.....

    I think somebody is making a few assumptions.

    You should stop doing that.


    The fact is, when I write an application then it does what I say. And
    /I/ decide how any error handling is to be performed.

    It has already been pointed out to you the reasoning behind
    the rule. Specifically to support pipelining the output of
    one command into another without interleaving diagnostic
    messages.

    $ cat /path/to/file | egrep -w '^fred|^joe|^sam' > list-of-lines-starting-with-fred-joe-or-sam

    Any diagnostics from cat or grep will go to stderr, not to the pipeline.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Scott Lurndal on Tue Sep 21 23:29:54 2021
    On 21/09/2021 21:23, Scott Lurndal wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 19:53, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 18:02, Scott Lurndal wrote:
    [...]
    Feel free. stdout and stderr, and the rules for their usage predate >>>>> MSDOS and were in existence long before microsoft produced a C compiler. >>>>
    Well I've never heard of any such rules.
    [...]

    So now you've learned something.



    Not really. The rules apply to what, exactly: a specific OS, ALL OSes, a
    specific language, ALL languages, some library.....

    I think somebody is making a few assumptions.

    You should stop doing that.


    The fact is, when I write an application then it does what I say. And
    /I/ decide how any error handling is to be performed.

    It has already been pointed out to you the reasoning behind
    the rule. Specifically to support pipelining the output of
    one command into another without interleaving diagnostic
    messages.

    $ cat /path/to/file | egrep -w '^fred|^joe|^sam' > list-of-lines-starting-with-fred-joe-or-sam

    Any diagnostics from cat or grep will go to stderr, not to the pipeline.


    OK, so primarily to suit Unix utilities.

    That's fine. I don't use Unix. I don't write utilities that take text
    input from pipes and write output to another pipe.

    There's usually more going on and I make my own arrangements for
    generating and displaying any diagnostics.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Wed Sep 22 05:06:36 2021
    Bart <bc@freeuk.com> wrote:
    Now you're saying that we need more templates on top of that to make the syntax palatable.

    It's not surprising that people complain about C++ being slower to compile!

    So you want to trade runtime efficiency for compilation efficiency, essentially?

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

    It seems to me that you come from a world of programming language design
    that pays little to no attention to the efficiency of the resulting
    program. This is very typical of eg. scripting languages and many other
    similar languages (usually interpreted, sometimes compiled). Dynamically allocated strings and objects are liberally created at every turn, things
    are converted into strings and from strings all the time, and so on and
    so forth, with exactly zero regard to how costly that may or may not be.
    A rampant "as long as it works" mentality, with zero regard to efficiency.

    That's not C++ (nor C for that matter). If you don't like the design of
    the language, then don't use it. It's that simple.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Wed Sep 22 04:58:39 2021
    Bart <bc@freeuk.com> wrote:
    What doesn't make sense to you?

    Having to overload "<<", as I assume you meant, as you seemed to imply
    that was better/easier than doing whatever it was to obj to allow its
    use in function syntax.

    So what's the alternative that you suggest?

    So if one of them is, say, a list of a thousand objects, and you want to
    print that list like that, it will dynamically allocate and construct a
    huge string, which gets printed, and then destroyed?

    Instead of, you know, the object just printing every element individually, >> requiring no extra memory and no extra allocations. Something that
    overloading operator<< easily achieves.


    This is a drawback of having a 'tostring' method applied to an entire, complex object.

    However, if the object is that complex, it will already be using
    equivalent amounts of memory anyway.

    The string will be constructed *in addition* to whatever memory the object
    may be taking, and it will be constructed solely for the printing process,
    and then immediately destroyed.

    This even though there's no reason to construct such a string into RAM,
    as each element could just be printed to the output individually by the
    object, without having to construct any strings.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Keith Thompson on Wed Sep 22 11:09:57 2021
    On 21/09/2021 20:51, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    "auto fred = std::cout;" will make "fred" a copy of the value of
    "std::cout".

    No it won't. There's no assignment operator for std::basic_ostream.

    Sorry. I had assumed that Bart had compiled the code he posted. (I
    don't use iostreams in my small-systems embedded code, so I don't know
    all the details of code that I wouldn't write even if I did use them.)


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


    Yes.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Wed Sep 22 10:51:23 2021
    On 22/09/2021 06:06, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    Now you're saying that we need more templates on top of that to make the
    syntax palatable.

    It's not surprising that people complain about C++ being slower to compile!

    So you want to trade runtime efficiency for compilation efficiency, essentially?

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

    It seems to me that you come from a world of programming language design
    that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    But I develop two languages, one for systems programming, one scripting.
    I understand when it is appropriate to use scripting techniques, and
    when it isn't.

    If you need to use sprintf() C, then that's when you might also consider
    using sprint() elsewhere.

    This is very typical of eg. scripting languages and many other
    similar languages (usually interpreted, sometimes compiled). Dynamically allocated strings and objects are liberally created at every turn, things
    are converted into strings and from strings all the time, and so on and
    so forth, with exactly zero regard to how costly that may or may not be.

    No; obviously you don't know how they work. Because they are slower, you
    have even more regard for efficiency, and avoid gratuitous string
    operations.

    A rampant "as long as it works" mentality, with zero regard to efficiency.

    That's not C++ (nor C for that matter). If you don't like the design of
    the language, then don't use it. It's that simple.

    But if you are going to use strings, since sometimes you will need to synthesise text files (eg. textual output of a compiler), have a look at
    this little test in C++ which stringifies the numbers from 1 to 10M into
    one string:

    #include <iostream>

    int main()
    { std::string s="";
    char t[100];

    for (int i=1; i<=10000000; ++i) {
    s += itoa(i,t,10);
    s += ' ';
    }

    std::cout << "S.size = " << s.size() << "\n";
    }

    Compiled as g++ -O2, this runs in 1.3 seconds on my machine. My script
    language might take only twice as long, but is much simpler and quicker
    to write.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Scott Lurndal on Wed Sep 22 09:21:50 2021
    On Tue, 21 Sep 2021 16:21:16 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:
    HorseyWorsey@the_stables.com writes:
    On Tue, 21 Sep 2021 15:36:15 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:
    Bart <bc@freeuk.com> writes:
    On 21/09/2021 13:45, Paavo Helde wrote:

    There are some messages to STDERR though, in critical conditions like >>>>> memory exhaustion. How do you write a message to STDERR with your
    'println'? It's not obvious at all, unlike for std::cout vs std::cerr. >>>>
    I virtually never use STDERR, mainly because I've no idea how to do so >>>>outside of C, or via fprintf from a FFI. Even when writing C, it's just >>>>not a thing for me. STDOUT is already used for logging, error messages, >>>>everthing.

    Another reason not to use your "language".

    hint: 'fprintf(stderr, ...'

    The utility guidelines require diagnostic messages go to stderr with >>>non-diagnostic output to stdout. This is been the case for a half >>>century for extremely good reasons.

    He's probably spent too long in an academic ivory tower and doesn't understand

    the use case for standard program output to go to one place while the error >>stream is directed elsewhere.

    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.

    And many who weren't. Dennis Richie and Stroustrup both worked at Bell labs, Unix was created by AT&T, SQL by IBM, Java by Sun, Bill Gates was a Harvard dropout etc.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to HorseyWorsey@the_stables.com on Wed Sep 22 11:59:46 2021
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    On Wed, 22 Sep 2021 10:51:23 +0100
    Bart <bc@freeuk.com> wrote:
    #include <iostream>

    int main()
    { std::string s="";
    char t[100];

    for (int i=1; i<=10000000; ++i) {
    s += itoa(i,t,10);
    s += ' ';
    }

    std::cout << "S.size = " << s.size() << "\n";
    }


    You learn something new every day. I'd never heard of itoa(). Apparently its an ancient K&R function which didn't get included into the ANSI C standard.


    So what would be the shiny new alternative in C++?

    I wanted to avoid sprintf which has extra overheads that would likely
    dominate the timing.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Wed Sep 22 10:54:32 2021
    On Wed, 22 Sep 2021 10:51:23 +0100
    Bart <bc@freeuk.com> wrote:
    #include <iostream>

    int main()
    { std::string s="";
    char t[100];

    for (int i=1; i<=10000000; ++i) {
    s += itoa(i,t,10);
    s += ' ';
    }

    std::cout << "S.size = " << s.size() << "\n";
    }


    You learn something new every day. I'd never heard of itoa(). Apparently its
    an ancient K&R function which didn't get included into the ANSI C standard.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Wed Sep 22 11:04:13 2021
    On Wed, 22 Sep 2021 11:59:46 +0100
    Bart <bc@freeuk.com> wrote:
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    On Wed, 22 Sep 2021 10:51:23 +0100
    Bart <bc@freeuk.com> wrote:
    #include <iostream>

    int main()
    { std::string s="";
    char t[100];

    for (int i=1; i<=10000000; ++i) {
    s += itoa(i,t,10);
    s += ' ';
    }

    std::cout << "S.size = " << s.size() << "\n";
    }


    You learn something new every day. I'd never heard of itoa(). Apparently its >> an ancient K&R function which didn't get included into the ANSI C standard. >>

    So what would be the shiny new alternative in C++?

    stringstream which has always struck me as horrible inefficient and I've never understood why std::string didn't have a built in number to string conversion.

    I wanted to avoid sprintf which has extra overheads that would likely >dominate the timing.

    Probably fewer overheads than stringstream. However there's always strtol().

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Wed Sep 22 11:26:58 2021
    On 22/09/2021 05:58, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    What doesn't make sense to you?

    Having to overload "<<", as I assume you meant, as you seemed to imply
    that was better/easier than doing whatever it was to obj to allow its
    use in function syntax.

    So what's the alternative that you suggest?

    Overloading whatever 'tostring' operations that are implicitly used when printing.


    So if one of them is, say, a list of a thousand objects, and you want to >>> print that list like that, it will dynamically allocate and construct a
    huge string, which gets printed, and then destroyed?

    Instead of, you know, the object just printing every element individually, >>> requiring no extra memory and no extra allocations. Something that
    overloading operator<< easily achieves.


    This is a drawback of having a 'tostring' method applied to an entire,
    complex object.

    However, if the object is that complex, it will already be using
    equivalent amounts of memory anyway.

    The string will be constructed *in addition* to whatever memory the object may be taking, and it will be constructed solely for the printing process, and then immediately destroyed.

    This even though there's no reason to construct such a string into RAM,
    as each element could just be printed to the output individually by the object, without having to construct any strings.

    OK, let's try it. Here's a program that writes 1 million lines of the
    same 3 variables:

    #include <iostream>
    #include <fstream>
    using namespace std;

    int main () {
    ofstream myfile;
    long long int a = 0x7FFFFFFFFFFFFFFF;
    double b = 3.14159265359;
    const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    myfile.open ("output");
    for (int i=0; i<1000000; ++i) {
    myfile << a << " " << b << " " << c << "\n";
    }
    myfile.close();
    return 0;
    }

    On my machine, that took 4 seconds. But when I tried my script language,
    where each element has to be converted to a string object before being
    printed, it took only 3 seconds:

    a := int64.max
    b := pi
    c := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    f:=createfile("output")

    to 1 million do
    println @f, a,b,c
    od

    closefile(f)

    But now look at this version, which makes use of that sprint() routine
    that you derided in another post; this one takes only 2.1 seconds:

    a := int64.max
    b := pi
    c := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    s ::= ""

    to 1 million do
    s +:= sprint(a,b,c,"\n")
    od

    writestrfile("output",s)

    (It seems that a sprintln() version would be useful to avoid that
    explicit "\n" argument, and make it even faster.)

    Perhaps you shouldn't write off these pesky scripting languages so
    quickly...


    [Timings shown for my language is for when the interpreter is transpiled
    to C and compiled with gcc-O3. That's only available with an older
    version. The new version doesn't have a C option and will be 30% slower
    until a C target is reinstated. C++ timings use g++-O2]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Bart on Wed Sep 22 23:13:55 2021
    On 22/09/2021 22:26, Bart wrote:

    OK, let's try it. Here's a program that writes 1 million lines of the
    same 3 variables:

    #include <iostream>
    #include <fstream>
    using namespace std;

    int main () {
    ofstream myfile;
    long long int a = 0x7FFFFFFFFFFFFFFF;
    double b = 3.14159265359;
    const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    myfile.open ("output");
    for (int i=0; i<1000000; ++i) {
    myfile << a << " " << b << " " << c << "\n";
    }
    myfile.close();
    return 0;
    }

    On my machine, that took 4 seconds.

    This will take roughly the time it takes to perform the file writing
    (0.4S on my machine). The time spend formatting the output is
    inconsequential in comparison.

    --
    Ian.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Wed Sep 22 15:18:16 2021
    22.09.2021 13:59 Bart kirjutas:
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    You learn something new every day. I'd never heard of itoa().
    Apparently its
    an ancient K&R function which didn't get included into the ANSI C
    standard.


    So what would be the shiny new alternative in C++?

    std::to_string()

    https://en.cppreference.com/w/cpp/string/basic_string/to_string

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to Bart on Wed Sep 22 14:17:54 2021
    On 22 Sep 2021 12:59, Bart wrote:
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    On Wed, 22 Sep 2021 10:51:23 +0100
    Bart <bc@freeuk.com> wrote:
       #include <iostream>

       int main()
       {   std::string s="";
           char t[100];

           for (int i=1; i<=10000000; ++i) {
               s += itoa(i,t,10);
               s += ' ';
           }

           std::cout << "S.size = " << s.size() << "\n";
       }


    You learn something new every day. I'd never heard of itoa().
    Apparently its
    an ancient K&R function which didn't get included into the ANSI C
    standard.


    So what would be the shiny new alternative in C++?

    I wanted to avoid sprintf which has extra overheads that would likely dominate the timing.

    #include <stddef.h> // ptrdiff_t
    #include <stdio.h> // printf, for the final output
    using Size = ptrdiff_t;

    #include <charconv> // std::to_chars
    #include <limits> // std::numeric_limits
    #include <string> // std::string
    #include <stdexcept> // std::runtime_error
    using namespace std::string_literals;

    void append_to( std::string& s, const int v )
    {
    static const int radix = 10;
    static const int max_int_digits =
    std::numeric_limits<int>::digits10 + 1;

    const Size original_size = s.size();
    s.resize( original_size + max_int_digits + 1 ); // 1 for
    possible sign.

    using P_char = char*;
    const P_char buffer_start = s.data() + original_size;
    const P_char buffer_end = s.data() + s.size();
    const std::to_chars_result tcr = std::to_chars( buffer_start,
    buffer_end, v, radix );
    if( tcr.ec == std::errc() ) {
    s.resize( tcr.ptr - s.data() );
    } else {
    throw std::runtime_error( ""s + __func__ + " - std::to_chars
    failed." );
    }
    }

    auto main() -> int
    {
    const int n = 10'000'000;
    std::string text;
    text.reserve( 10*n ); // Avoid (most of the) repeated dynamic allocations.
    for( int i = 1; i <= n; ++i ) {
    append_to( text, i );
    text += ' ';
    }
    printf( "text.size = %d\n", int( text.size() ) );
    }


    Building and running it in Powershell (using that abomination b/c it's
    got timing commands, and too lazy to enable dev mode in this Windows):

    PS D:\temp> g++ -std=c++17 -O2 .\x.cpp
    PS D:\temp> (measure-command { .\a.exe | out-default }).TotalMilliseconds text.size = 78888897
    264.2677
    PS D:\temp> (measure-command { .\a.exe | out-default }).TotalMilliseconds text.size = 78888897
    219.7058
    PS D:\temp> (measure-command { .\a.exe | out-default }).TotalMilliseconds text.size = 78888897
    204.7605

    Apparently it runs faster each time. However, if anyone's particularly interested in that, or how to report processor time instead of wall
    clock time in Windows, then hey, you got a nice project to engage in.

    - Alf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Wed Sep 22 15:29:01 2021
    22.09.2021 13:26 Bart kirjutas:
    On 22/09/2021 05:58, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    What doesn't make sense to you?

    Having to overload "<<", as I assume you meant, as you seemed to imply
    that was better/easier than doing whatever it was to obj to allow its
    use in function syntax.

    So what's the alternative that you suggest?

    Overloading whatever 'tostring' operations that are implicitly used when printing.


    So if one of them is, say, a list of a thousand objects, and you
    want to
    print that list like that, it will dynamically allocate and construct a >>>> huge string, which gets printed, and then destroyed?

    Instead of, you know, the object just printing every element
    individually,
    requiring no extra memory and no extra allocations. Something that
    overloading operator<< easily achieves.


    This is a drawback of having a 'tostring' method applied to an entire,
    complex object.

    However, if the object is that complex, it will already be using
    equivalent amounts of memory anyway.

    The string will be constructed *in addition* to whatever memory the
    object
    may be taking, and it will be constructed solely for the printing
    process,
    and then immediately destroyed.

    This even though there's no reason to construct such a string into RAM,
    as each element could just be printed to the output individually by the
    object, without having to construct any strings.

    OK, let's try it. Here's a program that writes 1 million lines of the
    same 3 variables:

      #include <iostream>
      #include <fstream>
      using namespace std;

      int main () {
          ofstream myfile;
          long long int a = 0x7FFFFFFFFFFFFFFF;
          double b = 3.14159265359;
          const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

          myfile.open ("output");
          for (int i=0; i<1000000; ++i) {
              myfile << a << " " << b << " " << c << "\n";
          }
          myfile.close();
          return 0;
      }

    On my machine, that took 4 seconds. But when I tried my script language, where each element has to be converted to a string object before being printed, it took only 3 seconds:

    A better comparison would be to measure the time of converting and
    appending a million numbers to a std::string, then outputting the huge
    string in one go.

    The C++ iostreams can be very slow and the timings depend on the implementation. In my experiments I saw that ostream << can be either
    10x slower than huge string building (MSVC++ 2019), or then 2x faster
    (g++ 8.3). I streamed to an in-memory ostringstream, so there was no
    disk slowdown involved.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Ian Collins on Wed Sep 22 13:45:01 2021
    On 22/09/2021 12:13, Ian Collins wrote:
    On 22/09/2021 22:26, Bart wrote:

    OK, let's try it. Here's a program that writes 1 million lines of the
    same 3 variables:

        #include <iostream>
        #include <fstream>
        using namespace std;

        int main () {
            ofstream myfile;
            long long int a = 0x7FFFFFFFFFFFFFFF;
            double b = 3.14159265359;
            const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

            myfile.open ("output");
            for (int i=0; i<1000000; ++i) {
                myfile << a << " " << b << " " << c << "\n";
            }
            myfile.close();
            return 0;
        }

    On my machine, that took 4 seconds.

    This will take roughly the time it takes to perform the file writing
    (0.4S on my machine).  The time spend formatting the output is inconsequential in comparison.


    But you don't know that? On my machine, timing went from 4.3 seconds to
    5.3 seconds if I changed the output file from "output" to "nul"
    (Windows' version of a null device, not a very effective one!).

    I don't know how to isolate the file i/o from the conversion in C++. If
    I switch to C *printf functions, then going from fprintf to sprintf,
    changes the timing from 4.3 seconds to 0.8 seconds; so more than 80% is
    writing via the file system.

    I wanted to determine the overheads of using "<<" on each print item, especially as there are 3 extra arguments of " ", " " and "\n".

    These latter overheads are irrelevant when using the format string of
    sprintf.

    The question posed was whether turning into individual print items into
    a string object, before sending that string to the output, was a
    significant overhead.

    I showed my /dynamic/ code wasn't significantly slower than C++
    (actually it was faster) despite doing those conversions, plus a whole
    bunch of other overheads that C++ will not have.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to HorseyWorsey@the_stables.com on Wed Sep 22 14:04:44 2021
    HorseyWorsey@the_stables.com writes:
    On Wed, 22 Sep 2021 10:51:23 +0100
    Bart <bc@freeuk.com> wrote:
    #include <iostream>

    int main()
    { std::string s="";
    char t[100];

    for (int i=1; i<=10000000; ++i) {
    s += itoa(i,t,10);
    s += ' ';
    }

    std::cout << "S.size = " << s.size() << "\n";
    }


    You learn something new every day. I'd never heard of itoa(). Apparently its >an ancient K&R function which didn't get included into the ANSI C standard.


    Because strtoul et al are far more useful than itoa/atoi for
    error checking.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Alf P. Steinbach on Wed Sep 22 14:32:22 2021
    On 22/09/2021 13:17, Alf P. Steinbach wrote:
    #include <stddef.h>     // ptrdiff_t
    #include <stdio.h>      // printf, for the final output
    using Size = ptrdiff_t;

    #include <charconv>         // std::to_chars
    #include <limits>           // std::numeric_limits
    #include <string>           // std::string
    #include <stdexcept>        // std::runtime_error
    using namespace std::string_literals;

    void append_to( std::string& s, const int v )
    {
        static const int radix          = 10;
        static const int max_int_digits =
    std::numeric_limits<int>::digits10 + 1;

        const Size original_size = s.size();
        s.resize( original_size + max_int_digits + 1 );     // 1 for possible sign.

        using P_char = char*;
        const P_char    buffer_start    = s.data() + original_size;
        const P_char    buffer_end      = s.data() + s.size();
        const std::to_chars_result tcr = std::to_chars( buffer_start, buffer_end, v, radix );
        if( tcr.ec == std::errc() ) {
            s.resize( tcr.ptr - s.data() );
        } else {
            throw std::runtime_error( ""s + __func__ + " - std::to_chars failed." );
        }
    }

    auto main() -> int
    {
        const int n = 10'000'000;
        std::string text;
        text.reserve( 10*n );      // Avoid (most of the) repeated dynamic
    allocations.
        for( int i = 1; i <= n; ++i ) {
            append_to( text, i );
            text += ' ';
        }
        printf( "text.size = %d\n", int( text.size() ) );
    }


    This fails rextester.com (doesn't know charconv); and my
    g++/mingw/10.3.0, doesn't like converting const char to P_char.

    If I use '-fpermissive' to get around that, then I get a timing of 0.56;
    more than twice as fast was my earlier time. I think about 5 times as
    fast as my dynamic code.

    However, if you are going to write custom code, then I can do the same...

    This is my script:

    s ::= "" # ::= makes a mutable copy

    for i to 10 million do
    s +:= tostr(i)
    s +:= ' '
    od

    println s.len

    (It uses 64-bit ints which impact the int-to-text conversion, which is
    not optimised for base-10.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to Bart on Wed Sep 22 16:23:16 2021
    On 22 Sep 2021 15:32, Bart wrote:
    On 22/09/2021 13:17, Alf P. Steinbach wrote:
    #include <stddef.h>     // ptrdiff_t
    #include <stdio.h>      // printf, for the final output
    using Size = ptrdiff_t;

    #include <charconv>         // std::to_chars
    #include <limits>           // std::numeric_limits
    #include <string>           // std::string
    #include <stdexcept>        // std::runtime_error
    using namespace std::string_literals;

    void append_to( std::string& s, const int v )
    {
         static const int radix          = 10;
         static const int max_int_digits =
    std::numeric_limits<int>::digits10 + 1;

         const Size original_size = s.size();
         s.resize( original_size + max_int_digits + 1 );     // 1 for
    possible sign.

         using P_char = char*;
         const P_char    buffer_start    = s.data() + original_size; >>      const P_char    buffer_end      = s.data() + s.size();
         const std::to_chars_result tcr = std::to_chars( buffer_start,
    buffer_end, v, radix );
         if( tcr.ec == std::errc() ) {
             s.resize( tcr.ptr - s.data() );
         } else {
             throw std::runtime_error( ""s + __func__ + " - std::to_chars
    failed." );
         }
    }

    auto main() -> int
    {
         const int n = 10'000'000;
         std::string text;
         text.reserve( 10*n );      // Avoid (most of the) repeated
    dynamic allocations.
         for( int i = 1; i <= n; ++i ) {
             append_to( text, i );
             text += ' ';
         }
         printf( "text.size = %d\n", int( text.size() ) );
    }


    This fails rextester.com (doesn't know charconv); and my
    g++/mingw/10.3.0, doesn't like converting const char to P_char.

    There's a good chance both problems are due to compiling for a too old
    C++ standard.

    Namely, `to_chars` was introduced in C++17, and the non-`const` `basic_string::data()`, producing a `char*`, was introduced in C++17;
    see <url: https://en.cppreference.com/w/cpp/string/basic_string/data>.

    So, specify `-std=c++17` or later.



    If I use '-fpermissive' to get around that, then I get a timing of 0.56;
    more than twice as fast was my earlier time. I think about 5 times as
    fast as my dynamic code.

    Not sure how you manage to compile this without `-std=c++17` though.

    Now that begins to look like a mystery! :-o


    However, if you are going to write custom code, then I can do the same...

    This is my script:

        s ::= ""          # ::= makes a mutable copy

        for i to 10 million do
            s +:= tostr(i)
            s +:= ' '
        od

        println s.len

    (It uses 64-bit ints which impact the int-to-text conversion, which is
    not optimised for base-10.)

    I didn't present custom code for the conversion.

    The added code was for a reasonable wrapping of the `std::to_chars` call.


    - Alf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to Paavo Helde on Wed Sep 22 16:16:57 2021
    On 22 Sep 2021 14:18, Paavo Helde wrote:
    22.09.2021 13:59 Bart kirjutas:
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    You learn something new every day. I'd never heard of itoa().
    Apparently its
    an ancient K&R function which didn't get included into the ANSI C
    standard.


    So what would be the shiny new alternative in C++?

    std::to_string()

    https://en.cppreference.com/w/cpp/string/basic_string/to_string

    Not fast and not locale-independent (it uses the C library's locale).

    Better use C++17 `to_chars`, <url: https://en.cppreference.com/w/cpp/utility/to_chars>.

    I gave a more or less full example in reply to the same posting you
    replied to.

    - Alf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to Bart on Wed Sep 22 07:18:18 2021
    Bart <bc@freeuk.com> writes:
    [...]
    #include <iostream>

    int main()
    { std::string s="";
    char t[100];

    for (int i=1; i<=10000000; ++i) {
    s += itoa(i,t,10);
    s += ' ';
    }

    std::cout << "S.size = " << s.size() << "\n";
    }

    Compiled as g++ -O2, this runs in 1.3 seconds on my machine. My script language might take only twice as long, but is much simpler and
    quicker to write.

    I'm a little surprised that compiles. It doesn't on my Linux system,
    but it does under Cygwin (but fails with "g++ -std=c++11 -pedantic").

    itoa() is non-standard, and apparently it's provided by newlib (Cygwin)
    but not by GNU libc (most Linux systems).

    std::to_string() (introduced in C++11) is the C++ equivalent.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Alf P. Steinbach on Wed Sep 22 15:15:08 2021
    On Wed, 22 Sep 2021 16:16:57 +0200
    "Alf P. Steinbach" <alf.p.steinbach@gmail.com> wrote:
    On 22 Sep 2021 14:18, Paavo Helde wrote:
    22.09.2021 13:59 Bart kirjutas:
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    You learn something new every day. I'd never heard of itoa().
    Apparently its
    an ancient K&R function which didn't get included into the ANSI C
    standard.


    So what would be the shiny new alternative in C++?

    std::to_string()

    https://en.cppreference.com/w/cpp/string/basic_string/to_string

    Not fast and not locale-independent (it uses the C library's locale).

    Better use C++17 `to_chars`, <url: >https://en.cppreference.com/w/cpp/utility/to_chars>.

    I gave a more or less full example in reply to the same posting you
    replied to.

    Because a 20 line user function just to convert a number into a string is
    soooo efficient.

    But then someone who writes "auto main() -> int" instead of "int main()"
    and then forgets the return value at the end anyway is probably not someone
    who writes sensible code.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Alf P. Steinbach on Wed Sep 22 16:05:16 2021
    On Wed, 22 Sep 2021 17:57:46 +0200
    "Alf P. Steinbach" <alf.p.steinbach@gmail.com> wrote:
    On 22 Sep 2021 17:15, HorseyWorsey@the_stables.com wrote:
    On Wed, 22 Sep 2021 16:16:57 +0200
    "Alf P. Steinbach" <alf.p.steinbach@gmail.com> wrote:
    On 22 Sep 2021 14:18, Paavo Helde wrote:
    22.09.2021 13:59 Bart kirjutas:
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    You learn something new every day. I'd never heard of itoa().
    Apparently its
    an ancient K&R function which didn't get included into the ANSI C
    standard.


    So what would be the shiny new alternative in C++?

    std::to_string()

    https://en.cppreference.com/w/cpp/string/basic_string/to_string

    Not fast and not locale-independent (it uses the C library's locale).

    Better use C++17 `to_chars`, <url:
    https://en.cppreference.com/w/cpp/utility/to_chars>.

    I gave a more or less full example in reply to the same posting you
    replied to.

    Because a 20 line user function just to convert a number into a string is
    soooo efficient.

    But then someone who writes "auto main() -> int" instead of "int main()"
    and then forgets the return value at the end anyway is probably not someone >> who writes sensible code.

    Attempt to troll someone else, please.

    Your example was a joke. Thats not trolling, thats a fact.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to HorseyWorsey@the_stables.com on Wed Sep 22 17:57:46 2021
    On 22 Sep 2021 17:15, HorseyWorsey@the_stables.com wrote:
    On Wed, 22 Sep 2021 16:16:57 +0200
    "Alf P. Steinbach" <alf.p.steinbach@gmail.com> wrote:
    On 22 Sep 2021 14:18, Paavo Helde wrote:
    22.09.2021 13:59 Bart kirjutas:
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    You learn something new every day. I'd never heard of itoa().
    Apparently its
    an ancient K&R function which didn't get included into the ANSI C
    standard.


    So what would be the shiny new alternative in C++?

    std::to_string()

    https://en.cppreference.com/w/cpp/string/basic_string/to_string

    Not fast and not locale-independent (it uses the C library's locale).

    Better use C++17 `to_chars`, <url:
    https://en.cppreference.com/w/cpp/utility/to_chars>.

    I gave a more or less full example in reply to the same posting you
    replied to.

    Because a 20 line user function just to convert a number into a string is soooo efficient.

    But then someone who writes "auto main() -> int" instead of "int main()"
    and then forgets the return value at the end anyway is probably not someone who writes sensible code.

    Attempt to troll someone else, please.

    - Alf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Wed Sep 22 20:46:02 2021
    22.09.2021 17:16 Alf P. Steinbach kirjutas:
    On 22 Sep 2021 14:18, Paavo Helde wrote:
    22.09.2021 13:59 Bart kirjutas:
    On 22/09/2021 11:54, HorseyWorsey@the_stables.com wrote:
    You learn something new every day. I'd never heard of itoa().
    Apparently its
    an ancient K&R function which didn't get included into the ANSI C
    standard.


    So what would be the shiny new alternative in C++?

    std::to_string()

    https://en.cppreference.com/w/cpp/string/basic_string/to_string

    Not fast and not locale-independent (it uses the C library's locale).

    Better use C++17 `to_chars`, <url: https://en.cppreference.com/w/cpp/utility/to_chars>.

    I gave a more or less full example in reply to the same posting you
    replied to.

    Yes, I saw your post later. You are right to_chars() ought to be faster
    indeed. Unfortunately I have not had a chance yet to try it out.

    Locale and speed issues are most severe for floating-point. At the
    moment we are using Google's double-conversion library for
    double->string conversion, this seems to be pretty fast as well.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to HorseyWorsey@the_stables.com on Wed Sep 22 14:13:39 2021
    HorseyWorsey@the_stables.com writes:
    [...]
    But then someone who writes "auto main() -> int" instead of "int main()"
    and then forgets the return value at the end anyway is probably not someone who writes sensible code.

    Were you not aware that reaching the closing "}" of main() does an
    implicit "return 0;"?

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Manfred on Wed Sep 22 23:51:06 2021
    On 22/09/2021 23:45, Manfred wrote:
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be
    natively supported by the core language. Then it can be kept streamlined >>> without wasting too much compiler time on it.

    That's your view.  It is not unique to you, but it is not the view of
    many other people.


    Actually this view was (and still is) shared by the creators of C and of
    C++.

    It is not part of the core language. It is part of the standard
    library. That's a very different thing. In particular, the great
    majority of printf implementations are written in C, the great majority
    of iostream implementations are written in C++.
    (Implementation-specific behaviour might be needed.) Printing is not a
    special statement in either language - it is handled by library
    functions that are optional (small embedded systems often don't use
    them, for example), and can be replaced by alternatives.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to David Brown on Wed Sep 22 23:45:01 2021
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be
    natively supported by the core language. Then it can be kept streamlined
    without wasting too much compiler time on it.

    That's your view. It is not unique to you, but it is not the view of
    many other people.


    Actually this view was (and still is) shared by the creators of C and of
    C++.
    In fact, that is the only reason (every language should have it as an unavoidable axiom) that I can see for C to have a function like printf:
    as a systems language, you don't need formatting support, you just need
    the ability to send chars to some device.
    But, since it is such a widely spread convenience, they decided to put something in the standard library.
    C++ tried to improve with iostreams, it was a genuine attempt, but the
    result proved unpleasant.

    (In other words, string formatting is properly a UI feature, so if you seriously need it, get some serious UI library, which has intentionally
    been left out of C and C++; or, if you have specific and limited needs,
    write it yourself)

    The key point is the word "basic" in Bart's sentence - it is the same as
    "easy to use", what does it mean?
    Definitions like this are obviously subjective, and they're a sure path
    to disagreement.

    I remember once some team was working on building support for some type
    of device into some system - integration would consist of controlling
    the device from C code, the system's language.
    The team was asked by management about the requirements for the device;
    the requirements came out along the lines of "it should be easy to use".
    The result was that management bought a device that could be driven by
    Excel.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From danielaparker@gmail.com@21:1/5 to Paavo Helde on Wed Sep 22 14:42:01 2021
    On Wednesday, September 22, 2021 at 8:18:27 AM UTC-4, Paavo Helde wrote:
    22.09.2021 13:59 Bart kirjutas:

    So what would be the shiny new alternative in C++?
    std::to_string()

    https://en.cppreference.com/w/cpp/string/basic_string/to_string

    Strange that in a language that's supposed to support genericity and
    user provided allocators, we have these things that support neither
    genericity or user provided allocators.

    Daniel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Manfred on Thu Sep 23 00:17:06 2021
    On 22/09/2021 22:45, Manfred wrote:
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be
    natively supported by the core language. Then it can be kept streamlined >>> without wasting too much compiler time on it.

    That's your view.  It is not unique to you, but it is not the view of
    many other people.


    Actually this view was (and still is) shared by the creators of C and of
    C++.
    In fact, that is the only reason (every language should have it as an unavoidable axiom) that I can see for C to have a function like printf:
    as a systems language, you don't need formatting support, you just need
    the ability to send chars to some device.
    But, since it is such a widely spread convenience, they decided to put something in the standard library.
    C++ tried to improve with iostreams, it was a genuine attempt, but the
    result proved unpleasant.

    (In other words, string formatting is properly a UI feature, so if you seriously need it, get some serious UI library, which has intentionally
    been left out of C and C++; or, if you have specific and limited needs,
    write it yourself)

    The key point is the word "basic" in Bart's sentence - it is the same as "easy to use", what does it mean?
    Definitions like this are obviously subjective, and they're a sure path
    to disagreement.

    The first languages I used all had a version of PRINT, needed as the
    primary display device was a teletype or VDU, but you also needed to
    write to text files (Algol, Fortran, Pascal; even assembly could do it!)

    So I find it difficult to get away from the idea that PRINT is anything
    but a fundamental feature of a language. Even though applications may
    work primarily with a GUI, or without a UI at all. Such an app may still
    need to write out a config file ...

    ... or read one in. Which brings me to something that hasn't been
    discussed: basic READ.

    This was something that was so easy in the 1970s, and now so hard;
    except in my own languages where I keep it simple:

    int a, b, c
    print "Prompt> "
    readln a, b, c
    println a, b, c

    I tried it in C++ to see how well it coped:

    #include <iostream>

    int main()
    { int a,b,c;
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    }

    (Just look at that last line; 15 tokens and 35 sig. characters; compare
    my 6 tokens and 12 characters...)

    Anyway, this was quite poor:

    * It doesn't like commas as separators as well as spaces

    * If less than 3 numbers are present, it keeps waiting for me to enter
    them on a subsequent line; very unfriendly

    * If more than 3 are entered, those extra ones are not ignored; on the
    next Prompt, those ones form the first part of the input of the new
    line, very confusing. This input is supposed to be LINE ORIENTED.

    * If I enter 12.34 56 78, it reads 12 for the first number, and zeros
    for the next two, and apparently zeros also for all subsequent lines


    None of those problems appear in mine:

    * It reads at most 3 numbers from the line

    * If fewer are present, it'll read them as zeros

    * If more, they are ignored. Whatever is entered on one line NEVER
    impinges on the next

    * Numbers can be separated with commas or spaces

    * Entering 12.34 56 78 is well behaved; it reads 12 56 78

    There are some weaknesses in my static language version, but most are
    fixed in my dynamic version (same code, but no 'int a,b,c'):

    * A print item is read as int, float, string or bignum according to what
    is entered

    * Missing items are read as ""

    * A type can be forced if needed

    READ is intended as a casual feature to quickly and informally read such
    input from a console or file. But it's amazing how accomplished it is
    compared with major languages.

    I'm sure C++ is also capable of the same things, but how much effort is
    it? Do you have to do everything yourself? Maybe there's a Boost library
    to do what used to be one line of code with Algol60.

    My first programs were student exercises. Then, getting the 3 numbers
    the task demanded was the easy bit!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bart on Thu Sep 23 02:03:33 2021
    On 2021-09-22, Bart <bc@freeuk.com> wrote:
    On 22/09/2021 22:45, Manfred wrote:
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be
    natively supported by the core language. Then it can be kept streamlined >>>> without wasting too much compiler time on it.

    That's your view.  It is not unique to you, but it is not the view of
    many other people.


    Actually this view was (and still is) shared by the creators of C and of
    C++.
    In fact, that is the only reason (every language should have it as an
    unavoidable axiom) that I can see for C to have a function like printf:
    as a systems language, you don't need formatting support, you just need
    the ability to send chars to some device.
    But, since it is such a widely spread convenience, they decided to put
    something in the standard library.
    C++ tried to improve with iostreams, it was a genuine attempt, but the
    result proved unpleasant.

    (In other words, string formatting is properly a UI feature, so if you
    seriously need it, get some serious UI library, which has intentionally
    been left out of C and C++; or, if you have specific and limited needs,
    write it yourself)

    The key point is the word "basic" in Bart's sentence - it is the same as
    "easy to use", what does it mean?
    Definitions like this are obviously subjective, and they're a sure path
    to disagreement.

    The first languages I used all had a version of PRINT, needed as the
    primary display device was a teletype or VDU, but you also needed to
    write to text files (Algol, Fortran, Pascal; even assembly could do it!)

    So I find it difficult to get away from the idea that PRINT is anything
    but a fundamental feature of a language. Even though applications may
    work primarily with a GUI, or without a UI at all. Such an app may still
    need to write out a config file ...

    ... or read one in. Which brings me to something that hasn't been
    discussed: basic READ.

    This was something that was so easy in the 1970s, and now so hard;
    except in my own languages where I keep it simple:

    int a, b, c
    print "Prompt> "
    readln a, b, c
    println a, b, c

    I tried it in C++ to see how well it coped:

    #include <iostream>

    int main()
    { int a,b,c;
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    }

    Same thing.
    But there is bug if user enters more or less then three. How you handle
    that case?
    In Swift:
    let values = readLine()?.components(separatedBy: CharacterSet.whitespacesAndNewlines) ?? []

    let valueOne = values.count > 0 ? Int(values[0]) : nil
    let valueTwo = values.count > 1 ? Int(values[1]) : nil

    so this handles correct.

    (Just look at that last line; 15 tokens and 35 sig. characters; compare
    my 6 tokens and 12 characters...)

    Anyway, this was quite poor:

    * It doesn't like commas as separators as well as spaces

    * If less than 3 numbers are present, it keeps waiting for me to enter
    them on a subsequent line; very unfriendly

    * If more than 3 are entered, those extra ones are not ignored; on the
    next Prompt, those ones form the first part of the input of the new
    line, very confusing. This input is supposed to be LINE ORIENTED.

    * If I enter 12.34 56 78, it reads 12 for the first number, and zeros
    for the next two, and apparently zeros also for all subsequent lines


    None of those problems appear in mine:

    * It reads at most 3 numbers from the line

    * If fewer are present, it'll read them as zeros

    nowhere is clear from code.
    read as you write, write as you speak, that's the rule...


    * If more, they are ignored. Whatever is entered on one line NEVER
    /what if that is not desired behavior? it is not clear from code.
    Don't do things behind peoples backs.

    --
    7-77-777
    \|/
    ---
    /|\

    impinges on the next

    * Numbers can be separated with commas or spaces

    * Entering 12.34 56 78 is well behaved; it reads 12 56 78

    There are some weaknesses in my static language version, but most are
    fixed in my dynamic version (same code, but no 'int a,b,c'):

    * A print item is read as int, float, string or bignum according to what
    is entered

    * Missing items are read as ""

    * A type can be forced if needed

    READ is intended as a casual feature to quickly and informally read such input from a console or file. But it's amazing how accomplished it is compared with major languages.

    I'm sure C++ is also capable of the same things, but how much effort is
    it? Do you have to do everything yourself? Maybe there's a Boost library
    to do what used to be one line of code with Algol60.

    My first programs were student exercises. Then, getting the 3 numbers
    the task demanded was the easy bit!



    --
    /Volumes/air AFP Music Volume/NATASA/t
  • From Paavo Helde@21:1/5 to All on Thu Sep 23 09:15:28 2021
    23.09.2021 00:42 daniel...@gmail.com kirjutas:
    On Wednesday, September 22, 2021 at 8:18:27 AM UTC-4, Paavo Helde wrote:
    22.09.2021 13:59 Bart kirjutas:

    So what would be the shiny new alternative in C++?
    std::to_string()

    https://en.cppreference.com/w/cpp/string/basic_string/to_string

    Strange that in a language that's supposed to support genericity and
    user provided allocators, we have these things that support neither genericity or user provided allocators.

    std::to_string() is a convenience function, meant for people who are
    uncapable of writing their own 3-liner wrappers around sprintf().

    stream<< is generic, but potentially slower and not so convenient to
    use, especially when the result should not go to a C++ stream.

    std::to_chars() is fast, but not generic (plus it also lacks locale
    support) and is not so convenient to use either as demonstrated by Alf's multi-page example about how to use it. It does not use allocators though.

    TBH, most std::string implementations are using short-string
    optimization nowadays, so in most cases std::to_string() should not
    involve any dynamic memory allocation either.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Thu Sep 23 07:31:24 2021
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design
    that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    If you need to use sprintf() C, then that's when you might also consider using sprint() elsewhere.

    sprintf() cannot be extended to support your own custom types.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Thu Sep 23 07:26:16 2021
    Bart <bc@freeuk.com> wrote:
    Having to overload "<<", as I assume you meant, as you seemed to imply
    that was better/easier than doing whatever it was to obj to allow its
    use in function syntax.

    So what's the alternative that you suggest?

    Overloading whatever 'tostring' operations that are implicitly used when printing.

    So your only alternative is to only support a "tostring" function?

    How about thanks, but no thanks? I'll take the operator<< overloading
    if your suggestions is the only available alternative.

    OK, let's try it. Here's a program that writes 1 million lines of the
    same 3 variables:

    You are comparing the seed of std::ostream to some other way of writing
    to a file. You are not comparing string creation vs. direct writing of
    values.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Thu Sep 23 11:05:56 2021
    23.09.2021 10:31 Juha Nieminen kirjutas:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>> that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    And how is it better to force every custom type to add support for
    std::ostream streaming? At least one can easily add formatting
    parameters to tostring() functions, with streams it becomes complicated
    and hidden.

    If memory and speed issues are critical then most probably one cannot or
    should not use iostreams anyway, so this point is moot.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Keith Thompson on Thu Sep 23 09:01:03 2021
    On Wed, 22 Sep 2021 14:13:39 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote: >HorseyWorsey@the_stables.com writes:
    [...]
    But then someone who writes "auto main() -> int" instead of "int main()"
    and then forgets the return value at the end anyway is probably not someone >> who writes sensible code.

    Were you not aware that reaching the closing "}" of main() does an
    implicit "return 0;"?

    And in C function return types default to int so perhaps for int functions
    we shouldn't bother to specify the types? Whats your point? If he decides
    to be a smartarse by using that syntax you'd think he'd dot all the i's etc.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Paavo Helde on Thu Sep 23 08:28:23 2021
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    23.09.2021 10:31 Juha Nieminen kirjutas:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>>> that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    And how is it better to force every custom type to add support for std::ostream streaming? At least one can easily add formatting
    parameters to tostring() functions, with streams it becomes complicated
    and hidden.

    So, what's *your* suggested alternative?

    (One could suggest std::format(), but AFAIK that's not going to be enormously more efficient either. It's more of a convenience thing than an efficiency thing.)

    Whatever your suggestion may be, it would be nice if it could be used in generic code, without much hassle. In other words, being able to do this
    kind of thing:

    template<typename T>
    void foobar(int value, const T& obj)
    {
    std::cout << "With value " << value << " we got:\n" << obj << "\n";
    }

    Preferably whatever the solution is, it shouldn't require the type
    to dynamically construct a string to be printed, and instead the
    type should get an std::ostream (or FILE*, or whatever) that it
    can use to directly write whatever it wants there.

    I'm not saying such an alternative is impossible (which is better than overloading operator<< for std::ostream). I'm just asking what it would
    look like.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Thu Sep 23 10:26:00 2021
    On Thu, 23 Sep 2021 11:18:02 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 03:03, Branimir Maksimovic wrote:
    On 2021-09-22, Bart <bc@freeuk.com> wrote:

    This was something that was so easy in the 1970s, and now so hard;
    except in my own languages where I keep it simple:

    int a, b, c
    print "Prompt> "
    readln a, b, c
    println a, b, c

    I tried it in C++ to see how well it coped:

    #include <iostream>

    int main()
    { int a,b,c;
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    }

    Same thing.
    But there is bug if user enters more or less then three. How you handle
    that case?

    How do you handle it in C++? There, if the user enters less than 3,

    You read in the entire line then split it up into tokens using whatever method takes your fancy.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Thu Sep 23 11:29:33 2021
    On 23/09/2021 08:31, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>> that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    I'm not forcing anything at all. Custom types can have dedicated
    tostring routines; or use default ones; or have nothing.

    You should look more towards scripting languages, you can learn a lot
    from them! They will usually have default printing of any types.

    (The first one I implemented was on IBM PCs with floppy disks, in
    mid-80s. The advantage was that functionality of a program could be
    stored as separate bytecode modules that could be loaded as needed,
    easing pressure on main memory.

    Of course, there were used where appropriate; not for the core routines
    (of my GUI apps) that needed to be fast.)

    If you need to use sprintf() C, then that's when you might also consider
    using sprint() elsewhere.

    sprintf() cannot be extended to support your own custom types.

    My point is that sprintf is used when you /want/ to end up with a
    string. Which is what my sprint() version of my print statement does.
    You didn't seem to like the idea of any print routine generating strings.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Branimir Maksimovic on Thu Sep 23 11:18:02 2021
    On 23/09/2021 03:03, Branimir Maksimovic wrote:
    On 2021-09-22, Bart <bc@freeuk.com> wrote:

    This was something that was so easy in the 1970s, and now so hard;
    except in my own languages where I keep it simple:

    int a, b, c
    print "Prompt> "
    readln a, b, c
    println a, b, c

    I tried it in C++ to see how well it coped:

    #include <iostream>

    int main()
    { int a,b,c;
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    }

    Same thing.
    But there is bug if user enters more or less then three. How you handle
    that case?

    How do you handle it in C++? There, if the user enters less than 3,
    nothing happens: the program apparenty hangs (waiting for more input).
    If more than 3, it doesn't detect that either, until mysterious things
    start happening on the next line.

    If you put my example into a loop, then for inputs of:

    10 20 30 40 50
    100 200 300 400 500

    where the user expects to see outputs of:

    10 20 30
    100 200 300

    they will in fact see, after entering only 2 lines:

    10 20 30
    40 50 100

    plus 200 300 400 as the output of a 3rd line that they haven't even
    entered! Then '500' will figure as the first number of the next line.

    It's missing an important thing: the ability to synchronise to each
    fresh line of input.

    In my version, there are a number of checks that can be made; missing
    items are zero. Error flags are set and can be accessed by special reads:

    read x:'E'

    but which need to be done after item (I'd need to look into my code, as
    I never bother for the casual use this is put to). In the dynamic
    version, missing items are set to "", so you can check the type.

    But you don't have to worry about input from multiple lines being
    jumbled up and losing track of which was the first number on a line, or
    using "," instead of " " screwing things up.


    In Swift:
    let values = readLine()?.components(separatedBy: CharacterSet.whitespacesAndNewlines) ?? []

    let valueOne = values.count > 0 ? Int(values[0]) : nil
    let valueTwo = values.count > 1 ? Int(values[1]) : nil

    so this handles correct.

    Yeah, this is Python-style too. You just grab the line of input as a
    string, and then have to effectively do your tokenising and conversions.

    But note that with this method, for the next line, it will discard the
    last line and read a fresh line, unlike the C++. It will resync.

    However, does you example allow spaces OR commas as separators?

    * If more, they are ignored. Whatever is entered on one line NEVER
    /what if that is not desired behavior? it is not clear from code.
    Don't do things behind peoples backs.

    Poeple are familiar with CLIs and know what to expect. Every fresh line
    of input is separate. They don't get a CLI which effectively
    concatenates all the user's input into one long line.

    On a Windows prompt, I can do:

    dir a b c

    or I can do:

    dir a, b, c

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bart on Thu Sep 23 10:26:55 2021
    On 2021-09-23, Bart <bc@freeuk.com> wrote:
    On 23/09/2021 03:03, Branimir Maksimovic wrote:
    On 2021-09-22, Bart <bc@freeuk.com> wrote:

    This was something that was so easy in the 1970s, and now so hard;
    except in my own languages where I keep it simple:

    int a, b, c
    print "Prompt> "
    readln a, b, c
    println a, b, c

    I tried it in C++ to see how well it coped:

    #include <iostream>

    int main()
    { int a,b,c;
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    }

    Same thing.
    But there is bug if user enters more or less then three. How you handle
    that case?

    How do you handle it in C++? There, if the user enters less than 3,
    nothing happens: the program apparenty hangs (waiting for more input).
    If more than 3, it doesn't detect that either, until mysterious things
    start happening on the next line.

    Same way as in Swift. getline on ' ' or '\'

    Greetings, Branimir.
    --
    7-77-777
    \|/
    ---
    /|\

    If you put my example into a loop, then for inputs of:

    10 20 30 40 50
    100 200 300 400 500

    where the user expects to see outputs of:

    10 20 30
    100 200 300

    they will in fact see, after entering only 2 lines:

    10 20 30
    40 50 100

    plus 200 300 400 as the output of a 3rd line that they haven't even
    entered! Then '500' will figure as the first number of the next line.

    It's missing an important thing: the ability to synchronise to each
    fresh line of input.

    In my version, there are a number of checks that can be made; missing
    items are zero. Error flags are set and can be accessed by special reads:

    read x:'E'

    but which need to be done after item (I'd need to look into my code, as
    I never bother for the casual use this is put to). In the dynamic
    version, missing items are set to "", so you can check the type.

    But you don't have to worry about input from multiple lines being
    jumbled up an
  • From Bart@21:1/5 to Bart on Thu Sep 23 12:40:26 2021
    On 23/09/2021 12:21, Bart wrote:
    On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
    On Thu, 23 Sep 2021 11:18:02 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 03:03, Branimir Maksimovic wrote:
    On 2021-09-22, Bart <bc@freeuk.com> wrote:

    This was something that was so easy in the 1970s, and now so hard;
    except in my own languages where I keep it simple:

           int a, b, c
           print "Prompt> "
           readln a, b, c
           println a, b, c

    I tried it in C++ to see how well it coped:

         #include <iostream>

         int main()
         {   int a,b,c;
             std::cout << "Prompt> ";
             std::cin >> a >> b >> c;
             std::cout << a << " " << b << " " << c << "\n";
         }

    Same thing.
    But there is bug if user enters more or less then three. How you handle >>>> that case?

    How do you handle it in C++? There, if the user enters less than 3,

    You read in the entire line then split it up into tokens using
    whatever method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do /line-oriented/ input.

    You're saying each programmer needs to reinvent this stuff?

    I've tested my version some more (still trying to read 3 integers):

     Input          Output of my code       Output of C++ code:

     "10" 20 30     10 20 30                Continuous zeros
     123'456 7 8    123456 7 8              123 then myriad zeros
     123_456 7 8    123456 7 8              Same
     .1234 5 6      0 5 6                   Same

    I mean same as the last example; just crazy stuff. Not the same as mine.

    Example:

    C:\c>a # C++ program with loop
    Prompt> 123'456 7 8 # this is what is typed
    123 0 0
    Prompt> 123 0 0 # these appear automatically
    Prompt> 123 0 0
    Prompt> 123 0 0
    Prompt> 123 0 0
    Prompt> 123 0 0
    Prompt> 123 0 0
    Prompt> 123 0 0
    Prompt> 123 0 0
    Prompt> 123 0 0
    ....

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to HorseyWorsey@the_stables.com on Thu Sep 23 12:21:48 2021
    On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
    On Thu, 23 Sep 2021 11:18:02 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 03:03, Branimir Maksimovic wrote:
    On 2021-09-22, Bart <bc@freeuk.com> wrote:

    This was something that was so easy in the 1970s, and now so hard;
    except in my own languages where I keep it simple:

    int a, b, c
    print "Prompt> "
    readln a, b, c
    println a, b, c

    I tried it in C++ to see how well it coped:

    #include <iostream>

    int main()
    { int a,b,c;
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    }

    Same thing.
    But there is bug if user enters more or less then three. How you handle
    that case?

    How do you handle it in C++? There, if the user enters less than 3,

    You read in the entire line then split it up into tokens using whatever method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do /line-oriented/ input.

    You're saying each programmer needs to reinvent this stuff?

    I've tested my version some more (still trying to read 3 integers):

    Input Output of my code Output of C++ code:

    "10" 20 30 10 20 30 Continuous zeros
    123'456 7 8 123456 7 8 123 then myriad zeros
    123_456 7 8 123456 7 8 Same
    .1234 5 6 0 5 6 Same
    -1234 5 6 -1234 5 6 -1234 5 6 (A miracle!)
    123e4 5 6 123 5 6 Goes crazy like above
    10,20,30 10 20 30 Goes crazy
    10+20+30 10 0 0 10 20 30
    10 10 0 0 Waits for more input
    19000000000000000000 3 4
    wrong val 3 4 i32.max then goes crazy


    Mine could be improved; but the C++ definitely needs some attention.

    7/10 and 3/10 respectively I think!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Damon@21:1/5 to Bart on Thu Sep 23 08:05:56 2021
    On 9/23/21 7:21 AM, Bart wrote:
    On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
    On Thu, 23 Sep 2021 11:18:02 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 03:03, Branimir Maksimovic wrote:
    On 2021-09-22, Bart <bc@freeuk.com> wrote:

    This was something that was so easy in the 1970s, and now so hard;
    except in my own languages where I keep it simple:

           int a, b, c
           print "Prompt> "
           readln a, b, c
           println a, b, c

    I tried it in C++ to see how well it coped:

         #include <iostream>

         int main()
         {   int a,b,c;
             std::cout << "Prompt> ";
             std::cin >> a >> b >> c;
             std::cout << a << " " << b << " " << c << "\n";
         }

    Same thing.
    But there is bug if user enters more or less then three. How you handle >>>> that case?

    How do you handle it in C++? There, if the user enters less than 3,

    You read in the entire line then split it up into tokens using
    whatever method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do /line-oriented/ input.

    Then use line oriented processing. That would be gets (or maybe better
    fgets to avoid overrun attacks) to get the line, and then parse with the
    method you want, sscanf if you can deal with the default error handling.

    C++ has similar functions for streams.

    Don't complain that your hammer doesn't work well on screws.


    You're saying each programmer needs to reinvent this stuff?

    I've tested my version some more (still trying to read 3 integers):

     Input          Output of my code       Output of C++ code:

     "10" 20 30     10 20 30                Continuous zeros  123'456 7 8    123456 7 8              123 then myriad zeros
     123_456 7 8    123456 7 8              Same
     .1234 5 6      0 5 6                   Same
     -1234 5 6      -1234 5 6               -1234 5 6 (A miracle!)
     123e4 5 6      123 5 6                 Goes crazy like above
     10,20,30       10 20 30                Goes crazy  10+20+30       10 0 0                  10 20 30  10             10 0 0                  Waits for more input
     19000000000000000000 3 4
                    wrong val 3 4           i32.max then goes crazy


    Mine could be improved; but the C++ definitely needs some attention.

    7/10 and 3/10 respectively I think!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Manfred on Thu Sep 23 14:04:48 2021
    Manfred <noname@add.invalid> writes:
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be
    natively supported by the core language. Then it can be kept streamlined >>> without wasting too much compiler time on it.

    That's your view. It is not unique to you, but it is not the view of
    many other people.


    Actually this view was (and still is) shared by the creators of C and of
    C++.
    In fact, that is the only reason (every language should have it as an >unavoidable axiom) that I can see for C to have a function like printf:
    as a systems language, you don't need formatting support, you just need
    the ability to send chars to some device.

    As someone who has been crafting operating systems for over forty
    years from mainframes to 5G base stations, your assertion is complete nonsense.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Juha Nieminen on Thu Sep 23 14:07:31 2021
    Juha Nieminen <nospam@thanks.invalid> writes:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>> that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    If you need to use sprintf() C, then that's when you might also consider
    using sprint() elsewhere.

    sprintf() cannot be extended to support your own custom types.

    Please. Competent C programmers eschew sprintf. It's dangerous and
    should be deprecated.

    snprintf is bounded and far safer than sprintf.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Richard Damon on Thu Sep 23 15:02:37 2021
    On 23/09/2021 13:05, Richard Damon wrote:
    On 9/23/21 7:21 AM, Bart wrote:

    How do you handle it in C++? There, if the user enters less than 3,

    You read in the entire line then split it up into tokens using
    whatever method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do
    /line-oriented/ input.

    Then use line oriented processing. That would be gets (or maybe better
    fgets to avoid overrun attacks) to get the line, and then parse with the method you want, sscanf if you can deal with the default error handling.

    C++ has similar functions for streams.

    So it /doesn't/ support line-oriented input unless you implement it
    yourself. /That/ is my complaint.

    This is a similar example in Basic:

    for i=1 to 3
    print "Prompt> "; rem ";" suppresses the newline
    input a,b,c rem I think this grabs a fresh line
    print a,b,c
    next i

    It works better than the C++! And better than C's scanf which everyone
    tries to avoid using.

    None of this is really surprising; I've also had the impression that the
    job of C++ was to make things more complicated than necessary and not
    simpler. (Perhaps it wouldn't do to have just anybody being able to use
    the language.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Thu Sep 23 14:58:48 2021
    On Thu, 23 Sep 2021 12:21:48 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
    You read in the entire line then split it up into tokens using whatever >method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do >/line-oriented/ input.

    You're saying each programmer needs to reinvent this stuff?

    Its not exactly rocket science. C++ isn't and isn't intended to be a hand holding scripting language, some things you have to know how to do yourself.

    Input Output of my code Output of C++ code:

    "10" 20 30 10 20 30 Continuous zeros
    123'456 7 8 123456 7 8 123 then myriad zeros
    123_456 7 8 123456 7 8 Same
    .1234 5 6 0 5 6 Same
    -1234 5 6 -1234 5 6 -1234 5 6 (A miracle!)
    123e4 5 6 123 5 6 Goes crazy like above
    10,20,30 10 20 30 Goes crazy
    10+20+30 10 0 0 10 20 30
    10 10 0 0 Waits for more input
    19000000000000000000 3 4
    wrong val 3 4 i32.max then goes crazy


    Mine could be improved; but the C++ definitely needs some attention.

    C++ cin is as useless as C's scanf() for doing actual real world stdin input processing. Unless the users follows the expected format then it all blows up. As I said, you read in the entire string then parse it using std::string find() and substr() or C's strtok() or even raw pointers. Either way an experienced programmer should take longer than 20 mins to come up with something.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Siri Cruise@21:1/5 to alessandro volturno on Thu Sep 23 07:38:17 2021
    In article <shvf4c$ark$3@gioia.aioe.org>,
    alessandro volturno <alessandro.volturno@libero.it> wrote:

    why not to introduce a way to handle rational numbers inside the C++
    standard or better make it a built in type?

    I'm working on an extension for erratic numbers, double precision
    that fills add/subtract loss of signficance with random bits.
    That will form a basis for happy numbers, sad numbers, and angry
    numbers, and more generally, emotional numbers.

    --
    :-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
    'I desire mercy, not sacrifice.' /|\ Discordia: not just a religion but also a parody. This post / \
    I am an Andrea Doria sockpuppet. insults Islam. Mohammed

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Scott Lurndal on Thu Sep 23 14:50:08 2021
    On 2021-09-23, Scott Lurndal <scott@slp53.sl.home> wrote:
    Juha Nieminen <nospam@thanks.invalid> writes:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>>> that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every >>custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    If you need to use sprintf() C, then that's when you might also consider >>> using sprint() elsewhere.

    sprintf() cannot be extended to support your own custom types.

    Please. Competent C programmers eschew sprintf. It's dangerous and
    should be deprecated.

    snprintf is bounded and far safer than sprintf.
    +1
    you can use sprintf still, if you can predict size of input.

    --
    7-77-777
    \|/
    ---
    /|\

    --
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to Scott Lurndal on Thu Sep 23 17:47:24 2021
    On 9/23/2021 4:04 PM, Scott Lurndal wrote:
    Manfred <noname@add.invalid> writes:
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be
    natively supported by the core language. Then it can be kept streamlined >>>> without wasting too much compiler time on it.

    That's your view. It is not unique to you, but it is not the view of
    many other people.


    Actually this view was (and still is) shared by the creators of C and of
    C++.
    In fact, that is the only reason (every language should have it as an
    unavoidable axiom) that I can see for C to have a function like printf:
    as a systems language, you don't need formatting support, you just need
    the ability to send chars to some device.

    As someone who has been crafting operating systems for over forty
    years from mainframes to 5G base stations, your assertion is complete nonsense.


    Thanks for the "nonsense" label.
    Just for the record, David Brown has just confirmed that printing (aka formatting in this context) is an "optional" library feature, that is in
    fact often /not/ used in some types of systems.

    Will you please come to an agreement before insulting me?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to HorseyWorsey@the_stables.com on Thu Sep 23 17:02:36 2021
    On 23/09/2021 15:58, HorseyWorsey@the_stables.com wrote:
    On Thu, 23 Sep 2021 12:21:48 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 11:26, HorseyWorsey@the_stables.com wrote:
    You read in the entire line then split it up into tokens using whatever
    method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do
    /line-oriented/ input.

    You're saying each programmer needs to reinvent this stuff?

    Its not exactly rocket science. C++ isn't and isn't intended to be a hand holding scripting language, some things you have to know how to do yourself.

    I usually devise my own languages, including those for systems programming.

    Without exception they had means to do line-based i/o as one of the
    first things implemented.

    Is that the attitude here, that such fundamental features are to be
    looked down upon because they would make life too easy?

    Or is this another Unix characteristic bestowed upon the world (on top
    of case-sensitivity etc): character-based i/o rather than line-based?


    Input Output of my code Output of C++ code:

    "10" 20 30 10 20 30 Continuous zeros
    123'456 7 8 123456 7 8 123 then myriad zeros
    123_456 7 8 123456 7 8 Same
    .1234 5 6 0 5 6 Same
    -1234 5 6 -1234 5 6 -1234 5 6 (A miracle!)
    123e4 5 6 123 5 6 Goes crazy like above
    10,20,30 10 20 30 Goes crazy
    10+20+30 10 0 0 10 20 30
    10 10 0 0 Waits for more input
    19000000000000000000 3 4
    wrong val 3 4 i32.max then goes crazy


    Mine could be improved; but the C++ definitely needs some attention.

    C++ cin is as useless as C's scanf() for doing actual real world stdin input processing. Unless the users follows the expected format then it all blows up.
    As I said, you read in the entire string then parse it using std::string find()
    and substr() or C's strtok() or even raw pointers. Either way an experienced programmer should take longer than 20 mins to come up with something.

    In other words, a million programmers have to keep reinventing the same
    thing. Or a million variations of the same thing.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to HorseyWorsey@the_stables.com on Thu Sep 23 12:08:32 2021
    On 9/23/21 5:01 AM, HorseyWorsey@the_stables.com wrote:
    On Wed, 22 Sep 2021 14:13:39 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    Were you not aware that reaching the closing "}" of main() does an
    implicit "return 0;"?

    And in C function return types default to int ...
    That hasn't been true since C99, 22 years ago, and that's the same
    version in which the rule that Keith mentioned was added to C. There's
    never been a version of standard C for which both features applied.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to David Brown on Thu Sep 23 18:42:23 2021
    On 9/22/2021 11:51 PM, David Brown wrote:
    On 22/09/2021 23:45, Manfred wrote:
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be
    natively supported by the core language. Then it can be kept streamlined >>>> without wasting too much compiler time on it.

    That's your view.  It is not unique to you, but it is not the view of
    many other people.


    Actually this view was (and still is) shared by the creators of C and of
    C++.

    It is not part of the core language. It is part of the standard
    library. That's a very different thing. In particular, the great
    majority of printf implementations are written in C, the great majority
    of iostream implementations are written in C++.
    (Implementation-specific behaviour might be needed.) Printing is not a special statement in either language - it is handled by library
    functions that are optional (small embedded systems often don't use
    them, for example), and can be replaced by alternatives.


    Agreed.
    My point is about having it in the language as in the "language
    specification", which includes the standard library, a broader sense
    than yours.

    It appears that we agree that printing support (or formatting, as I
    wrote afterwards) is not strictly needed from the language as long as it
    offers the means, if you need it, to build or integrate alternatives
    according to your needs.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Thu Sep 23 16:21:20 2021
    On Thu, 23 Sep 2021 17:02:36 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 15:58, HorseyWorsey@the_stables.com wrote:
    Its not exactly rocket science. C++ isn't and isn't intended to be a hand
    holding scripting language, some things you have to know how to do yourself.

    I usually devise my own languages, including those for systems programming.

    Clever you.

    Is that the attitude here, that such fundamental features are to be
    looked down upon because they would make life too easy?

    Your attitude seems to be "C++ doesn't do what I want therefore its crap".
    C++ is what it is. If you don't like it use another language, you have plenty to choose from including your own.

    As I said, you read in the entire string then parse it using std::string >find()
    and substr() or C's strtok() or even raw pointers. Either way an experienced >> programmer should take longer than 20 mins to come up with something.

    In other words, a million programmers have to keep reinventing the same >thing. Or a million variations of the same thing.

    Since a basic line splitter is easy for any half competant programmer and anything more complex - ie a parser - is usually tuned for a particular need what would be the point? C++ has already had the kitchen sink thrown into it because of people like you yet you want even basic stuff done for you? What next , concatenation too hard? Perhaps a built in function that automatically concats a vector of strings for you? Maybe you'd be better off using javascript.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Manfred on Thu Sep 23 17:07:31 2021
    Manfred <noname@add.invalid> writes:
    On 9/23/2021 4:04 PM, Scott Lurndal wrote:
    Manfred <noname@add.invalid> writes:
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be >>>>> natively supported by the core language. Then it can be kept streamlined >>>>> without wasting too much compiler time on it.

    That's your view. It is not unique to you, but it is not the view of
    many other people.


    Actually this view was (and still is) shared by the creators of C and of >>> C++.
    In fact, that is the only reason (every language should have it as an
    unavoidable axiom) that I can see for C to have a function like printf:
    as a systems language, you don't need formatting support, you just need
    the ability to send chars to some device.

    As someone who has been crafting operating systems for over forty
    years from mainframes to 5G base stations, your assertion is complete nonsense.


    Thanks for the "nonsense" label.
    Just for the record, David Brown has just confirmed that printing (aka >formatting in this context) is an "optional" library feature, that is in
    fact often /not/ used in some types of systems.

    Will you please come to an agreement before insulting me?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Manfred on Thu Sep 23 17:08:34 2021
    Manfred <noname@add.invalid> writes:
    On 9/23/2021 4:04 PM, Scott Lurndal wrote:
    Manfred <noname@add.invalid> writes:

    In fact, that is the only reason (every language should have it as an
    unavoidable axiom) that I can see for C to have a function like printf:
    as a systems language, you don't need formatting support, you just need
    the ability to send chars to some device.

    As someone who has been crafting operating systems for over forty
    years from mainframes to 5G base stations, your assertion is complete nonsense.


    Thanks for the "nonsense" label.
    Just for the record, David Brown has just confirmed that printing (aka >formatting in this context) is an "optional" library feature, that is in
    fact often /not/ used in some types of systems.

    You wrote:

    as a systems language, you don't need formatting support

    Which is complete nonsense. I stand by my assertion.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to Scott Lurndal on Thu Sep 23 19:30:59 2021
    On 9/23/2021 7:08 PM, Scott Lurndal wrote:
    Manfred <noname@add.invalid> writes:
    On 9/23/2021 4:04 PM, Scott Lurndal wrote:
    Manfred <noname@add.invalid> writes:

    In fact, that is the only reason (every language should have it as an
    unavoidable axiom) that I can see for C to have a function like printf: >>>> as a systems language, you don't need formatting support, you just need >>>> the ability to send chars to some device.

    As someone who has been crafting operating systems for over forty
    years from mainframes to 5G base stations, your assertion is complete nonsense.


    Thanks for the "nonsense" label.
    Just for the record, David Brown has just confirmed that printing (aka
    formatting in this context) is an "optional" library feature, that is in
    fact often /not/ used in some types of systems.

    You wrote:

    as a systems language, you don't need formatting support

    Which is complete nonsense. I stand by my assertion.


    Maybe we refer to different meanings of formatting in this context, or whatever.

    I find it really hard to try and reason with such an insulting attitude.
    Have it your way.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to HorseyWorsey@the_stables.com on Thu Sep 23 18:31:34 2021
    On 23/09/2021 17:21, HorseyWorsey@the_stables.com wrote:
    On Thu, 23 Sep 2021 17:02:36 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 15:58, HorseyWorsey@the_stables.com wrote:
    Its not exactly rocket science. C++ isn't and isn't intended to be a hand >>> holding scripting language, some things you have to know how to do yourself.

    I usually devise my own languages, including those for systems programming.

    Clever you.

    Is that the attitude here, that such fundamental features are to be
    looked down upon because they would make life too easy?

    Your attitude seems to be "C++ doesn't do what I want therefore its crap". C++ is what it is. If you don't like it use another language, you have plenty to choose from including your own.

    As I said, you read in the entire string then parse it using std::string
    find()
    and substr() or C's strtok() or even raw pointers. Either way an experienced
    programmer should take longer than 20 mins to come up with something.

    In other words, a million programmers have to keep reinventing the same
    thing. Or a million variations of the same thing.

    Since a basic line splitter is easy for any half competant programmer and anything more complex - ie a parser - is usually tuned for a particular need what would be the point? C++ has already had the kitchen sink thrown into it because of people like you yet you want even basic stuff done for you?

    This is the paradox: C++ has a lot of hugely complicated but neglects
    the basics.

    And it's just C++ but a lot of current languages, because they have
    their focus elsewhere. (I especially know about Python.)

    An effective basic Print (and Read) needs language support otherwise it
    becomes a pain to use.

    The support needed is not significant. My proof-of-concept to add
    automatic printf format codes to a C compiler (so you do "%?" for any
    basic type instead of "%d" etc), was 50 lines of code.

    That would simplify the maintenance of a billion codes of code.



    What
    next , concatenation too hard? Perhaps a built in function that automatically concats a vector of strings for you? Maybe you'd be better off using javascript.

    So. why bother with even std::cout (I still don't know what that
    actually is) or printf? Just have fgetc and fputc.

    After all how hard can it be to knock up an int-to-string converter? The language already has enough stuff in it!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to HorseyWorsey@the_stables.com on Thu Sep 23 10:55:15 2021
    HorseyWorsey@the_stables.com writes:
    On Wed, 22 Sep 2021 14:13:39 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    HorseyWorsey@the_stables.com writes:
    [...]
    But then someone who writes "auto main() -> int" instead of "int main()" >>> and then forgets the return value at the end anyway is probably not someone >>> who writes sensible code.

    Were you not aware that reaching the closing "}" of main() does an
    implicit "return 0;"?

    And in C function return types default to int so perhaps for int functions
    we shouldn't bother to specify the types?

    That is neither true nor relevant. C dropped the implicit int rule in 1999.

    Whats your point? If he decides
    to be a smartarse by using that syntax you'd think he'd dot all the i's etc.

    My point is that your criticism is invalid. Omitting a final "return 0;"
    in main is perfectly valid. It's not an i that needs to be dotted.
    (See the code examples in Stroustrup's books.)

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Manfred on Thu Sep 23 21:52:46 2021
    On 23/09/2021 18:42, Manfred wrote:
    On 9/22/2021 11:51 PM, David Brown wrote:
    On 22/09/2021 23:45, Manfred wrote:
    On 9/20/2021 6:08 PM, David Brown wrote:
    On 20/09/2021 17:11, Bart wrote:
    <snip>

    My view is that basic Print is a fundamental feature that needs to be >>>>> natively supported by the core language. Then it can be kept
    streamlined
    without wasting too much compiler time on it.

    That's your view.  It is not unique to you, but it is not the view of >>>> many other people.


    Actually this view was (and still is) shared by the creators of C and of >>> C++.

    It is not part of the core language.  It is part of the standard
    library.  That's a very different thing.  In particular, the great
    majority of printf implementations are written in C, the great majority
    of iostream implementations are written in C++.
    (Implementation-specific behaviour might be needed.)  Printing is not a
    special statement in either language - it is handled by library
    functions that are optional (small embedded systems often don't use
    them, for example), and can be replaced by alternatives.


    Agreed.
    My point is about having it in the language as in the "language specification", which includes the standard library, a broader sense
    than yours.

    Yes, I can see that. That is why I made the distinction of the /core/ language. That includes statements, expressions, operators, types, etc.
    It can also language support libraries that come with compilers - for
    more limited processors, things like floating point might be in a
    software library. (These are for function calls generated by the
    compiler, rather than written in the source code.) And some headers
    would be included as they are required for the language - for example,
    the language "sizeof" operator evaluates to an expression of type
    "size_t" defined in <stddef.h>.

    (One could reasonably argue that it would be better to talk about
    "freestanding C and C++ environments, rather than "core language" - at
    least these terms are well defined in the standards.)


    It appears that we agree that printing support (or formatting, as I
    wrote afterwards) is not strictly needed from the language as long as it offers the means, if you need it, to build or integrate alternatives according to your needs.

    Yes, indeed. When you have such flexible and general purpose languages
    as C and C++, then any given solution to printing will be far too big
    and complicated for some use-cases, and far too small and limited for
    others. The language has to provide the tools you need to make the
    solutions you need. And then the standard library can provide one or
    more printing and formatting systems that suit a wide range of programs,
    so that you only need to re-invent the wheel when you really need a new one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Bart on Fri Sep 24 08:48:00 2021
    On 24/09/2021 02:02, Bart wrote:
    On 23/09/2021 13:05, Richard Damon wrote:
    On 9/23/21 7:21 AM, Bart wrote:

    How do you handle it in C++? There, if the user enters less than 3,

    You read in the entire line then split it up into tokens using
    whatever method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do
    /line-oriented/ input.

    Then use line oriented processing. That would be gets (or maybe better
    fgets to avoid overrun attacks) to get the line, and then parse with the
    method you want, sscanf if you can deal with the default error handling.

    C++ has similar functions for streams.

    So it /doesn't/ support line-oriented input unless you implement it
    yourself. /That/ is my complaint.

    This is a similar example in Basic:

    for i=1 to 3
    print "Prompt> "; rem ";" suppresses the newline
    input a,b,c rem I think this grabs a fresh line
    print a,b,c
    next i

    It works better than the C++! And better than C's scanf which everyone
    tries to avoid using.

    How is that fundamentally different from

    for( int i = 0; i < 3; ++i )
    {
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << ' ' << b << ' ' << c << '\n';
    }
    ?

    --
    Ian.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Manfred on Fri Sep 24 10:06:27 2021
    On 24/09/2021 05:30, Manfred wrote:
    On 9/23/2021 7:08 PM, Scott Lurndal wrote:
    Manfred <noname@add.invalid> writes:
    On 9/23/2021 4:04 PM, Scott Lurndal wrote:
    Manfred <noname@add.invalid> writes:

    In fact, that is the only reason (every language should have it as an >>>>> unavoidable axiom) that I can see for C to have a function like printf: >>>>> as a systems language, you don't need formatting support, you just need >>>>> the ability to send chars to some device.

    As someone who has been crafting operating systems for over forty
    years from mainframes to 5G base stations, your assertion is complete nonsense.


    Thanks for the "nonsense" label.
    Just for the record, David Brown has just confirmed that printing (aka
    formatting in this context) is an "optional" library feature, that is in >>> fact often /not/ used in some types of systems.

    You wrote:

    as a systems language, you don't need formatting support

    Which is complete nonsense. I stand by my assertion.


    Maybe we refer to different meanings of formatting in this context, or whatever.

    I find it really hard to try and reason with such an insulting attitude.
    Have it your way.

    Incorrect might be a kinder way of putting it.

    Many command line tools provide a variety of output formatting options,
    such as human and machine readable formats. Even basic kernel and
    driver logging requires some degree of formatting (timestamps, fixed
    widths etc.). Much "systems" programming is tool writing.

    --
    Ian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Fri Sep 24 00:51:10 2021
    23.09.2021 11:28 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    23.09.2021 10:31 Juha Nieminen kirjutas:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>>>> that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    And how is it better to force every custom type to add support for
    std::ostream streaming? At least one can easily add formatting
    parameters to tostring() functions, with streams it becomes complicated
    and hidden.

    So, what's *your* suggested alternative?

    Suggested alternative for what? Formatting or streaming?

    The solutions like printf() and iostreams mix these two up and attempt
    to solve them both in one go, and do not really succeed in either, IMO.

    Or do you mean an alternative easy syntax for debug printouts? That's a
    totally another topic (which I'm not very interested in).


    (One could suggest std::format(), but AFAIK that's not going to be enormously more efficient either. It's more of a convenience thing than an efficiency thing.)

    The best performance is delivered by formatting the data into raw
    memory. That's what std::to_chars() and Boost's double-conversion are doing.

    To avoid memory and latency overheads, this raw memory should be
    periodically flushed out to the final destination. For example, if the
    output is sent out over network, ideally each TCP frame should be sent
    out as soon as it is ready. If it is written in a disk file, the content
    should be flushed before the computer free memory is exhausted, etc.

    The idea with iostreams is that the data is flushed by each primitive
    value written. This can become a bottleneck because iostreams are keen
    on doing formatting in addition to streaming and are thus choked full of virtual functions and multithread-hostile locale dependencies.

    My solution would be to cleanly separate the formatting and the
    streaming parts. The class would format its content to a raw memory
    buffer as needed, and the streaming part would flush the buffer to the destination as often as needed.

    One thing with today's many-gigabyte machines is that in most cases this
    need to flush never appears, the whole data structure can be easily
    formatted into raw memory fully before sending it to anywhere. BTW, one
    does not need to use a fixed-size buffer, for example
    std::string::append() is perfectly capable of growing the buffer with
    amortized constant complexity.

    Some motivations for formatting the whole file in memory first: when
    sending data over network one often wants to send Content-Length first
    which might not be known before formatting the whole packet. When
    storing the data in a local file it often does not really matter if the
    file sits in RAM in a userland buffer or in the kernel disk cache.

    Thus we arrive to the dreaded "tostring" solution (advocated by Bart for example). The whole data structure is first formatted into a std::string
    or equiv, then streamed out to std::cout or wherever.

    Understandably, this solution does not fit 8-bit controllers and like,
    but neither do iostreams! At least the "tostring" solution cleanly
    separates the formatting and streaming parts, and allows for easy way to
    pass formatting parameters to the formatting part. Tell me again how do
    I instruct my class operator<< to place "</td><td>" between each output
    number when formatting HTML output?


    Whatever your suggestion may be, it would be nice if it could be used in generic code, without much hassle. In other words, being able to do this
    kind of thing:

    template<typename T>
    void foobar(int value, const T& obj)
    {
    std::cout << "With value " << value << " we got:\n" << obj << "\n";
    }

    Preferably whatever the solution is, it shouldn't require the type
    to dynamically construct a string to be printed, and instead the
    type should get an std::ostream (or FILE*, or whatever) that it
    can use to directly write whatever it wants there.

    Why? Is this just because of memory overhead concerns?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Ian Collins on Thu Sep 23 23:05:25 2021
    On 23/09/2021 21:48, Ian Collins wrote:
    On 24/09/2021 02:02, Bart wrote:
    On 23/09/2021 13:05, Richard Damon wrote:
    On 9/23/21 7:21 AM, Bart wrote:

    How do you handle it in C++? There, if the user enters less than 3, >>>>>
    You read in the entire line then split it up into tokens using
    whatever method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do
    /line-oriented/ input.

    Then use line oriented processing. That would be gets (or maybe better
    fgets to avoid overrun attacks) to get the line, and then parse with the >>> method you want, sscanf if you can deal with the default error handling. >>>
    C++ has similar functions for streams.

    So it /doesn't/ support line-oriented input unless you implement it
    yourself. /That/ is my complaint.

    This is a similar example in Basic:

        for i=1 to 3
          print "Prompt> ";         rem ";" suppresses the newline >>       input a,b,c               rem I think this grabs a fresh line
          print a,b,c
        next i

    It works better than the C++! And better than C's scanf which everyone
    tries to avoid using.

    How is that fundamentally different from

      for( int i = 0; i < 3; ++i )
      {
        std::cout << "Prompt> ";
        std::cin >> a >> b >> c;
        std::cout << a << ' ' << b << ' ' << c << '\n';
      }
    ?


    Haven't you followed the thread? A lot of things have been pointed out.
    But here's a summary of issues with the C++ loop:


    * It's not line-oriented; the new lines get out of sync with the data
    being read

    * If fewer than 3 items are present on a line, then it apparently hangs,
    with no explanation, waiting for them on the next line

    * If more than 3 items are present on a line, then those aren't
    discarded, but are confusingly used as input for a, b, c for the next
    line. So if 400 and 500 are extra items, and the user enters 10 20 30 on
    the next line, if will read '400 500 10', with 20 and 30 rolled over to
    the subsequent line

    * If more than 3 extra items are present, then on the next iteration, it doesn't wait for user input at all. If will not do so until everything
    on that initial line is consumed

    * Numeric separators within numbers such as "_" and "'" are not
    recognised, and cause an error

    * Numbers which are quoted are not recognised, and cause an error

    * Separators between numbers other than white space are not recognised,
    such as commas, and cause an error

    * Floating point numbers (using "." and/or "e") are not recognised;
    those characters cause an error

    * When an out-of-range number is entered, it reads i32.max (etc) for
    that number, but also generates an error

    * I mentioned error a few times, when that happens, it goes crazy. I
    think the internal pointer is not stepped past it, and it just reads
    zeros, so it never consumes the rest of the line. So in a loop, it just
    prints zeros over and over again without the user entering anything.

    Apart from that it's fine!


    The behaviour of mine (bearing in mind I only use the feature casually,
    and it's never been implemented comprehensively), is as follows:

    * It is strictly line oriented. Each READLN discards the rest of the
    last read, and asks for a fresh line of input. It can never get out of sync

    * If fewer than 3 items are entered, the missing ones are zero. (In
    dynamic version, they are read as "".) It will not hang.

    * If more than 3 items are entered, those are ignored. (A program would
    have to speculatively read a fourth item, as a string, to test for
    trailing characters)

    * Numeric separators within numbers like "_" and "'" are recognised and skipped.

    * Numbers can be separated by white space or commas, or a mix (remember
    this can be used for ad hoc user input, not tidy machine-generated files)

    * Floating point numbers are properly consumed, then converted to ints
    (when reading int values)

    * Out-of-range numbers are truncated to 64 bits (for int types). (In
    dynamic version, it results in a bignum value.)

    * For certain errors, internal flags are set, which can be interrogated
    with a special Read (eg. read err:"e"), but I rarely do so. It doesn't
    now screw any line synchronisation

    * Print items can be enclosed in quotes. (Mainly for the benefit of
    strings, names etc which then allow embedded spaces, commas and quotes,
    but all print items share the same tokenisation step.)


    Hope that answers your question! I can't speak specifically for that
    Basic code, as I only tested one version, and only to confirm that it
    appeared to be line-oriented too.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to Bart on Thu Sep 23 16:56:52 2021
    Bart <bc@freeuk.com> writes:
    On 23/09/2021 21:48, Ian Collins wrote:
    On 24/09/2021 02:02, Bart wrote:
    [...]
    This is a similar example in Basic:

        for i=1 to 3
          print "Prompt> ";         rem ";" suppresses the newline >>>       input a,b,c               rem I think this grabs a fresh line
          print a,b,c
        next i

    It works better than the C++! And better than C's scanf which everyone
    tries to avoid using.
    How is that fundamentally different from
      for( int i = 0; i < 3; ++i )
      {
        std::cout << "Prompt> ";
        std::cin >> a >> b >> c;
        std::cout << a << ' ' << b << ' ' << c << '\n';
      }
    ?

    Haven't you followed the thread? A lot of things have been pointed
    out. But here's a summary of issues with the C++ loop:


    * It's not line-oriented; the new lines get out of sync with the data
    being read

    Right, it's not designed to be. For example:

    int a, b, c;
    std::cin >> a >> b >> c;
    std::cout << "a=" << a << " b=" << b << " c=" << c << '\n';

    The std::cin line reads integer values, skipping white space (which
    includes newlines) before each. If you just want to skip white space
    other than newlines, there's probably a way to do that.

    If you want line-oriented input, read a line at a time using
    std::getline() and then parse each line. It's not that hard.

    std::string line;
    std::getline(std::cin, line);
    std::stringstream ss(line);
    ss >> a >> b >> c;

    * If fewer than 3 items are present on a line, then it apparently
    hangs, with no explanation, waiting for them on the next line

    Because it's not line-oriented.

    * If more than 3 items are present on a line, then those aren't
    discarded, but are confusingly used as input for a, b, c for the
    next line. So if 400 and 500 are extra items, and the user enters 10
    20 30 on the next line, if will read '400 500 10', with 20 and 30
    rolled over to the subsequent line

    Because it's not line-oriented.

    * If more than 3 extra items are present, then on the next iteration,
    it doesn't wait for user input at all. If will not do so until
    everything on that initial line is consumed

    Because it's not line-oriented.

    * Numeric separators within numbers such as "_" and "'" are not
    recognised, and cause an error

    Right. Just how permissive do you think it should be?

    * Numbers which are quoted are not recognised, and cause an error

    Right. 123 is a number; "123", “123”, '123', and «123» are not.

    * Separators between numbers other than white space are not
    recognised, such as commas, and cause an error

    Right.

    * Floating point numbers (using "." and/or "e") are not recognised;
    those characters cause an error

    Right. You can read into a floating-point object if you want to support floating-point syntax.

    * When an out-of-range number is entered, it reads i32.max (etc) for
    that number, but also generates an error

    Yes, and?

    * I mentioned error a few times, when that happens, it goes crazy. I
    think the internal pointer is not stepped past it, and it just reads
    zeros, so it never consumes the rest of the line. So in a loop, it
    just prints zeros over and over again without the user entering
    anything.

    It's difficult to respond to that without an example.

    [...]

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bart on Thu Sep 23 23:47:39 2021
    On 2021-09-23, Bart <bc@freeuk.com> wrote:
    On 23/09/2021 21:48, Ian Collins wrote:
    On 24/09/2021 02:02, Bart wrote:
    On 23/09/2021 13:05, Richard Damon wrote:
    On 9/23/21 7:21 AM, Bart wrote:

    How do you handle it in C++? There, if the user enters less than 3, >>>>>>
    You read in the entire line then split it up into tokens using
    whatever method
    takes your fancy.



    Example?

    My original point was for a language to provide ready means to do
    /line-oriented/ input.

    Then use line oriented processing. That would be gets (or maybe better >>>> fgets to avoid overrun attacks) to get the line, and then parse with the >>>> method you want, sscanf if you can deal with the default error handling. >>>>
    C++ has similar functions for streams.

    So it /doesn't/ support line-oriented input unless you implement it
    yourself. /That/ is my complaint.

    This is a similar example in Basic:

        for i=1 to 3
          print "Prompt> ";         rem ";" suppresses the newline >>>       input a,b,c               rem I think this grabs a fresh line
          print a,b,c
        next i

    It works better than the C++! And better than C's scanf which everyone
    tries to avoid using.

    How is that fundamentally different from

      for( int i = 0; i < 3; ++i )
      {
        std::cout << "Prompt> ";
        std::cin >> a >> b >> c;
        std::cout << a << ' ' << b << ' ' << c << '\n';
      }
    ?


    Haven't you followed the thread? A lot of things have been pointed out.
    But here's a summary of issues with the C++ loop:


    * It's not line-oriented; the new lines get out of sync with the data
    being read

    * If fewer than 3 items are present on a line, then it apparently hangs,
    with no explanation, waiting for them on the next line
    streams are for serialization, getline is for user input.

    --
    7-77-777
    \|/
    ---
    /|\


    * If more than 3 items are present on a line, then those aren't
    discarded, but are confusingly used as input for a, b, c for the next
    line. So if 400 and 500 are extra items, and the user enters 10 20 30 on
    the next line, if will read '400 500 10', with 20 and 30 rolled over to
    the subsequent line

    * If more than 3 extra items are present, then on the next iteration, it doesn't wait for user input at all. If will not do so until everything
    on that initial line is consumed

    * Numeric separators within numbers such as "_" and "'" are not
    recognised, and cause an error

    * Numbers which are quoted are not recognised, and cause an error

    * Separators between numbers other than white space are not recognised,
    such as commas, and cause an error

    * Floating point numbers (using "." and/or "e") are not recognised;
    those characters cause an error

    * When an out-of-range number is entered, it reads i32.max (etc) for
    that number, but also genera
  • From Bart@21:1/5 to Keith Thompson on Fri Sep 24 01:58:42 2021
    On 24/09/2021 00:56, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:

    * It's not line-oriented; the new lines get out of sync with the data
    being read

    Right, it's not designed to be. For example:

    int a, b, c;
    std::cin >> a >> b >> c;
    std::cout << "a=" << a << " b=" << b << " c=" << c << '\n';

    The std::cin line reads integer values, skipping white space (which
    includes newlines) before each. If you just want to skip white space
    other than newlines, there's probably a way to do that.

    If you want line-oriented input, read a line at a time using
    std::getline() and then parse each line. It's not that hard.

    std::string line;
    std::getline(std::cin, line);
    std::stringstream ss(line);
    ss >> a >> b >> c;

    Thanks at last somebody posted some actual code instead of just saying
    how easy it was. But a couple of things:

    * (It needs #include <sstream>)

    * If I put this in my loop, and type 10 20 30 on the first line, it
    prints 10 20 30; that's fine.

    * But if I type only 40 on the next line, it prints 40 20 30. So if
    there are fewer entries than expected, it will not do '>> b >> c'; those
    values are unchanged from before.

    * It's better behaved as it doesn't try to exhaust the same line over
    again. But if the input is '10.2 11 12', the output is '10 0 999'. (The
    999 is what I've now initialised a,b,c to at the start of each loop.)


    * If fewer than 3 items are present on a line, then it apparently
    hangs, with no explanation, waiting for them on the next line

    Because it's not line-oriented.

    Because it's not line-oriented.

    Because it's not line-oriented.

    Isn't that what I said?


    * Numeric separators within numbers such as "_" and "'" are not
    recognised, and cause an error

    Right. Just how permissive do you think it should be?

    For interactive user input - quite permissive. People are quite likely
    to type in decimal points or do unexpected things. A full treatment is
    hard, but if someone types "100." or 1e2 instead of "100", should that
    be a hanging offence?

    * Numbers which are quoted are not recognised, and cause an error

    Right. 123 is a number; "123", “123”, '123', and «123» are not.

    If you are reading CSV files and such, fields are sometimes enclosed in
    quotes, including numeric fields.

    * When an out-of-range number is entered, it reads i32.max (etc) for
    that number, but also generates an error

    Yes, and?

    That error is the problem.

    * I mentioned error a few times, when that happens, it goes crazy. I
    think the internal pointer is not stepped past it, and it just reads
    zeros, so it never consumes the rest of the line. So in a loop, it
    just prints zeros over and over again without the user entering
    anything.

    It's difficult to respond to that without an example.

    I thought I posted it earlier. Here's the code:

    #include <iostream>

    int main()
    { int a,b,c;
    int x=0;
    do {
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    } while (++x<10);
    }

    And here it is in action; the only input I type in is the '10.2 11 12'
    line, the rest just keeps going, and only stops because I cap the output
    at 10 lines:


    C:\c>a
    Prompt> 10.2 11 12
    10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bart on Fri Sep 24 01:40:27 2021
    int main()
    {

    string line = "GeeksForGeeks is a must try";

    // Vector of string to save tokens
    vector <string> tokens;

    // stringstream class check1
    stringstream check1(line);

    string intermediate;

    // Tokenizing w.r.t. space ' '
    while(getline(check1, intermediate, ' '))
    {
    tokens.push_back(intermediate);
    }

    // Printing the token vector
    for(int i = 0; i < tokens.size(); i++)
    cout << tokens[i] << '\n';
    }

    --
    7-77-777
    \|/
    /|\

    On 2021-09-24, Bart <bc@freeuk.com> wrote:
    On 24/09/2021 00:56, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:

    * It's not line-oriented; the new lines get out of sync with the data
    being read

    Right, it's not designed to be. For example:

    int a, b, c;
    std::cin >> a >> b >> c;
    std::cout << "a=" << a << " b=" << b << " c=" << c << '\n';

    The std::cin line reads integer values, skipping white space (which
    includes newlines) before each. If you just want to skip white space
    other than newlines, there's probably a way to do that.

    If you want line-oriented input, read a line at a time using
    std::getline() and then parse each line. It's not that hard.

    std::string line;
    std::getline(std::cin, line);
    std::stringstream ss(line);
    ss >> a >> b >> c;

    Thanks at last somebody posted some actual code instead of just saying
    how easy it was. But a couple of things:

    * (It needs #include <sstream>)

    * If I put this in my loop, and type 10 20 30 on the first line, it
    prints 10 20 30; that's fine.

    * But if I type only 40 on the next line, it prints 40 20 30. So if
    there are fewer entries than expected, it will not do '>> b >> c'; those values are unchanged from before.

    * It's better behaved as it doesn't try to exhaust the same line over
    again. But if the input is '10.2 11 12', the output is '10 0 999'. (The
    999 is what I've now initialised a,b,c to at the start of each loop.)


    * If fewer than 3 items are present on a line, then it apparently
    hangs, with no explanation, waiting for them on the next line

    Because it's not line-oriented.

    Because it's not line-oriented.

    Because it's not line-oriented.

    Isn't that what I said?


    * Numeric separators within numbers such as "_" and "'" are not
    recognised, and cause an error

    Right. Just how permissive do you think it should be?

    For interactive user input - quite permissive. People are quite likely
    to type in decimal points or do unexpected things. A full treatment is
    hard, but if someone types "100." or 1e2 instead of "100", should that
    be a hanging offence?

    * Numbers which are quoted are not recognised, and cause an error

    Right. 123 is a number; "123", “123”, '123', and «123» are not.

    If you are reading CSV files and such, fields are sometimes enclosed in quotes, including numeric fields.

    * When an out-of-range number is entered, it reads i32.max (etc) for
    that number, but also generates an error

    Yes, and?

    That error is the problem.

    * I mentioned error a few times, when that happens, it goes crazy. I
    think the internal pointer is not stepped past it, and it just reads
    zeros, so it never consumes the rest of the line. So in a loop, it
    just prints zeros over and over again without the user entering
    anything.

    It's difficult to respond to that without an example.

    I thought I posted it earlier. Here's the code:

    #include <iostream>

    int main()
    { int a,b,c;
    int x=0;
    do {
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    } while (++x<10);
    }

    And here it is in action; the only input I type in is the '10.2 11 12'
    line, the rest just keeps going, and only stops because I cap the output
    at 10 lines:


    C:\c>a
    Prompt> 10.2 11 12
    10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0


    --
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to Bart on Thu Sep 23 19:35:34 2021
    Bart <bc@freeuk.com> writes:
    On 24/09/2021 00:56, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:

    * It's not line-oriented; the new lines get out of sync with the data
    being read
    Right, it's not designed to be. For example:
    int a, b, c;
    std::cin >> a >> b >> c;
    std::cout << "a=" << a << " b=" << b << " c=" << c << '\n';
    The std::cin line reads integer values, skipping white space (which
    includes newlines) before each. If you just want to skip white space
    other than newlines, there's probably a way to do that.
    If you want line-oriented input, read a line at a time using
    std::getline() and then parse each line. It's not that hard.
    std::string line;
    std::getline(std::cin, line);
    std::stringstream ss(line);
    ss >> a >> b >> c;

    Thanks at last somebody posted some actual code instead of just saying
    how easy it was. But a couple of things:

    * (It needs #include <sstream>)

    Yes?

    * If I put this in my loop, and type 10 20 30 on the first line, it
    prints 10 20 30; that's fine.

    * But if I type only 40 on the next line, it prints 40 20 30. So if
    there are fewer entries than expected, it will not do '>> b >> c';
    those values are unchanged from before.

    My quick and dirty code sample didn't check for errors. The user didn't provide inputs for those values. What exactly do you expect to happen?

    You can query ss.good(), ss.bad(), ss.fail(), and ss.eof() to see
    whether the input operation succeeded.

    * It's better behaved as it doesn't try to exhaust the same line over
    again. But if the input is '10.2 11 12', the output is '10 0
    999'. (The 999 is what I've now initialised a,b,c to at the start of
    each loop.)


    * If fewer than 3 items are present on a line, then it apparently
    hangs, with no explanation, waiting for them on the next line
    Because it's not line-oriented.

    Because it's not line-oriented.

    Because it's not line-oriented.

    Isn't that what I said?

    My point is that you complained that it's not line-oriented (which is a deliberate design decision) and then complained about the inevitable consequences of the fact that it's not line-oriented.

    * Numeric separators within numbers such as "_" and "'" are not
    recognised, and cause an error
    Right. Just how permissive do you think it should be?

    For interactive user input - quite permissive. People are quite likely
    to type in decimal points or do unexpected things. A full treatment is
    hard, but if someone types "100." or 1e2 instead of "100", should that
    be a hanging offence?

    Hanging offence? Give me a freaking break.

    Numeric input has to define *some* syntax. If you want a different
    syntax, implement it. That includes deciding what an integer should be
    set to if the input is "1.5". If you like, read it into a string and
    try converting that string to whatever you want.

    The default input for numeric input is reasonably simple and
    straightforward.

    * Numbers which are quoted are not recognised, and cause an error
    Right. 123 is a number; "123", “123”, '123', and «123» are not.

    If you are reading CSV files and such, fields are sometimes enclosed
    in quotes, including numeric fields.

    * When an out-of-range number is entered, it reads i32.max (etc) for
    that number, but also generates an error
    Yes, and?

    That error is the problem.

    What?

    You're not suggesting that it should set the value to INT_MAX *and then
    not give any indication that there was a problem*, are you?

    * I mentioned error a few times, when that happens, it goes crazy. I
    think the internal pointer is not stepped past it, and it just reads
    zeros, so it never consumes the rest of the line. So in a loop, it
    just prints zeros over and over again without the user entering
    anything.
    It's difficult to respond to that without an example.

    I thought I posted it earlier. Here's the code:

    #include <iostream>

    int main()
    { int a,b,c;
    int x=0;
    do {
    std::cout << "Prompt> ";
    std::cin >> a >> b >> c;
    std::cout << a << " " << b << " " << c << "\n";
    } while (++x<10);
    }

    And here it is in action; the only input I type in is the '10.2 11 12'
    line, the rest just keeps going, and only stops because I cap the
    output at 10 lines:

    C:\c>a
    Prompt> 10.2 11 12
    10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0
    Prompt> 10 0 0

    The first << operation succeeded, set a to 10, and consumed the
    characters '1' and '0'.

    The second one failed because it was trying to read an integer value and
    saw a '.' character. Try reading an integer again, and it fails again.
    If you instead tried to read a string or a character, it would consume
    the '.' character and whatever follows it.

    If you want to consume and discard incorrect input rather than letting
    it remain in the input stream, you can do that by writing different code.

    If you do something simple like `std::cin >> a >> b >> c`, it doesn't
    give you a way to determine which input operation failed -- but you can
    tell whether they were all successful or not. Sometimes that's good
    enough. If it isn't, write different code.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Paavo Helde on Fri Sep 24 04:37:11 2021
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Preferably whatever the solution is, it shouldn't require the type
    to dynamically construct a string to be printed, and instead the
    type should get an std::ostream (or FILE*, or whatever) that it
    can use to directly write whatever it wants there.

    Why? Is this just because of memory overhead concerns?

    What is this sudden strange attitude of "efficiency doesn't matter"?

    This is C++ we are talking about, not Python, or JavaScript, or PHP,
    or a shell script.

    The very reason why std::ostream uses operator overloading to become
    extensible to custom types is that it allows these custom types to
    output their data in any way they want, using the std::ostream
    object. If the custom type in question is a list of a million
    objects, you don't need to allocate and construct a string
    containing the textual representation of these million objects
    (the length of the string not even necessarily being known in
    advance, requiring multiple reallocations), then the string printed,
    and then the string destroyed... only to immediately doing the
    exact same thing again with another object (or, heck, with the
    same object).

    The operator overloading allows for the object to output one element
    at a time, without the overhead of constructing a gigantic string,
    using multiple reallocations.

    If an alternative to operator overloading is suggested, that alternative shouldn't be worse in terms of performance (and, preferably, not any
    more difficult to use). If someone says "using operator<< for this
    is horrible", then by all means suggest a better alternative, not
    a worse one.

    A "tostring()" method is *most definitely* a worse one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Fri Sep 24 04:38:52 2021
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 08:31, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>>> that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    I'm not forcing anything at all. Custom types can have dedicated
    tostring routines; or use default ones; or have nothing.

    Then how exactly do you add support for your type into the standard
    printing function, if not by forcing your type to have a "tostring"
    method?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Juha Nieminen on Fri Sep 24 07:46:40 2021
    I realy like to_string, to me it is *very usefull* and use it often
    since then.

    --
    7-77-777
    \|/
    ---
    /|\

    On 2021-09-24, Juha Nieminen <nospam@thanks.invalid> wrote:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Preferably whatever the solution is, it shouldn't require the type
    to dynamically construct a string to be printed, and instead the
    type should get an std::ostream (or FILE*, or whatever) that it
    can use to directly write whatever it wants there.

    Why? Is this just because of memory overhead concerns?

    What is this sudden strange attitude of "efficiency doesn't matter"?

    This is C++ we are talking about, not Python, or JavaScript, or PHP,
    or a shell script.

    The very reason why std::ostream uses operator overloading to become extensible to custom types is that it allows these custom types to
    output their data in any way they want, using the std::ostream
    object. If the custom type in question is a list of a million
    objects, you don't need to allocate and construct a string
    containing the textual representation of these million objects
  • From alessandro volturno@21:1/5 to All on Fri Sep 24 09:45:57 2021
    Il 23/09/2021 16:38, Siri Cruise ha scritto:
    In article <shvf4c$ark$3@gioia.aioe.org>,
    alessandro volturno <alessandro.volturno@libero.it> wrote:

    why not to introduce a way to handle rational numbers inside the C++
    standard or better make it a built in type?

    I'm working on an extension for erratic numbers, double precision
    that fills add/subtract loss of signficance with random bits.
    That will form a basis for happy numbers, sad numbers, and angry
    numbers, and more generally, emotional numbers.


    I've never heard about erratic or emotional numbers. Is it a joke or a
    strange application in mathematical field?

    Could you please give me an example of use, so to make understanding easier?

    Thank you

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to alessandro volturno on Fri Sep 24 07:50:49 2021
    I beleive it is joke :P
    But in math you can define ANY set, that follow rules of ALGEBRA :P
    group, semigroup, ring, field....

    --
    7-77-777
    \|/
    ---
    /|\

    On 2021-09-24, alessandro volturno <alessandro.volturno@libero.it> wrote:
    Il 23/09/2021 16:38, Siri Cruise ha scritto:
    In article <shvf4c$ark$3@gioia.aioe.org>,
    alessandro volturno <alessandro.volturno@libero.it> wrote:

    why not to introduce a way to handle rational numbers inside the C++
    standard or better make it a built in type?

    I'm working on an extension for erratic numbers, double precision
    that fills add/subtract loss of signficance with random bits.
    That will form a basis for happy numbers, sad numbers, and angry
    numbers, and more generally, emotional numbers.


    I've never heard about erratic or emotional numbers. Is it a joke or a strange application in mathematical field?

    Could you please give me an example of use, so to make understanding easier?

    Thank you


    --
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Fri Sep 24 09:12:49 2021
    On Thu, 23 Sep 2021 18:31:34 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 17:21, HorseyWorsey@the_stables.com wrote:
    Since a basic line splitter is easy for any half competant programmer and
    anything more complex - ie a parser - is usually tuned for a particular need >> what would be the point? C++ has already had the kitchen sink thrown into it >> because of people like you yet you want even basic stuff done for you?

    This is the paradox: C++ has a lot of hugely complicated but neglects
    the basics.

    And it's just C++ but a lot of current languages, because they have
    their focus elsewhere. (I especially know about Python.)

    An effective basic Print (and Read) needs language support otherwise it >becomes a pain to use.

    The support needed is not significant. My proof-of-concept to add
    automatic printf format codes to a C compiler (so you do "%?" for any
    basic type instead of "%d" etc), was 50 lines of code.

    And no doubt requires the resulting binary to store a boatload of RTTI in order to do that which rather defeats the point of using C which is to create slimline efficient binaries. It could have been done for C++ which has RTTI anyway but stroustrup went with iostream instead.

    concats a vector of strings for you? Maybe you'd be better off using >javascript.

    So. why bother with even std::cout (I still don't know what that
    actually is) or printf? Just have fgetc and fputc.

    As you well know the point of cout is to allow output of complex objects
    which have overloaded << without having to call a converter function first.
    If all you're doing is outputting formatted strings then IMO *printf() is a better choice because its more expressive and compact.

    After all how hard can it be to knock up an int-to-string converter? The

    A universal number to string converter is actually quite complex as it has to deal with IEEE 754 floating point format not to mention negative numbers and formatting.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to alessandro volturno on Fri Sep 24 10:58:14 2021
    On 24/09/2021 09:45, alessandro volturno wrote:
    Il 23/09/2021 16:38, Siri Cruise ha scritto:
    In article <shvf4c$ark$3@gioia.aioe.org>,
      alessandro volturno <alessandro.volturno@libero.it> wrote:

    why not to introduce a way to handle rational numbers inside the C++
    standard or better make it a built in type?

    I'm working on an extension for erratic numbers, double precision
    that fills add/subtract loss of signficance with random bits.
    That will form a basis for happy numbers, sad numbers, and angry
    numbers, and more generally, emotional numbers.


    I've never heard about erratic or emotional numbers. Is it a joke or a strange application in mathematical field?

    Could you please give me an example of use, so to make understanding
    easier?


    It is a joke. There are lucky numbers, perfect numbers, practical
    numbers, fortunate numbers, untouchable numbers, weird numbers, polite
    numbers, and extravagant numbers. But no emotional numbers, that I am
    aware of.

    These are all integer sequences or subsets, and thus don't need any
    special new arithmetic.

    If you want to have other number types that could have C++ classes with operators, you could try Gaussian integers, algebraic numbers,
    constructable numbers, computable numbers, transfinite numbers,
    hyperreals, surreals, etc. Or you can support all kinds of constructed algebraic structures. GF(2⁸) is a nice one to play with, and has
    practical applications (it is the basis for most RAID6 implementations).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Siri Cruise@21:1/5 to David Brown on Fri Sep 24 02:48:10 2021
    In article <sik3v7$2av$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:

    I'm working on an extension for erratic numbers, double precision
    that fills add/subtract loss of signficance with random bits.
    That will form a basis for happy numbers, sad numbers, and angry
    numbers, and more generally, emotional numbers.


    I've never heard about erratic or emotional numbers. Is it a joke or a strange application in mathematical field?

    Could you please give me an example of use, so to make understanding easier?


    It is a joke. There are lucky numbers, perfect numbers, practical
    numbers, fortunate numbers, untouchable numbers, weird numbers, polite numbers, and extravagant numbers. But no emotional numbers, that I am
    aware of.

    I think erratic numbers would be a good lesson. People have the
    illusion that losing almost all bits in a subtraction does not
    result in the loss of precision. The CDC Star-100 had something
    similar and it really peeved off customers. They didm't want to
    ne reminded that all their displays of real number fractions were
    meaningless. Introducing random bits instead of zeros when
    normalising differences would visibly change output on each run
    for numerically unstable code.

    --
    :-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
    'I desire mercy, not sacrifice.' /|\ Discordia: not just a religion but also a parody. This post / \
    I am an Andrea Doria sockpuppet. insults Islam. Mohammed

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Juha Nieminen on Fri Sep 24 21:45:57 2021
    On 20/09/2021 17:20, Juha Nieminen wrote:
    Scott Lurndal <scott@slp53.sl.home> wrote:
    In other words, you can achieve this:

    MyClass obj;
    std::cout << "Value = " << obj << "\n";

    fprintf(stdout, "Value = %s\n" obj.to_string());

    I don't really know how exactly you expect that to be possible in all cases. The returned const char* has to point somewhere. To something that will outlive the to_string() function itself, but will, if necessary, be destroyed after use (because in many cases you will need to create a dynamically allocated string in order to contain the textual representation of the value of the object you are trying to print).

    The whole to_string() concept also falls apart if you are printing in a template. int.to_string() anyone?

    --
    Ian.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Bart on Fri Sep 24 21:37:40 2021
    On 23/09/2021 00:45, Bart wrote:
    On 22/09/2021 12:13, Ian Collins wrote:
    On 22/09/2021 22:26, Bart wrote:

    OK, let's try it. Here's a program that writes 1 million lines of the
    same 3 variables:

        #include <iostream>
        #include <fstream>
        using namespace std;

        int main () {
            ofstream myfile;
            long long int a = 0x7FFFFFFFFFFFFFFF;
            double b = 3.14159265359;
            const char* c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

            myfile.open ("output");
            for (int i=0; i<1000000; ++i) {
                myfile << a << " " << b << " " << c << "\n";
            }
            myfile.close();
            return 0;
        }

    On my machine, that took 4 seconds.

    This will take roughly the time it takes to perform the file writing
    (0.4S on my machine).  The time spend formatting the output is
    inconsequential in comparison.


    But you don't know that? On my machine, timing went from 4.3 seconds to
    5.3 seconds if I changed the output file from "output" to "nul"
    (Windows' version of a null device, not a very effective one!).

    I don't know how to isolate the file i/o from the conversion in C++. If
    I switch to C *printf functions, then going from fprintf to sprintf,
    changes the timing from 4.3 seconds to 0.8 seconds; so more than 80% is writing via the file system.

    I wanted to determine the overheads of using "<<" on each print item, especially as there are 3 extra arguments of " ", " " and "\n".

    These latter overheads are irrelevant when using the format string of sprintf.

    The question posed was whether turning into individual print items into
    a string object, before sending that string to the output, was a
    significant overhead.

    The answer is in comparison with doing the actual output, no.

    I showed my /dynamic/ code wasn't significantly slower than C++
    (actually it was faster) despite doing those conversions, plus a whole
    bunch of other overheads that C++ will not have.

    What you showed is the implementation you are using is really really
    (10x slower than my unimpressive laptop) slow!

    -
    Ian.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Fri Sep 24 12:17:25 2021
    24.09.2021 07:37 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Preferably whatever the solution is, it shouldn't require the type
    to dynamically construct a string to be printed, and instead the
    type should get an std::ostream (or FILE*, or whatever) that it
    can use to directly write whatever it wants there.

    Why? Is this just because of memory overhead concerns?

    What is this sudden strange attitude of "efficiency doesn't matter"?

    This is C++ we are talking about, not Python, or JavaScript, or PHP,
    or a shell script.


    It appears we are both concerned about efficiency. Alas, we have
    drastically different opinions about where the inefficiencies lure.
    Fortunately programming is strongly connected to reality, unlike some
    other areas of human activity, so one can check the reality to see
    what's really happening.

    Here is a test program measuring the two different approaches to
    streaming: (A) sending 100 million ints to std::ostream separately, and
    (B) formatting them first into a huge std::string, then sending that to std::ostream in one go. My results are here:

    MSVC++ 2019 x64 Release (/O2 optimization):
    Traditional streaming: 28561 ms
    to_string() streaming: 2663 ms
    to_string() is 10.7251 times faster than traditional streaming.

    To be honest, g++ 8.3 on Linux (or more exactly, libstdc++) seems to be
    much better with iostreams, but still to_string() beats iostreams:

    $ g++ -Wall -O2 test5.cpp -std=c++17
    $ ./a.out
    Traditional streaming: 4268 ms
    to_string() streaming: 2592 ms
    to_string() is 1.6466 times faster than traditional streaming.

    Source code:

    #include <iostream>
    #include <string>
    #include <sstream>
    #include <vector>
    #include <numeric>
    #include <charconv>
    #include <chrono>
    #include <cstdint>

    class A {
    public:
    A();

    // traditional operator<<
    friend std::ostream& operator<<(std::ostream& os, const A& a);

    // tostring() operator
    std::string to_string() const;

    private:
    std::vector<int> data;
    };

    A::A() {
    // Initialize data to something
    data.resize(100000000);
    std::iota(data.begin(), data.end(), 0);
    }

    std::ostream& operator<<(std::ostream& os, const A& a) {
    for (auto& x: a.data) {
    os << x << ' ';
    }
    return os;
    }

    std::string A::to_string() const {
    const size_t k = 64;
    char buffer[k];
    std::string result;
    for (auto x: data) {
    auto q = std::to_chars(buffer+0, buffer+k, x, 10).ptr;
    *q++ = ' ';
    result.append(buffer, q-buffer);
    }
    return result;
    }

    using sclock = std::chrono::steady_clock;

    std::int64_t ms(sclock::duration lapse) {
    return std::chrono::duration_cast<std::chrono::milliseconds>(lapse).count();
    }

    int main() {

    std::ostringstream sink1, sink2;
    A a;

    // traditional streaming
    sclock::time_point start1 = sclock::now();
    sink1 << a;
    sclock::time_point finish1 = sclock::now();
    std::cout << "Traditional streaming: " << ms(finish1-start1) << "
    ms\n";

    // tostring()
    sclock::time_point start2 = sclock::now();
    sink2 << a.to_string();
    sclock::time_point finish2 = sclock::now();
    std::cout << "to_string() streaming: " << ms(finish2-start2) << "
    ms\n";

    double ratio = double(ms(finish1-start1))/ms(finish2-start2);
    std::cout << "to_string() is " << ratio << " times " <<
    (ratio>1.0 ? "faster" : "slower") << " than traditional
    streaming.\n";

    // Make use of the results to ensure these were not optimized away.
    return int(sink1.str().size()-sink2.str().size());
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bart on Fri Sep 24 10:19:48 2021
    Efficincy in IO is not issue as IO itself is SLOW. Also ALGORITHM is
    WHAT COUNTS, this is how HUMANS can always BEAT compilers.

    --
    7-77-777
    \|/
    /|\
    On 2021-09-24, Bart <bc@freeuk.com> wrote:
    On 24/09/2021 05:38, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 08:31, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>>>>> that pays little to no attention to the efficiency of the resulting >>>>>> program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    I'm not forcing anything at all. Custom types can have dedicated
    tostring routines; or use default ones; or have nothing.

    Then how exactly do you add support for your type into the standard
    printing function, if not by forcing your type to have a "tostring"
    method?


    I've lost track of what you're asking.

    But if there is really a need to convert of value of some abstract type
    T into a sequenct of characters, then how else can be it done other than providing support functions which does that conversion?

    If your quibble about having to do the whole conversion into some intermediate string before starting to output characters from that new string, rather than do it a character at a time?

    I'm sure, it's possible to that that conversion incrementally, to
    provide that conversion in the form of a generator function, which
    yields the next character (not sure what C++ capabilities are here).

    Or to provide a callback function to the translation function to tell it
    what to do with each new generated character. Although both of sound a
    lot less efficient to me.

    Probably 99% of all print items would have an intermediate string less
    than 100 characters along, so that a simple fixed buffer would suffice. That's a better idea than sending a character at time to some stream-processing function (like fputc).



    --
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Fri Sep 24 11:15:32 2021
    On 24/09/2021 05:38, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 08:31, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    It seems to me that you come from a world of programming language design >>>>> that pays little to no attention to the efficiency of the resulting
    program.

    Not at all. I used to write compilers and applications for 8-bit
    computers; I know how to be efficient!

    If that were the case, then you would abhor the idea of forcing every
    custom type to have a "tostring" function which is the only way to
    add support to the standard printing function for your type.

    I'm not forcing anything at all. Custom types can have dedicated
    tostring routines; or use default ones; or have nothing.

    Then how exactly do you add support for your type into the standard
    printing function, if not by forcing your type to have a "tostring"
    method?


    I've lost track of what you're asking.

    But if there is really a need to convert of value of some abstract type
    T into a sequenct of characters, then how else can be it done other than providing support functions which does that conversion?

    If your quibble about having to do the whole conversion into some
    intermediate string before starting to output characters from that new
    string, rather than do it a character at a time?

    I'm sure, it's possible to that that conversion incrementally, to
    provide that conversion in the form of a generator function, which
    yields the next character (not sure what C++ capabilities are here).

    Or to provide a callback function to the translation function to tell it
    what to do with each new generated character. Although both of sound a
    lot less efficient to me.

    Probably 99% of all print items would have an intermediate string less
    than 100 characters along, so that a simple fixed buffer would suffice.
    That's a better idea than sending a character at time to some
    stream-processing function (like fputc).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to HorseyWorsey@the_stables.com on Fri Sep 24 12:10:01 2021
    On 24/09/2021 10:12, HorseyWorsey@the_stables.com wrote:
    On Thu, 23 Sep 2021 18:31:34 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 17:21, HorseyWorsey@the_stables.com wrote:
    Since a basic line splitter is easy for any half competant programmer and >>> anything more complex - ie a parser - is usually tuned for a particular need
    what would be the point? C++ has already had the kitchen sink thrown into it
    because of people like you yet you want even basic stuff done for you?

    This is the paradox: C++ has a lot of hugely complicated but neglects
    the basics.

    And it's just C++ but a lot of current languages, because they have
    their focus elsewhere. (I especially know about Python.)

    An effective basic Print (and Read) needs language support otherwise it
    becomes a pain to use.

    The support needed is not significant. My proof-of-concept to add
    automatic printf format codes to a C compiler (so you do "%?" for any
    basic type instead of "%d" etc), was 50 lines of code.

    And no doubt requires the resulting binary to store a boatload of RTTI in order
    to do that which rather defeats the point of using C which is to create slimline efficient binaries.

    Huh? This tweak to C means that when somebody writes:

    printf("%? %?", i, f);

    it converts the string to "%d %f". There is zero impact on any binaries.

    It could have been done for C++ which has RTTI
    anyway but stroustrup went with iostream instead.

    concats a vector of strings for you? Maybe you'd be better off using
    javascript.

    So. why bother with even std::cout (I still don't know what that
    actually is) or printf? Just have fgetc and fputc.

    As you well know the point of cout is to allow output of complex objects which have overloaded << without having to call a converter function first.

    Actually no I don't. I'm still not entirely clear how << works, other
    than it is 100% unintuitive.

    Virtually all output I want to do is of standard types. It would just be
    nice to output A and B by writing:

    ... A, B ...

    rather than:

    ... A << " " << B ...

    I'm just surprised you don't have to type:

    ... A std::<< " " std::<< B ...


    If all you're doing is outputting formatted strings then IMO *printf() is a better choice because its more expressive and compact.

    Yeah. It takes a lot to suddenly make printf seem much better!

    After all how hard can it be to knock up an int-to-string converter? The

    A universal number to string converter is actually quite complex as it has to deal with IEEE 754 floating point format not to mention negative numbers and formatting.

    Negative numbers aren't that difficult actually...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bart on Fri Sep 24 11:23:52 2021
    For example of type safe print take a look at Bjarne's BOOK.

    --
    7-77-777
    \|/
    ---
    /|\
    On 2021-09-24, Bart <bc@freeuk.com> wrote:
    On 24/09/2021 10:12, HorseyWorsey@the_stables.com wrote:
    On Thu, 23 Sep 2021 18:31:34 +0100
    Bart <bc@freeuk.com> wrote:
    On 23/09/2021 17:21, HorseyWorsey@the_stables.com wrote:
    Since a basic line splitter is easy for any half competant programmer and >>>> anything more complex - ie a parser - is usually tuned for a particular need
    what would be the point? C++ has already had the kitchen sink thrown into it
    because of people like you yet you want even basic stuff done for you?

    This is the paradox: C++ has a lot of hugely complicated but neglects
    the basics.

    And it's just C++ but a lot of current languages, because they have
    their focus elsewhere. (I especially know about Python.)

    An effective basic Print (and Read) needs language support otherwise it
    becomes a pain to use.

    The support needed is not significant. My proof-of-concept to add
    automatic printf format cod
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Fri Sep 24 15:19:59 2021
    On Fri, 24 Sep 2021 12:10:01 +0100
    Bart <bc@freeuk.com> wrote:
    On 24/09/2021 10:12, HorseyWorsey@the_stables.com wrote:
    And no doubt requires the resulting binary to store a boatload of RTTI in >order
    to do that which rather defeats the point of using C which is to create
    slimline efficient binaries.

    Huh? This tweak to C means that when somebody writes:

    printf("%? %?", i, f);

    it converts the string to "%d %f". There is zero impact on any binaries.

    And what happens if 'i' is a char? Do you want %c, %d or %u? What if its a pointer? Do you want %p, %x, %X, %lu etc?

    As you well know the point of cout is to allow output of complex objects
    which have overloaded << without having to call a converter function first.

    Actually no I don't. I'm still not entirely clear how << works, other
    than it is 100% unintuitive.

    So you're complaining about basic C++ functionality you don't even understand. Got it.

    Virtually all output I want to do is of standard types. It would just be
    nice to output A and B by writing:

    ... A, B ...

    rather than:

    ... A << " " << B ...

    Whats special about a space? What if someone wants 2 spaces as a seperator
    or maybe a tab or comma? C++ is a professional language, its not BASIC for kiddies to output simple tabular results. Plus a comma already has syntactic meaning in C & C++.

    A universal number to string converter is actually quite complex as it has to

    deal with IEEE 754 floating point format not to mention negative numbers and >> formatting.

    Negative numbers aren't that difficult actually...

    So long as you remember chars,ints etc are 2's complement whereas floating point uses a sign bit.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From danielaparker@gmail.com@21:1/5 to Branimir Maksimovic on Fri Sep 24 08:59:44 2021
    On Friday, September 24, 2021 at 3:46:49 AM UTC-4, Branimir Maksimovic wrote:
    I realy like to_string, to me it is *very usefull* and use it often
    since then.

    It's inherently inefficient though, particularly as it's frequently used to append a
    small piece of text to a larger string, repeated many times. Thus are many copies created.

    Daniel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From danielaparker@gmail.com@21:1/5 to Keith Thompson on Fri Sep 24 09:07:55 2021
    On Thursday, September 23, 2021 at 10:35:44 PM UTC-4, Keith Thompson wrote:

    If you do something simple like `std::cin >> a >> b >> c`, it doesn't
    give you a way to determine which input operation failed -- but you can
    tell whether they were all successful or not. Sometimes that's good
    enough. If it isn't, write different code.

    I see `std::cout << a` in real code, but I don't see `std::cin >> a >> b >> c` in
    anything other than toy examples. If we have something, we can send that
    to `std::cout` without worrying about it, but input invariably has to be validated.

    Daniel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From danielaparker@gmail.com@21:1/5 to Bart on Fri Sep 24 09:21:36 2021
    On Thursday, September 23, 2021 at 8:59:02 PM UTC-4, Bart wrote:
    If you are reading CSV files and such, fields are sometimes enclosed in quotes, including numeric fields.

    I don't think anybody would attempt to read a CSV file with
    `<istream> >> field1 >> field2 >> field3` notation. But of course
    line oriented input wouldn't be of much help here either,
    in general.

    As to a number enclosed in quotes, I think a typical CSV parser
    would by default interpret that as string, but perhaps provide
    an option to interpret a quoted value in a specified column
    as a number.

    Daniel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to HorseyWorsey@the_stables.com on Fri Sep 24 17:25:24 2021
    On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
    On Fri, 24 Sep 2021 12:10:01 +0100
    Bart <bc@freeuk.com> wrote:
    On 24/09/2021 10:12, HorseyWorsey@the_stables.com wrote:
    And no doubt requires the resulting binary to store a boatload of RTTI in >> order
    to do that which rather defeats the point of using C which is to create
    slimline efficient binaries.

    Huh? This tweak to C means that when somebody writes:

    printf("%? %?", i, f);

    it converts the string to "%d %f". There is zero impact on any binaries.

    And what happens if 'i' is a char? Do you want %c, %d or %u? What if its a pointer? Do you want %p, %x, %X, %lu etc?

    In C, char types count as integers. My scheme only takes care of the
    /types/ of the expression (so that you don't to choose from %d %lld
    PRIi64 etc). If you want a different textual representation, that's when
    you need to be explicit.

    My experimental feature generates one of %d %u %lld %llu %f %s %p.

    %s is used for char* types, and %p for other pointers.

    With this program:

    int main(void) {
    int a=10;
    unsigned int b=20;
    long long int c=30;
    unsigned long long int d=40;
    double e=50.1;
    char* f="sixty";
    void* g=&a;
    void(*h)(void)=main;

    printf("%? %? %? %? %? %? %? %?\n", a, b, c, d, e, f, g, h);
    }

    the format string is changed to:

    "%d %u %lld %llu %f %s %p %p\n"

    The output is:

    10 20 30 40 50.100000 sixty 000000000080FF48 0000000000401000

    At this point, with this enhancement, C's printf (I know it's in C++
    too) looks better than:

    std::cout << a << " " << b << " " << c << " " << d << " " << e << " "
    << f << " " << g << " " << h << "\n";

    But remember that in my kiddies' language, it's still just:

    println a, b, c, d, e, f, g, h

    And still totally unprofessional, of course. (Maybe a professional
    wouldn't be able to claim so many hours' pay if the language was too easy!)


    So you're complaining about basic C++ functionality you don't even understand.
    Got it.

    Would understanding it make me happier about typing out all that <<
    nonsense above?

    Virtually all output I want to do is of standard types. It would just be
    nice to output A and B by writing:

    ... A, B ...

    rather than:

    ... A << " " << B ...

    Whats special about a space?

    Have a look at the English written in these posts; what's the common
    separator between words? Yep, it's a single space. Handy for stopping alphanumeric entities from running into each other.

    Because of course, when you generate human readable text from a
    programming language, the most sensible default is to end up with:

    12345678910

    instead of:

    1 2 3 4 5 6 7 8 9 10

    What if someone wants 2 spaces as a seperator
    or maybe a tab or comma? C++ is a professional language, its not BASIC for kiddies to output simple tabular results.

    So 'professional' equals 'unnecessarily complicated and unintuitive'?

    I think everyone's got that about C++!

    What if someone wants 2 spaces as a seperator
    or maybe a tab or comma?

    You make the most common, most useful and convenient requirement the
    default. Anything different, then that's when you have special code.
    Such as using formatted printing.

    In my book that's better than HAVING to write '<< " " <<' 99 times out
    of hundred, instead of nothing.

    Plus a comma already has syntactic
    meaning in C & C++.

    In programming languages it is very commonly used to separate the
    elements of a list. So why not the list of expressions in a print
    statement (or whatever std::cout << is classed as).

    Negative numbers aren't that difficult actually...

    So long as you remember chars,ints etc are 2's complement whereas floating point uses a sign bit.

    Yeah, thanks.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Fri Sep 24 22:49:22 2021
    24.09.2021 18:59 daniel...@gmail.com kirjutas:
    On Friday, September 24, 2021 at 3:46:49 AM UTC-4, Branimir Maksimovic wrote:
    I realy like to_string, to me it is *very usefull* and use it often
    since then.

    It's inherently inefficient though, particularly as it's frequently used to append a
    small piece of text to a larger string, repeated many times. Thus are many copies created.

    Memory copy is very cheap nowadays. And std::string::append() grows the
    buffer in the same way as std::vector::push_back, i.e. the complexity of growing a large string piecewise is amortized constant.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to daniel...@gmail.com on Sat Sep 25 00:55:11 2021
    I don't care about such efficency, as then I would use mine natural
    language, assembler.

    --
    7-77-777
    \|/
    ---
    /|\
    On 2021-09-24, daniel...@gmail.com <danielaparker@gmail.com> wrote:
    On Friday, September 24, 2021 at 3:46:49 AM UTC-4, Branimir Maksimovic wrote:
    I realy like to_string, to me it is *very usefull* and use it often
    since then.

    It's inherently inefficient though, particularly as it's frequently used to append a
    small piece of text to a larger string, repeated many times. Thus are many copies created.

    Daniel


    --
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Sat Sep 25 09:27:27 2021
    On Fri, 24 Sep 2021 17:25:24 +0100
    Bart <bc@freeuk.com> wrote:
    On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
    println a, b, c, d, e, f, g, h

    And still totally unprofessional, of course. (Maybe a professional
    wouldn't be able to claim so many hours' pay if the language was too easy!)

    If someone needs a nice easy scripting language they'll use Python. And they do.

    So you're complaining about basic C++ functionality you don't even >understand.
    Got it.

    Would understanding it make me happier about typing out all that <<
    nonsense above?

    It might help.

    Whats special about a space?

    Have a look at the English written in these posts; what's the common >separator between words? Yep, it's a single space. Handy for stopping >alphanumeric entities from running into each other.

    So? Even your sentence above contains "," "?" and " " so your reasoning
    fails immediately.

    Because of course, when you generate human readable text from a
    programming language, the most sensible default is to end up with:

    12345678910

    instead of:

    1 2 3 4 5 6 7 8 9 10

    You seem to be fixated on simple output spacing. Its really not a Big Deal
    for most people. How hard is printf("%d %d %d %d\n".... to write?

    What if someone wants 2 spaces as a seperator
    or maybe a tab or comma? C++ is a professional language, its not BASIC for >> kiddies to output simple tabular results.

    So 'professional' equals 'unnecessarily complicated and unintuitive'?

    No, it equals syntax able to do complex tasks easily. BASIC makes it easy to print stuff out but I wouldn't use it to write Fintech software in!

    What if someone wants 2 spaces as a seperator
    or maybe a tab or comma?

    You make the most common, most useful and convenient requirement the

    Where did you get the idea its the most common? I'm afraid thats BS. We're talking program output, not human writing.

    In programming languages it is very commonly used to separate the
    elements of a list. So why not the list of expressions in a print
    statement (or whatever std::cout << is classed as).

    face <- palm. Honestly, why don't you go play in comp.lang.basic

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to HorseyWorsey@the_stables.com on Sat Sep 25 11:07:16 2021
    On 25/09/2021 10:27, HorseyWorsey@the_stables.com wrote:
    On Fri, 24 Sep 2021 17:25:24 +0100
    Bart <bc@freeuk.com> wrote:
    On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
    println a, b, c, d, e, f, g, h

    And still totally unprofessional, of course. (Maybe a professional
    wouldn't be able to claim so many hours' pay if the language was too easy!)

    If someone needs a nice easy scripting language they'll use Python. And they do.

    I write both kinds of languages, systems ones and scripting ones. Both
    have the same easy print facilities. Except the scripting one can print
    more complex objects too.



    So 'professional' equals 'unnecessarily complicated and unintuitive'?

    No, it equals syntax able to do complex tasks easily. BASIC makes it easy to print stuff out but I wouldn't use it to write Fintech software in!

    ANY language can make it easier to print stuff out!

    Believe me, it's of the simplest parts of implementing a language. And
    it's what needs to be done early as it plays a part in testing
    everything else.

    But some languages are pig-headed enough to make it difficult and to
    keep it that way in the mistaken belief that making things too easy is
    in some way 'unprofessional', and something to be look down upon.

    So, make a rod for your own back, then.

    You make the most common, most useful and convenient requirement the

    Where did you get the idea its the most common? I'm afraid thats BS. We're talking program output, not human writing.

    Program output as text? The intention is usually to keep it human
    readable. Each machine readable text will need separators.

    (Except in the specific case of generating fixed field database files,
    but those are unlikely to use hard-coded lists of print items, which is
    the print feature we're talking about.)

    At least 90% of the print statements I write (not 90% of the ones in a
    finished program) are temporary ones to do with debugging.


    In programming languages it is very commonly used to separate the
    elements of a list. So why not the list of expressions in a print
    statement (or whatever std::cout << is classed as).

    face <- palm. Honestly, why don't you go play in comp.lang.basic

    /I/ should do the face-palm, given your completely irrational insistence
    that:

    A << " " << B

    is miles better than:

    A, " ", B

    /and/ better than simply:

    A, B

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Sat Sep 25 10:14:37 2021
    On Sat, 25 Sep 2021 11:07:16 +0100
    Bart <bc@freeuk.com> wrote:
    On 25/09/2021 10:27, HorseyWorsey@the_stables.com wrote:
    Where did you get the idea its the most common? I'm afraid thats BS. We're >> talking program output, not human writing.

    Program output as text? The intention is usually to keep it human
    readable. Each machine readable text will need separators.

    And just how many C++ programs these days do you think return their output
    to the console assuming human readable output is even their raison d'etre?
    C++ is usually used for huge backend systems that run in the background and
    any readable output will probably be formatted data written to a log that
    won't be simply words seperated by a space.

    In programming languages it is very commonly used to separate the
    elements of a list. So why not the list of expressions in a print
    statement (or whatever std::cout << is classed as).

    face <- palm. Honestly, why don't you go play in comp.lang.basic

    /I/ should do the face-palm, given your completely irrational insistence >that:

    A << " " << B

    is miles better than:

    A, " ", B

    Where did I say that? Comma is already overloaded in C/C++, it doesn't need
    yet another meaning.

    /and/ better than simply:

    A, B

    Because the use case of that for C++ is virtually non existent except in debugging.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to HorseyWorsey@the_stables.com on Sat Sep 25 11:53:39 2021
    On 25/09/2021 11:14, HorseyWorsey@the_stables.com wrote:
    On Sat, 25 Sep 2021 11:07:16 +0100
    Bart <bc@freeuk.com> wrote:
    On 25/09/2021 10:27, HorseyWorsey@the_stables.com wrote:
    Where did you get the idea its the most common? I'm afraid thats BS. We're >>> talking program output, not human writing.

    Program output as text? The intention is usually to keep it human
    readable. Each machine readable text will need separators.

    And just how many C++ programs these days do you think return their output
    to the console assuming human readable output is even their raison d'etre? C++ is usually used for huge backend systems that run in the background and any readable output will probably be formatted data written to a log that won't be simply words seperated by a space.

    According to Wikipedia, C++ is a general purpose language.

    My own applications were mostly GUI ones, with no attached console, and
    the languages used still had Print.

    Print is used also to send output to files. And could be used to display
    text within a GUI window.




    In programming languages it is very commonly used to separate the
    elements of a list. So why not the list of expressions in a print
    statement (or whatever std::cout << is classed as).

    face <- palm. Honestly, why don't you go play in comp.lang.basic

    /I/ should do the face-palm, given your completely irrational insistence
    that:

    A << " " << B

    is miles better than:

    A, " ", B

    Where did I say that? Comma is already overloaded in C/C++, it doesn't need yet another meaning.

    But, what on earth does that mean? Overloaded for what purpose? Last
    time I looked, comma was still used to separate the arguments of a function.

    Are you hung up on the fact that because "<<" is an operator (a very
    strange one), then any replacement for that whole god-forsaken std::cout
    scheme must be implemented as some kind of operator too?

    Forget about the operator idea, it's just a list!

    (I was going to post examples of << code, with versions that use commas
    to show much easier on the eye it would be.

    But then I accidentally caught glimpses of full-on C++ code, and
    realised trying to fix this small corner of the language is completely
    futile. The whole thing is just irretrievably broken.)


    /and/ better than simply:

    A, B

    Because the use case of that for C++ is virtually non existent except in debugging.

    So quite an important use-case.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Sat Sep 25 11:23:27 2021
    On Sat, 25 Sep 2021 11:53:39 +0100
    Bart <bc@freeuk.com> wrote:
    On 25/09/2021 11:14, HorseyWorsey@the_stables.com wrote:
    On Sat, 25 Sep 2021 11:07:16 +0100
    Bart <bc@freeuk.com> wrote:
    On 25/09/2021 10:27, HorseyWorsey@the_stables.com wrote:
    Where did you get the idea its the most common? I'm afraid thats BS. We're >>>> talking program output, not human writing.

    Program output as text? The intention is usually to keep it human
    readable. Each machine readable text will need separators.

    And just how many C++ programs these days do you think return their output >> to the console assuming human readable output is even their raison d'etre? >> C++ is usually used for huge backend systems that run in the background and >> any readable output will probably be formatted data written to a log that
    won't be simply words seperated by a space.

    According to Wikipedia, C++ is a general purpose language.

    Most languages are technically general purpose but most of them also
    specialise in certain areas. C/C++ is mainly used in large applications, systems and low level programming and places where speed matters. They're
    not generally used to write quick and dirty console apps though you can use them for that.

    Where did I say that? Comma is already overloaded in C/C++, it doesn't need >> yet another meaning.

    But, what on earth does that mean? Overloaded for what purpose? Last
    time I looked, comma was still used to separate the arguments of a function.

    Arguments of a function, variable definitions, class initialisers and also
    to seperate function calls and assignments (though not built-in keywords for some reason) instead of using curly brackets which not many people know eg:

    while(i < 10) printf("i = %d\n",i),++i,puts("---");

    Are you hung up on the fact that because "<<" is an operator (a very
    strange one), then any replacement for that whole god-forsaken std::cout >scheme must be implemented as some kind of operator too?

    No. Personally I think overloading << was a stupid idea, strstroup should have invented a turbo charged version of printf() instead like your %? instead with a formatter that called a default class method to output itself.

    Because the use case of that for C++ is virtually non existent except in
    debugging.

    So quite an important use-case.

    Only if you still using print statements to debug instead of using a debugger.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Sat Sep 25 15:37:58 2021
    25.09.2021 12:27 HorseyWorsey@the_stables.com kirjutas:
    On Fri, 24 Sep 2021 17:25:24 +0100
    Bart <bc@freeuk.com> wrote:
    On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
    println a, b, c, d, e, f, g, h

    And still totally unprofessional, of course. (Maybe a professional
    wouldn't be able to claim so many hours' pay if the language was too easy!)

    If someone needs a nice easy scripting language they'll use Python. And they do.

    In Python they apparently thought printing was too simple, so in Python
    3 they now require parens:

    Python2: print 1, 2, 3

    Python3: print(1, 2, 3)

    BTW, in C++ one can easily define python3 style print:

    #include <iostream>

    inline void print() {
    std::cout << "\n";
    }

    template<typename T, typename... Args>
    void print(T x, Args... args) {
    std::cout << x << ' ';
    print(args...);
    }

    int main() {
    print(1, 2, 3);
    }

    Note to Bart: the ellipses above are actual C++11 syntax, not some
    pseudocode. This is a running demo program. In your own C++ code just
    put these print() definitions in sme common header file, and you can use python3 style print syntax for all built-in and other types which
    support stream<<.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to HorseyWorsey@the_stables.com on Sat Sep 25 12:34:53 2021
    On 2021-09-25, HorseyWorsey@the_stables.com <HorseyWorsey@the_stables.com> wrote:
    On Fri, 24 Sep 2021 17:25:24 +0100

    If someone needs a nice easy scripting language they'll use Python. And they do.


    OK. Agreed. But what about ONES that think using SCRIPTING LANGUAGE,
    is Bellow HONOR?


    --
    7-77-777
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Sat Sep 25 16:15:16 2021
    24.09.2021 12:45 Ian Collins kirjutas:
    On 20/09/2021 17:20, Juha Nieminen wrote:
    Scott Lurndal <scott@slp53.sl.home> wrote:
    In other words, you can achieve this:

      MyClass obj;
      std::cout << "Value = " << obj << "\n";

       fprintf(stdout, "Value = %s\n" obj.to_string());

    I don't really know how exactly you expect that to be possible in all
    cases.
    The returned const char* has to point somewhere. To something that will
    outlive the to_string() function itself, but will, if necessary, be
    destroyed
    after use (because in many cases you will need to create a dynamically
    allocated string in order to contain the textual representation of the
    value
    of the object you are trying to print).

    The whole to_string() concept also falls apart if you are printing in a template.  int.to_string() anyone?

    Adding a stream adaptor for a class having only a to_string() is trivial:

    std::ostream& operator<<(std::ostream& os, const A& a) {
    os << a.to_string();
    return os;
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Paavo Helde on Sat Sep 25 15:46:27 2021
    On 25/09/2021 13:37, Paavo Helde wrote:
    25.09.2021 12:27 HorseyWorsey@the_stables.com kirjutas:
    On Fri, 24 Sep 2021 17:25:24 +0100
    Bart <bc@freeuk.com> wrote:
    On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
       println a, b, c, d, e, f, g, h

    And still totally unprofessional, of course. (Maybe a professional
    wouldn't be able to claim so many hours' pay if the language was too
    easy!)

    If someone needs a nice easy scripting language they'll use Python.
    And they
    do.

    In Python they apparently thought printing was too simple, so in Python
    3 they now require parens:

    Python2:  print 1, 2, 3

    Python3: print(1, 2, 3)

    That was one giant PITA. A lot of downloadable Python at one time was
    Python2. So you had to convert all the uses of 'print'.

    The change was to turn 'print' from a statement into a function, because
    it was 'better'.


    BTW, in C++ one can easily define python3 style print:

    #include <iostream>

    inline void print() {
        std::cout << "\n";
    }

    template<typename T, typename... Args>
    void print(T x, Args... args) {
        std::cout << x << ' ';
        print(args...);
    }

    int main() {
        print(1, 2, 3);
    }

    Note to Bart: the ellipses above are actual C++11 syntax, not some pseudocode. This is a running demo program. In your own C++ code just
    put these print() definitions in sme common header file, and you can use python3 style print syntax for all built-in and other types which
    support stream<<.

    This is good. It doesn't handle all the possibilities of properly
    built-in Print, although print/println variations are easy. But it will
    do for quick debug prints where layout doesn't matter.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From HorseyWorsey@the_stables.com@21:1/5 to Bart on Sat Sep 25 15:19:43 2021
    On Sat, 25 Sep 2021 15:46:27 +0100
    Bart <bc@freeuk.com> wrote:
    On 25/09/2021 13:37, Paavo Helde wrote:
    25.09.2021 12:27 HorseyWorsey@the_stables.com kirjutas:
    On Fri, 24 Sep 2021 17:25:24 +0100
    Bart <bc@freeuk.com> wrote:
    On 24/09/2021 16:19, HorseyWorsey@the_stables.com wrote:
       println a, b, c, d, e, f, g, h

    And still totally unprofessional, of course. (Maybe a professional
    wouldn't be able to claim so many hours' pay if the language was too
    easy!)

    If someone needs a nice easy scripting language they'll use Python.
    And they
    do.

    In Python they apparently thought printing was too simple, so in Python
    3 they now require parens:

    Python2:  print 1, 2, 3

    Python3: print(1, 2, 3)

    That was one giant PITA. A lot of downloadable Python at one time was >Python2. So you had to convert all the uses of 'print'.

    Removing python2 syntax from python3 wasn't one of Guido's smartest moves.
    No reason it couldn't have been left in and deprecated.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bart on Sat Sep 25 17:16:45 2021
    On 2021-09-25, Bart <bc@freeuk.com> wrote:
    Python2:  print 1, 2, 3

    Python3: print(1, 2, 3)

    That was one giant PITA. A lot of downloadable Python at one time was Python2. So you had to convert all the uses of 'print'.

    The change was to turn 'print' from a statement into a function, because
    it was 'better'.

    This is why I don't like student code and libraries to use. They don't
    care about API and code stability...


    --

    7-77-777
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Mon Sep 27 05:34:36 2021
    Bart <bc@freeuk.com> wrote:
    Then how exactly do you add support for your type into the standard
    printing function, if not by forcing your type to have a "tostring"
    method?


    I've lost track of what you're asking.

    But if there is really a need to convert of value of some abstract type
    T into a sequenct of characters, then how else can be it done other than providing support functions which does that conversion?

    By providing a way for the custom type to directly output its contents
    to the output (in whichever way it chooses), rather than forcing it
    to create a dynamically allocated string in memory (which then gets
    immediately destroyed afterwards).

    In C++, when you overload operator<< for std::ostream, the custom type
    does not need to construct any strings with its contents. It can output directly to that std::ostream object. (The speed of std::ostream itself
    is not the relevant thing here.)

    I am not asking to replicate the way in which C++ solved that problem.
    I am asking what's your own suggestion for a better alternative (that
    does not involve forcing types to create dynamically allocated strings).

    Probably 99% of all print items would have an intermediate string less
    than 100 characters along, so that a simple fixed buffer would suffice.

    Would that be a fixed buffer per object, or per type?

    If it's a fixed buffer per object, then if you have a million objects
    that would be 100 million bytes in buffers in total.

    If it's per type, then that's not very thread-safe. Nor is it completely
    safe even in single-threaded mode, if the references to the returned
    strings can outlive their retrieval (so that you can have several
    references to the strings returned by several objects... which would
    all in fact refer to the same fixed buffer, which contents would only
    be that of the last object called, making the other references invalid,
    with no warning.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Paavo Helde on Mon Sep 27 05:36:45 2021
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Adding a stream adaptor for a class having only a to_string() is trivial:

    std::ostream& operator<<(std::ostream& os, const A& a) {
    os << a.to_string();
    return os;
    }

    While you are at it, why not just output the contents of that A object directly, rather than making it construct a string?

    At this point that to_string() method is completely superfluous.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Paavo Helde on Mon Sep 27 05:25:33 2021
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    It appears we are both concerned about efficiency. Alas, we have
    drastically different opinions about where the inefficiencies lure. Fortunately programming is strongly connected to reality, unlike some
    other areas of human activity, so one can check the reality to see
    what's really happening.

    Here is a test program measuring the two different approaches to
    streaming: (A) sending 100 million ints to std::ostream separately, and
    (B) formatting them first into a huge std::string, then sending that to std::ostream in one go. My results are here:

    You are constructing a string with the contents of the data in both cases.
    This is not what I'm talking about. It's quite obvious (and I have never
    had any illusion otherwise) that std::ostringstream is extraordinarily inefficient. Obviously using other methods for constructing a string
    are going to be a million times faster. (I myself pretty much never
    use std::ostringstream if I can avoid it.)

    But I am not talking about constructing a string from the content of
    the data. In fact, I'm talking about the exact opposite: *Avoiding* constructing a string into memory with the data.

    How do you add support to the standard output functions for custom
    types without requiring those custom types to create strings from
    their data, and being able to directly output the data?

    Many people responding to this challenge are arguing against it
    by comparing the speed of std::ostream to the speed of some other
    ways of outputting data. This is not relevant to my question.
    Just substitute std::ostream with something more efficient.
    The question remains: How do you add native support for custom
    types to that output method, without requiring the custom types
    to create dynamically allocated strings in memory, and instead
    being able to directly use that output method to print their
    contents (in whichever way they choose)?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Mon Sep 27 11:37:12 2021
    27.09.2021 08:25 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    It appears we are both concerned about efficiency. Alas, we have
    drastically different opinions about where the inefficiencies lure.
    Fortunately programming is strongly connected to reality, unlike some
    other areas of human activity, so one can check the reality to see
    what's really happening.

    Here is a test program measuring the two different approaches to
    streaming: (A) sending 100 million ints to std::ostream separately, and
    (B) formatting them first into a huge std::string, then sending that to
    std::ostream in one go. My results are here:

    I used std::ostringstream only to exclude disk access from timings.

    You are constructing a string with the contents of the data in both cases.

    No. In one case I construct a string with data indeed, but with
    to_string() approach I construct this string *twice*! And it's still
    faster than the first method!

    This is not what I'm talking about. It's quite obvious (and I have never
    had any illusion otherwise) that std::ostringstream is extraordinarily inefficient. Obviously using other methods for constructing a string
    are going to be a million times faster. (I myself pretty much never
    use std::ostringstream if I can avoid it.)

    It's the general std::ostream interface which is slow. One can easily
    switch to ofstream in my example if this feels better, this won't change
    the timings much. Here are the results for std::ofstream:

    MSVC++ 2019 x64 Release build:

    Traditional streaming: 32367 ms
    to_string() streaming: 3979 ms
    to_string() is 8.13446 times faster than traditional streaming.

    g++ 8.3 on Linux:
    $ g++ -Wall -O2 test5.cpp -std=c++17
    $ ./a.out
    Traditional streaming: 3451 ms
    to_string() streaming: 1771 ms
    to_string() is 1.94862 times faster than traditional streaming.

    Source code below.



    But I am not talking about constructing a string from the content of
    the data. In fact, I'm talking about the exact opposite: *Avoiding* constructing a string into memory with the data.

    Why? In my practice this is a major usage scenario.


    How do you add support to the standard output functions for custom
    types without requiring those custom types to create strings from
    their data, and being able to directly output the data?

    Why? What's wrong with creating strings?


    Just substitute std::ostream with something more efficient.

    I just did. It's called to_string().

    The question remains: How do you add native support for custom
    types to that output method, without requiring the custom types
    to create dynamically allocated strings in memory, and instead
    being able to directly use that output method to print their
    contents (in whichever way they choose)?

    Why? A lot of data transfer mechanisms use internal memory buffers,
    which often are dynamically allocated.


    Test source code without std::ostringstream:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <numeric>
    #include <charconv>
    #include <chrono>
    #include <cstdint>
    #include <fstream>

    class A {
    public:
    A();

    // traditional operator<<
    friend std::ostream& operator<<(std::ostream& os, const A& a);

    // tostring() operator
    std::string to_string() const;

    private:
    std::vector<int> data;
    };

    A::A() {
    // Initialize data to something
    data.resize(100000000);
    std::iota(data.begin(), data.end(), 0);
    }

    std::ostream& operator<<(std::ostream& os, const A& a) {
    for (auto& x: a.data) {
    os << x << ' ';
    }
    return os;
    }

    std::string A::to_string() const {
    const size_t k = 64;
    char buffer[k];
    std::string result;
    for (auto x: data) {
    auto q = std::to_chars(buffer, buffer+k, x).ptr;
    *q++ = ' ';
    result.append(buffer, q-buffer);
    }
    return result;
    }

    using sclock = std::chrono::steady_clock;

    std::int64_t ms(sclock::duration lapse) {
    return std::chrono::duration_cast<std::chrono::milliseconds>(lapse).count();
    }

    int main() {

    std::ofstream sink1("sink1.txt"), sink2("sink2.txt");
    A a;

    // traditional streaming
    sclock::time_point start1 = sclock::now();
    sink1 << a;
    sclock::time_point finish1 = sclock::now();
    std::cout << "Traditional streaming: " << ms(finish1-start1) << "
    ms\n";

    // tostring()
    sclock::time_point start2 = sclock::now();
    sink2 << a.to_string();
    sclock::time_point finish2 = sclock::now();
    std::cout << "to_string() streaming: " << ms(finish2-start2) << "
    ms\n";

    double ratio = double(ms(finish1-start1))/ms(finish2-start2);
    std::cout << "to_string() is " << ratio << " times " <<
    (ratio>1.0 ? "faster" : "slower") << " than traditional
    streaming.\n";

    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Mon Sep 27 11:19:51 2021
    27.09.2021 08:36 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Adding a stream adaptor for a class having only a to_string() is trivial:

    std::ostream& operator<<(std::ostream& os, const A& a) {
    os << a.to_string();
    return os;
    }

    While you are at it, why not just output the contents of that A object directly, rather than making it construct a string?


    Because of speed. I just showed elsethread that serializing a large
    object into an in-memory string can be up to 10x faster than writing it
    into a std::ostream piece-by-piece.

    Also, because of better modularity and easier usage. A string is
    basically just a raw memory buffer which is easy to transport and use.
    Streams are more complicated.

    Say, I want to write my large data structure into a file in AWS cloud. AmazonStreamingWebServiceRequest::SetBody() takes a pointer to an input
    stream and reads data from it later when I call S3Object::PutObject().

    Say, for my large data structure I have proper streaming support which
    writes the data into an std::ostream. So now what? How do I connect this
    output stream to an input stream used by the AWS library so that they
    would "flow together"? Sure it can be done, but seems not so easy.
    Threads or coroutines come to mind.

    The easiest way is to dump the data into a temporary file, then let the
    AWS library to read it. We do not need a file on disk, so this ought to
    be an in-memory file. And guess what is the fastest way to create an
    in-memory file? Answer: serializing the data into a raw memory buffer
    such as std::string. IOW the dreaded to_string() method.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Paavo Helde on Mon Sep 27 21:27:09 2021
    On 27/09/2021 21:19, Paavo Helde wrote:
    27.09.2021 08:36 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Adding a stream adaptor for a class having only a to_string() is trivial: >>>
    std::ostream& operator<<(std::ostream& os, const A& a) {
    os << a.to_string();
    return os;
    }

    While you are at it, why not just output the contents of that A object
    directly, rather than making it construct a string?


    Because of speed. I just showed elsethread that serializing a large
    object into an in-memory string can be up to 10x faster than writing it
    into a std::ostream piece-by-piece.

    Also, because of better modularity and easier usage. A string is
    basically just a raw memory buffer which is easy to transport and use. Streams are more complicated.

    Say, I want to write my large data structure into a file in AWS cloud. AmazonStreamingWebServiceRequest::SetBody() takes a pointer to an input stream and reads data from it later when I call S3Object::PutObject().

    Say, for my large data structure I have proper streaming support which
    writes the data into an std::ostream. So now what? How do I connect this output stream to an input stream used by the AWS library so that they
    would "flow together"? Sure it can be done, but seems not so easy.
    Threads or coroutines come to mind.

    The easiest way is to dump the data into a temporary file, then let the
    AWS library to read it. We do not need a file on disk, so this ought to
    be an in-memory file. And guess what is the fastest way to create an in-memory file? Answer: serializing the data into a raw memory buffer
    such as std::string. IOW the dreaded to_string() method.

    You can string it into an in memory straeam buffer.

    I can't see how adding to a string can be any faster and you have to
    convert each field to a string representation which is what streams do
    for you.

    --
    Ian.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Mon Sep 27 15:49:37 2021
    27.09.2021 11:27 Ian Collins kirjutas:
    On 27/09/2021 21:19, Paavo Helde wrote:
    27.09.2021 08:36 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Adding a stream adaptor for a class having only a to_string() is
    trivial:

    std::ostream& operator<<(std::ostream& os, const A& a) {
          os << a.to_string();
          return os;
    }

    While you are at it, why not just output the contents of that A object
    directly, rather than making it construct a string?


    Because of speed. I just showed elsethread that serializing a large
    object into an in-memory string can be up to 10x faster than writing it
    into a std::ostream piece-by-piece.

    Also, because of better modularity and easier usage. A string is
    basically just a raw memory buffer which is easy to transport and use.
    Streams are more complicated.

    Say, I want to write my large data structure into a file in AWS cloud.
    AmazonStreamingWebServiceRequest::SetBody() takes a pointer to an input
    stream and reads data from it later when I call S3Object::PutObject().

    Say, for my large data structure I have proper streaming support which
    writes the data into an std::ostream. So now what? How do I connect this
    output stream to an input stream used by the AWS library so that they
    would "flow together"? Sure it can be done, but seems not so easy.
    Threads or coroutines come to mind.

    The easiest way is to dump the data into a temporary file, then let the
    AWS library to read it. We do not need a file on disk, so this ought to
    be an in-memory file. And guess what is the fastest way to create an
    in-memory file? Answer: serializing the data into a raw memory buffer
    such as std::string. IOW the dreaded to_string() method.

    You can string it into an in memory straeam buffer.

    This is the slow part.

    I can't see how adding to a string can be any faster

    See my demo programs and timings elsethread.

    and you have to
    convert each field to a string representation which is what streams do
    for you.

    Yes, and that's the slow part. When adding to a string I can choose what conversion function to use. There is a reason why std::to_chars() was
    added to C++.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Mon Sep 27 23:51:10 2021
    Am 25.09.21 um 14:37 schrieb Paavo Helde:
    In Python they apparently thought printing was too simple, so in Python
    3 they now require parens:

    Python2:  print 1, 2, 3

    Python3: print(1, 2, 3)


    It wasn't "too simple", whatever that means, but in Python2, "print" was
    a keyword and specially treated in the interpreter, whereas the core
    developers thought that it should not be set apart from regular
    functions, because there is nothing that "print" can do that any other
    old function could not do. Variable number of arguments of varying type
    is possible for any Python function.

    Christian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Christian Gollwitzer on Mon Sep 27 23:41:17 2021
    On 27/09/2021 22:51, Christian Gollwitzer wrote:
    Am 25.09.21 um 14:37 schrieb Paavo Helde:
    In Python they apparently thought printing was too simple, so in
    Python 3 they now require parens:

    Python2:  print 1, 2, 3

    Python3: print(1, 2, 3)


    It wasn't "too simple", whatever that means, but in Python2, "print" was
    a keyword and specially treated in the interpreter, whereas the core developers thought that it should not be set apart from regular
    functions, because there is nothing that "print" can do that any other
    old function could not do.

    Other than provide a more ergonomic syntax.

    Some languages have features that allow 'if' and 'for' statements to be implemented as functions. But just because you can, should you?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Paavo Helde on Tue Sep 28 04:53:28 2021
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    27.09.2021 08:36 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Adding a stream adaptor for a class having only a to_string() is trivial: >>>
    std::ostream& operator<<(std::ostream& os, const A& a) {
    os << a.to_string();
    return os;
    }

    While you are at it, why not just output the contents of that A object
    directly, rather than making it construct a string?

    Because of speed. I just showed elsethread that serializing a large
    object into an in-memory string can be up to 10x faster than writing it
    into a std::ostream piece-by-piece.

    Suppose that the 'a' object above consists of 2 large strings, and you
    want to write them to 'os' concatenated.

    Are you seriously telling me that it's more efficient to first create a
    new dynamically allocated string, write the two strings from 'a' there,
    write that string to 'os' and then destroy that temporary string, than
    it would be to just write the two strings directly to 'os' one after
    another?

    If that were the case, then it logically follows that if you do that again
    with the resulting concatenated temporary string, by creating a second temporary string with it, it would be even faster! And if you do it a
    third time, it would be even faster still!

    It seems extraordinarily silly to have the std::ostream object right
    there to be used, and *still* construct a useless temporary string just
    to write it there.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Paavo Helde on Tue Sep 28 04:49:06 2021
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    But I am not talking about constructing a string from the content of
    the data. In fact, I'm talking about the exact opposite: *Avoiding*
    constructing a string into memory with the data.

    Why? In my practice this is a major usage scenario.

    Because if I want to write something eg. into a file, I don't want to
    first to have to create a dynamically allocated string, just to write
    the contents of that string to the file and then destroy that string.
    I want to write directly to the file.

    How do you add support to the standard output functions for custom
    types without requiring those custom types to create strings from
    their data, and being able to directly output the data?

    Why? What's wrong with creating strings?

    Because it's useless and inefficient, fills caches with useless
    garbage and causes memory fragmentation. In the worst cases it consumes
    a lot of RAM for no good reason.

    Consider what happens if what you want to write to the file is, for
    example, three large strings, which you want to write to the file
    concatenated. What possible benefit would there be in first creating
    a new string that's a concatenation of those three strings, and then
    write that string, when you could just as well simply write the three
    strings directly to the file?

    I would ask you the reverse: Why dou you want to create a string first,
    if you could just write to the file directly?

    Just substitute std::ostream with something more efficient.

    I just did. It's called to_string().

    to_string() does not write to a file.

    The question remains: How do you add native support for custom
    types to that output method, without requiring the custom types
    to create dynamically allocated strings in memory, and instead
    being able to directly use that output method to print their
    contents (in whichever way they choose)?

    Why? A lot of data transfer mechanisms use internal memory buffers,
    which often are dynamically allocated.

    Because if I am, for example, writing a bunch of strings to a file,
    I don't want to first concatenate those strings to a new string in
    memory before writing it. I want to write the strings directly to
    the file without that useless middle step, which is just a waste
    of time and memory.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Tue Sep 28 10:16:00 2021
    On 28/09/2021 05:53, Juha Nieminen wrote:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    27.09.2021 08:36 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Adding a stream adaptor for a class having only a to_string() is trivial: >>>>
    std::ostream& operator<<(std::ostream& os, const A& a) {
    os << a.to_string();
    return os;
    }

    While you are at it, why not just output the contents of that A object
    directly, rather than making it construct a string?

    Because of speed. I just showed elsethread that serializing a large
    object into an in-memory string can be up to 10x faster than writing it
    into a std::ostream piece-by-piece.

    Suppose that the 'a' object above consists of 2 large strings, and you
    want to write them to 'os' concatenated.

    Are you seriously telling me that it's more efficient to first create a
    new dynamically allocated string, write the two strings from 'a' there,
    write that string to 'os' and then destroy that temporary string, than
    it would be to just write the two strings directly to 'os' one after
    another?


    Bizarrely, yes it could be faster!

    Because, for most objects that are not already strings, assembling into
    a local temporary string, then dumping the whole string at once, might
    be faster than calling some external character-at-a-time routine.

    So even if your specific example of large strings is slower, overall
    with a mix of objects, there might be a net benefit.

    If the strings are large enough that having duplicates will impact on
    memory resources, then that might be a consideration. But it might never happen.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Tue Sep 28 13:23:38 2021
    28.09.2021 07:53 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    27.09.2021 08:36 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Adding a stream adaptor for a class having only a to_string() is trivial: >>>>
    std::ostream& operator<<(std::ostream& os, const A& a) {
    os << a.to_string();
    return os;
    }

    While you are at it, why not just output the contents of that A object
    directly, rather than making it construct a string?

    Because of speed. I just showed elsethread that serializing a large
    object into an in-memory string can be up to 10x faster than writing it
    into a std::ostream piece-by-piece.

    Suppose that the 'a' object above consists of 2 large strings, and you
    want to write them to 'os' concatenated.

    This is another task. If you already have data formatted into strings,
    then of course these can be written directly to a file. But for that you
    don't need a C++ std::ostream interface, you can write directly into the
    file descriptor, or C++ streambuf(). If there are only a handful of
    strings, then you can of course write them to the stream as well, the
    overhead is insignificant.

    What I'm talking is about outstreaming millions of small items
    one-by-one, like advocated by ostream<< enthusiasts: just define a
    proper operator<< overload and write everything in the ostream,
    recursively, each number separately.

    It's this formatting interface of C++ iostreams which is slow. With
    MSVC++ I just stepped though an operator<<(std::ofstream&, int), this
    involved at least 2 virtual function calls, 4 locking/unlocking of
    current locale, and consulting TLS about the number of uncaught
    exceptions, not to speak about tens of non-virtual function calls (which hopefully get optimized away) and twiddling with the stream state. This
    is all 100% unnecessary overhead for formatting an int in C locale. It
    won't matter for a single debug printout line, but it will matter when exporting a 100,000 line table into a CSV file.

    Are you seriously telling me that it's more efficient to first create a
    new dynamically allocated string, write the two strings from 'a' there,
    write that string to 'os' and then destroy that temporary string, than
    it would be to just write the two strings directly to 'os' one after
    another?

    No, of course not.

    [Rest of strawman arguments snipped]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Paavo Helde on Wed Sep 29 10:34:03 2021
    On 28/09/2021 23:23, Paavo Helde wrote:
    28.09.2021 07:53 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    27.09.2021 08:36 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Adding a stream adaptor for a class having only a to_string() is trivial: >>>>>
    std::ostream& operator<<(std::ostream& os, const A& a) {
    os << a.to_string();
    return os;
    }

    While you are at it, why not just output the contents of that A object >>>> directly, rather than making it construct a string?

    Because of speed. I just showed elsethread that serializing a large
    object into an in-memory string can be up to 10x faster than writing it
    into a std::ostream piece-by-piece.

    Suppose that the 'a' object above consists of 2 large strings, and you
    want to write them to 'os' concatenated.

    This is another task. If you already have data formatted into strings,
    then of course these can be written directly to a file. But for that you don't need a C++ std::ostream interface, you can write directly into the
    file descriptor, or C++ streambuf(). If there are only a handful of
    strings, then you can of course write them to the stream as well, the overhead is insignificant.

    What I'm talking is about outstreaming millions of small items
    one-by-one, like advocated by ostream<< enthusiasts: just define a
    proper operator<< overload and write everything in the ostream,
    recursively, each number separately.

    It's this formatting interface of C++ iostreams which is slow. With
    MSVC++ I just stepped though an operator<<(std::ofstream&, int), this involved at least 2 virtual function calls, 4 locking/unlocking of
    current locale, and consulting TLS about the number of uncaught
    exceptions, not to speak about tens of non-virtual function calls (which hopefully get optimized away) and twiddling with the stream state. This
    is all 100% unnecessary overhead for formatting an int in C locale. It
    won't matter for a single debug printout line, but it will matter when exporting a 100,000 line table into a CSV file.

    Ah, right so it's the overhead of locale based formatting that's the
    real problem here. Presumably this would be the same for C printing
    functions as well. I can see why std::to_chars would have an advantage
    here.

    I haven't seen such an high overhead on Unix/Linux, I wonder of the
    Windows way of doing things is more burdensome? An example wit timings
    would be useful!

    --
    Ian.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Wed Sep 29 12:18:08 2021
    29.09.2021 00:34 Ian Collins kirjutas:
    On 28/09/2021 23:23, Paavo Helde wrote:
    It's this formatting interface of C++ iostreams which is slow. With
    MSVC++ I just stepped though an operator<<(std::ofstream&, int), this
    involved at least 2 virtual function calls, 4 locking/unlocking of
    current locale, and consulting TLS about the number of uncaught
    exceptions, not to speak about tens of non-virtual function calls (which
    hopefully get optimized away) and twiddling with the stream state. This
    is all 100% unnecessary overhead for formatting an int in C locale. It
    won't matter for a single debug printout line, but it will matter when
    exporting a 100,000 line table into a CSV file.

    Ah, right so it's the overhead of locale based formatting that's the
    real problem here.  Presumably this would be the same for C printing functions as well.  I can see why std::to_chars would have an advantage here.

    Right. Actually it is not so important where the output is collected,
    it's the formatting step what is the bottleneck. It is even possible to
    use the standard stream for collecting the output, for those who repel
    the idea of a string buffer. The trick is to ignore the stream part and
    only use the streambuf part, see the test program below.

    I haven't seen such an high overhead on Unix/Linux, I wonder of the
    Windows way of doing things is more burdensome?  An example wit timings would be useful!

    Here you are. These timings are for 50 million ints. You can try the
    demo program out by yourself with your favorite compiler and hardware.
    On my Windows the "traditional" streaming is ca 10 times slower than alternatives, on my Linux the difference is smaller, just ca 2 times.

    MSVC++ 2019 on Windows, x64 Release build:

    Traditional streaming: 16479 ms
    Streaming with std::to_chars() directly into streambuf: 1612 ms
    Collecting the content in a string buffer of 418 MB: 1126 ms
    Writing the string buffer of 418 MB into a disk file: 796 ms


    g++ 8.3 on Linux:
    $ g++ -Wall -O3 -std=c++17 test6.cpp
    $ ./a.out
    Traditional streaming: 2080 ms
    Streaming with std::to_chars() directly into streambuf: 903 ms
    Collecting the content in a string buffer of 418 MB: 655 ms
    Writing the string buffer of 418 MB into a disk file: 146 ms

    Source code:
    #include <iostream>
    #include <string>
    #include <vector>
    #include <numeric>
    #include <charconv>
    #include <chrono>
    #include <cstdint>
    #include <fstream>

    class A {
    public:
    A();

    // traditional operator<<
    friend std::ostream& operator<<(std::ostream& os, const A& a);

    // tostring() operator
    std::string to_string() const;

    // Select whether operator<< uses stream or streambuf interface.
    bool useStreamBufOnly = false;

    private:
    std::vector<int> data;
    };

    A::A() {
    // Initialize data to 50 million ints.
    data.resize(50000000);
    std::iota(data.begin(), data.end(), 0);
    }

    std::ostream& operator<<(std::ostream& os, const A& a) {
    if (a.useStreamBufOnly) {
    // Ignore stream, use streambuf only.
    auto streamBuf = os.rdbuf();
    const size_t k = 64;
    char buff[k];
    for (auto& x: a.data) {
    auto q = std::to_chars(buff, buff+k, x).ptr;
    *q++ = ' ';
    streamBuf->sputn(buff, q-buff);
    }
    } else {
    // Traditional stream output
    for (auto& x: a.data) {
    os << x << ' ';
    }
    }
    return os;
    }

    std::string A::to_string() const {
    const size_t k = 64;
    char buffer[k];
    std::string result;
    for (auto x: data) {
    auto q = std::to_chars(buffer, buffer+k, x).ptr;
    *q++ = ' ';
    result.append(buffer, q-buffer);
    }
    return result;
    }

    using sclock = std::chrono::steady_clock;

    std::int64_t ms(sclock::duration lapse) {
    return std::chrono::duration_cast<std::chrono::milliseconds>(lapse).count();
    }

    int main() {

    A a;

    std::ofstream sink1("sink1.txt"), sink2("sink2.txt"),
    sink3("sink3.txt");

    // traditional streaming
    a.useStreamBufOnly = false;
    sclock::time_point start1 = sclock::now();
    sink1 << a;
    sink1.close();
    sclock::time_point finish1 = sclock::now();
    std::cout << "Traditional streaming: " << ms(finish1-start1) << "
    ms\n";

    // streaming with to_chars() and streambuf
    a.useStreamBufOnly = true;
    sclock::time_point start2 = sclock::now();
    sink2 << a;
    sink2.close();
    sclock::time_point finish2 = sclock::now();
    std::cout << "Streaming with std::to_chars() directly into
    streambuf: " << ms(finish2-start2) << " ms\n";

    // to_string()
    sclock::time_point start3 = sclock::now();
    std::string s3 = a.to_string();
    sclock::time_point finish3 = sclock::now();
    std::cout << "Collecting the content in a string buffer of " << s3.length()/(1024*1024) << " MB: " << ms(finish3-start3) << " ms\n";

    sclock::time_point start4 = sclock::now();
    sink3.rdbuf()->sputn(s3.data(), s3.length());
    sink3.close();
    sclock::time_point finish4 = sclock::now();
    std::cout << "Writing the string buffer of " <<
    s3.length()/(1024*1024) << " MB into a disk file: " <<
    ms(finish4-start4) << " ms\n";

    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ian Collins@21:1/5 to Paavo Helde on Wed Sep 29 22:46:16 2021
    On 29/09/2021 22:18, Paavo Helde wrote:
    29.09.2021 00:34 Ian Collins kirjutas:
    On 28/09/2021 23:23, Paavo Helde wrote:
    It's this formatting interface of C++ iostreams which is slow. With
    MSVC++ I just stepped though an operator<<(std::ofstream&, int), this
    involved at least 2 virtual function calls, 4 locking/unlocking of
    current locale, and consulting TLS about the number of uncaught
    exceptions, not to speak about tens of non-virtual function calls (which >>> hopefully get optimized away) and twiddling with the stream state. This
    is all 100% unnecessary overhead for formatting an int in C locale. It
    won't matter for a single debug printout line, but it will matter when
    exporting a 100,000 line table into a CSV file.

    Ah, right so it's the overhead of locale based formatting that's the
    real problem here.  Presumably this would be the same for C printing
    functions as well.  I can see why std::to_chars would have an advantage
    here.

    Right. Actually it is not so important where the output is collected,
    it's the formatting step what is the bottleneck. It is even possible to
    use the standard stream for collecting the output, for those who repel
    the idea of a string buffer. The trick is to ignore the stream part and
    only use the streambuf part, see the test program below.

    I haven't seen such an high overhead on Unix/Linux, I wonder of the
    Windows way of doing things is more burdensome?  An example wit timings
    would be useful!

    Here you are. These timings are for 50 million ints. You can try the
    demo program out by yourself with your favorite compiler and hardware.
    On my Windows the "traditional" streaming is ca 10 times slower than alternatives, on my Linux the difference is smaller, just ca 2 times.

    MSVC++ 2019 on Windows, x64 Release build:

    Traditional streaming: 16479 ms
    Streaming with std::to_chars() directly into streambuf: 1612 ms
    Collecting the content in a string buffer of 418 MB: 1126 ms
    Writing the string buffer of 418 MB into a disk file: 796 ms


    g++ 8.3 on Linux:
    $ g++ -Wall -O3 -std=c++17 test6.cpp
    $ ./a.out
    Traditional streaming: 2080 ms
    Streaming with std::to_chars() directly into streambuf: 903 ms
    Collecting the content in a string buffer of 418 MB: 655 ms
    Writing the string buffer of 418 MB into a disk file: 146 ms

    Interesting, thanks for posting. It's a similar ratio on my machine. I
    can see that the Windows way of doing things is definitely more
    burdensome.

    It also gives me another argument for upgrading our embedded target
    compiler to one which supports C++17!

    <snip>

    --
    Ian.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Wed Sep 29 13:07:00 2021
    29.09.2021 12:46 Ian Collins kirjutas:

    It also gives me another argument for upgrading our embedded target
    compiler to one which supports C++17!

    Beware that some g++ versions do not support std::to_chars() with floating-point, even when otherwise supporting C++17.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Wed Sep 29 12:10:44 2021
    Bart <bc@freeuk.com> wrote:
    Are you seriously telling me that it's more efficient to first create a
    new dynamically allocated string, write the two strings from 'a' there,
    write that string to 'os' and then destroy that temporary string, than
    it would be to just write the two strings directly to 'os' one after
    another?

    Bizarrely, yes it could be faster!

    Because, for most objects that are not already strings, assembling into
    a local temporary string, then dumping the whole string at once, might
    be faster than calling some external character-at-a-time routine.

    I did not ask whether outputting one concatenated string is faster than outputting two strings one character at a time.

    I asked if concatenating the two strings and then outputting the result
    is faster than just outputting the two strings.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Paavo Helde on Wed Sep 29 12:16:20 2021
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Suppose that the 'a' object above consists of 2 large strings, and you
    want to write them to 'os' concatenated.

    This is another task.

    No, it isn't.

    I just said "custom type" which wants to output its contents. I did not
    specify what the content exactly is. You seem to be assuming that I was
    talking about, for example, a data container containing numbers.

    If you already have data formatted into strings,
    then of course these can be written directly to a file. But for that you don't need a C++ std::ostream interface, you can write directly into the
    file descriptor, or C++ streambuf().

    No you can't, if you don't have a reference to the ostream object (or FILE pointer).

    Sure, you could just call a member function of the class giving it
    that object, but then you cannot use that in generic code. You would
    merely be trying to work your way around not overloading operator<<,
    which does exactly that thing, in a way that allows it to be used in
    generic code.

    So my question is, once again: If overloading operator<< for this
    is such a horrible thing, what exactly is your alternative?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Juha Nieminen on Wed Sep 29 14:34:35 2021
    On 29/09/2021 13:10, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    Are you seriously telling me that it's more efficient to first create a
    new dynamically allocated string, write the two strings from 'a' there,
    write that string to 'os' and then destroy that temporary string, than
    it would be to just write the two strings directly to 'os' one after
    another?

    Bizarrely, yes it could be faster!

    Because, for most objects that are not already strings, assembling into
    a local temporary string, then dumping the whole string at once, might
    be faster than calling some external character-at-a-time routine.

    I did not ask whether outputting one concatenated string is faster than outputting two strings one character at a time.

    I asked if concatenating the two strings and then outputting the result
    is faster than just outputting the two strings.

    I was talking about the net effect when outputting lots of different
    objects, since the gains can offset the losses.

    But, OK, the answer to your specific question: I guess it depends. On
    the overheads of calling the o/p routine, and the efficiency of string concatenation.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Bart on Wed Sep 29 15:54:02 2021
    On 29/09/2021 14:34, Bart wrote:
    On 29/09/2021 13:10, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    Are you seriously telling me that it's more efficient to first create a >>>> new dynamically allocated string, write the two strings from 'a' there, >>>> write that string to 'os' and then destroy that temporary string, than >>>> it would be to just write the two strings directly to 'os' one after
    another?

    Bizarrely, yes it could be faster!

    Because, for most objects that are not already strings, assembling into
    a local temporary string, then dumping the whole string at once, might
    be faster than calling some external character-at-a-time routine.

    I did not ask whether outputting one concatenated string is faster than
    outputting two strings one character at a time.

    I asked if concatenating the two strings and then outputting the result
    is faster than just outputting the two strings.

    I was talking about the net effect when outputting lots of different
    objects, since the gains can offset the losses.

    But, OK, the answer to your specific question: I guess it depends. On
    the overheads of calling the o/p routine, and the efficiency of string concatenation.


    Here's a random observation using script code. A and B are both
    100-character strings:

    to 1 million do
    println A,,B
    od

    The above prints 1M lines of A and B (the ",," means no gap), so outputs
    2M strings of 100 chars each.

    The following combines A+B into one string each time, and writes 1M
    strings of 200 chars each:

    to 1 million do
    println A + B
    od

    The first took around 4.5 seconds, the second about 4.3 seconds. (Run on Windows and directing output to a file.)

    If I instead printed 10,000 strings of 10,000 chars each, the results
    were much closer (approx 3.5 second for both).

    I didn't observe a slow-down due to having to 'pointlessly' create a
    temporary string object and then tear it down again.

    So in answer to this:

    I asked if concatenating the two strings and then outputting the result
    is faster than just outputting the two strings.

    Yes, it can be. At least, you shouldn't just dismiss the possibility.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Wed Sep 29 20:15:42 2021
    29.09.2021 15:16 Juha Nieminen kirjutas:
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    Suppose that the 'a' object above consists of 2 large strings, and you
    want to write them to 'os' concatenated.

    This is another task.

    No, it isn't.

    Yes it is. Outputting two strings is another task than formatting *and* outputting millions of numbers.


    I just said "custom type" which wants to output its contents. I did not specify what the content exactly is. You seem to be assuming that I was talking about, for example, a data container containing numbers.

    Yes, that's the scenario which was in my mind as this is the problematic
    one.


    If you already have data formatted into strings,
    then of course these can be written directly to a file. But for that you
    don't need a C++ std::ostream interface, you can write directly into the
    file descriptor, or C++ streambuf().

    No you can't, if you don't have a reference to the ostream object (or FILE pointer).

    In that case you can concatenate them and return as a string to the
    point where they need to be used (not necessarily a file).

    Sure, you could just call a member function of the class giving it
    that object, but then you cannot use that in generic code. You would
    merely be trying to work your way around not overloading operator<<,
    which does exactly that thing, in a way that allows it to be used in
    generic code.

    So my question is, once again: If overloading operator<< for this
    is such a horrible thing, what exactly is your alternative?

    I have nothing against operator<<, it just tends to be slow if
    implemented as taught in the books. I believe it was you who stressed
    the importance of efficiency in C++.

    Here are two examples of operator<< which are potentially faster:

    std::ostream& operator<<(std::ostream& os, const A& a) {
    std::string buff = a.to_string();
    os.rdbuf()->sputn(buff.data(), buff.length());
    }

    std::ostream& operator<<(std::ostream& os, const A& a) {
    auto streamBuf = os.rdbuf();
    const size_t k = 64;
    char buff[k];
    for (auto x: a.data) {
    auto q = std::to_chars(buff, buff+k, x).ptr;
    *q++ = ' ';
    streamBuf->sputn(buff, q-buff);
    }
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Paavo Helde on Thu Sep 30 04:46:45 2021
    Paavo Helde <myfirstname@osa.pri.ee> wrote:
    I have nothing against operator<<, it just tends to be slow if
    implemented as taught in the books. I believe it was you who stressed
    the importance of efficiency in C++.

    The thing is that with overloading operator<< (or any other similar solution where you have direct access to the stream object) you can choose how to implement the writing.

    In a scenario where every custom type is forced to implement some kind of "tostring()" function for output you have no choice, even if outputting
    in some other way would be more efficient, convenient, or even
    necessary.

    In fact, it would be better if that "tostring()" would instead be
    something like "write_to_stream()" which gets the stream object.
    That way the custom type can choose how it will write to that stream.
    If it wants to create a string first, it can. But it can also choose
    to do something else.

    Which, incidentally, is exactly what overloading operator<< does.

    My original objection was to the objection that using << is bad,
    and there are better ways. I was asking what exactly is this "better
    way". And I do not consider everything having a "tostring()" method
    to be better.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to All on Sat Oct 2 22:57:50 2021
    29.09.2021 12:46 Ian Collins kirjutas:
    On 29/09/2021 22:18, Paavo Helde wrote:
    Here you are. These timings are for 50 million ints. You can try the
    demo program out by yourself with your favorite compiler and hardware.
    On my Windows the "traditional" streaming is ca 10 times slower than
    alternatives, on my Linux the difference is smaller, just ca 2 times.

    MSVC++ 2019 on Windows, x64 Release build:

    Traditional streaming: 16479 ms
    Streaming with std::to_chars() directly into streambuf: 1612 ms
    Collecting the content in a string buffer of 418 MB: 1126 ms
    Writing the string buffer of 418 MB into a disk file: 796 ms


    g++ 8.3 on Linux:
    $ g++ -Wall -O3 -std=c++17 test6.cpp
    $ ./a.out
    Traditional streaming: 2080 ms
    Streaming with std::to_chars() directly into streambuf: 903 ms
    Collecting the content in a string buffer of 418 MB: 655 ms
    Writing the string buffer of 418 MB into a disk file: 146 ms

    Interesting, thanks for posting.  It's a similar ratio on my machine.  I can see that the Windows way of doing things is definitely more burdensome.

    For curiosity, I also added a non-portable memory map variant to
    timings. As expected, it beats all the other methods. On Windows it is
    ca 21 times faster than ostream<<int streaming, on Linux it is just 3
    times faster. It preallocates a large file in advance and trims it into
    the correct size later, it might be one can yet shave off some cycles by
    doing something smarter.

    MSVC++ Win x64 Release:
    Traditional streaming (ostream<<int): 16309 ms
    Streaming with std::to_chars() directly into streambuf: 1353 ms
    Collecting the content in a string buffer of 418 MB: 1123 ms
    Writing the string buffer of 418 MB into a disk file: 668 ms
    Serializing to memory-mapped file: 753 ms
    Speedup of mmap, compared to ostream<<int: 21.6587 times

    Linux g++ 8.3:
    $ g++ -O3 -std=c++17 test7.cpp
    $ ./a.out
    Traditional streaming (ostream<<int): 2358 ms
    Streaming with std::to_chars() directly into streambuf: 1142 ms
    Collecting the content in a string buffer of 418 MB: 674 ms
    Writing the string buffer of 418 MB into a disk file: 393 ms
    Serializing to memory-mapped file: 772 ms
    Speedup of mmap, compared to ostream<<int: 3.0544 times

    #include <iostream>
    #include <string>
    #include <vector>
    #include <numeric>
    #include <charconv>
    #include <chrono>
    #include <cstdint>
    #include <fstream>
    #include <limits>
    #include <stdexcept>

    #ifdef _WIN32
    #define NOMINMAX
    #include <Windows.h>
    #endif

    #ifdef __linux__
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #endif

    #ifdef _WIN32

    class MMapper {
    public:
    MMapper(const char* filename, size_t len) {
    h_ = ::CreateFileA(filename, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL, NULL);
    if (h_==INVALID_HANDLE_VALUE) {
    throw std::runtime_error("CreateFileA() failed");
    }
    LARGE_INTEGER x;
    x.QuadPart = len;
    if (!::SetFilePointerEx(h_, x, nullptr, FILE_BEGIN)) {
    throw std::runtime_error("SetFilePointerEx() failed");
    }
    if (!::SetEndOfFile(h_)) {
    throw std::runtime_error("SetEndOfFile() failed");
    }
    m_ = ::CreateFileMappingA(h_, NULL, PAGE_READWRITE, 0, 0, NULL);
    if (!m_) {
    auto err = ::GetLastError();
    throw std::runtime_error("CreateFileMappingA() failed");
    }
    view_ = ::MapViewOfFile(m_, FILE_MAP_WRITE, 0, 0, len);
    if (!view_) {
    auto err = ::GetLastError();
    throw std::runtime_error("MapViewOfFile() failed");
    }
    }
    ~MMapper() {
    Close(0);
    }
    void Close(size_t len) {
    if (view_) {
    ::UnmapViewOfFile(view_);
    view_ = nullptr;
    }
    if (m_) {
    ::CloseHandle(m_);
    m_ = nullptr;
    }
    if (h_) {
    LARGE_INTEGER x;
    x.QuadPart = len;
    if (!::SetFilePointerEx(h_, x, nullptr, FILE_BEGIN)) {
    throw std::runtime_error("SetFilePointerEx() failed");
    }
    if (!::SetEndOfFile(h_)) {
    throw std::runtime_error("SetEndOfFile() failed");
    }
    ::CloseHandle(h_);
    h_ = nullptr;
    }
    }
    char* Buffer() {
    return static_cast<char*>(view_);
    }
    private:
    HANDLE h_, m_;
    void* view_;
    };

    #endif

    #ifdef __linux__
    class MMapper {
    public:
    MMapper(const char* filename, size_t len): len_(len) {
    fd_ = open(filename, O_CREAT|O_RDWR|O_TRUNC, 0644);
    if (fd_==-1) {
    throw std::runtime_error("creat() failed");
    }
    if (ftruncate(fd_, len)!=0) {
    throw std::runtime_error("ftruncate() failed");
    }
    view_ = mmap(nullptr, len, PROT_WRITE, MAP_SHARED, fd_, 0);
    if (view_==MAP_FAILED) {
    throw std::runtime_error("mmap() failed");
    }
    }
    ~MMapper() {
    Close(0);
    }
    void Close(size_t len) {
    if (view_) {
    munmap(view_, len_);
    view_ = nullptr;
    }
    if (fd_!=-1) {
    if (ftruncate(fd_, len)!=0) {
    throw std::runtime_error("ftruncate() failed");
    }
    close(fd_);
    fd_ = -1;
    }
    }
    char* Buffer() {
    return static_cast<char*>(view_);
    }
    private:
    size_t len_;
    int fd_;
    void* view_;
    };
    #endif

    class A {
    public:
    A();

    // traditional operator<<
    friend std::ostream& operator<<(std::ostream& os, const A& a);

    // tostring() operator
    std::string to_string() const;

    // Select whether operator<< uses stream or streambuf interface.
    bool useStreamBufOnly = false;

    // Return the maximum needed buffer space for serializing.
    size_t MaxSerializedSize() const {
    char buff[64];
    size_t maxLen = std::to_chars(buff, buff+sizeof(buff), std::numeric_limits<int>::min()).ptr - buff;
    return data.size()*(maxLen+1); // +1 for a space between numbers.
    }

    size_t Serialize(char* buffer) const;
    private:
    std::vector<int> data;
    };

    A::A() {
    // Initialize data to 50 million ints.
    data.resize(50000000);
    std::iota(data.begin(), data.end(), 0);
    }

    std::ostream& operator<<(std::ostream& os, const A& a) {
    if (a.useStreamBufOnly) {
    // Ignore stream, use streambuf only.
    auto streamBuf = os.rdbuf();
    const size_t k = 64;
    char buff[k];
    for (auto x: a.data) {
    auto q = std::to_chars(buff, buff+k, x).ptr;
    *q++ = ' ';
    streamBuf->sputn(buff, q-buff);
    }
    } else {
    // Traditional stream output
    for (auto x: a.data) {
    os << x << ' ';
    }
    }
    return os;
    }

    std::string A::to_string() const {
    const size_t k = 64;
    char buffer[k];
    std::string result;
    for (auto x: data) {
    auto q = std::to_chars(buffer, buffer+k, x).ptr;
    *q++ = ' ';
    result.append(buffer, q-buffer);
    }
    return result;
    }

    size_t A::Serialize(char* buffer) const {
    char* p = buffer;
    for (auto x: data) {
    p = std::to_chars(p, p+64, x).ptr;
    *p++ = ' ';
    }
    return p - buffer;
    }

    using sclock = std::chrono::steady_clock;

    std::int64_t ms(sclock::duration lapse) {
    return std::chrono::duration_cast<std::chrono::milliseconds>(lapse).count();
    }

    int main() {
    try {

    A a;

    // traditional streaming
    a.useStreamBufOnly = false;
    sclock::time_point start1 = sclock::now();
    std::ofstream sink1("sink1.txt", std::ios::binary);
    sink1 << a;
    sink1.close();
    sclock::time_point finish1 = sclock::now();
    std::cout << "Traditional streaming (ostream<<int): " << ms(finish1-start1) << " ms\n";

    // streaming with to_chars() and streambuf
    a.useStreamBufOnly = true;
    sclock::time_point start2 = sclock::now();
    std::ofstream sink2("sink2.txt", std::ios::binary);
    sink2 << a;
    sink2.close();
    sclock::time_point finish2 = sclock::now();
    std::cout << "Streaming with std::to_chars() directly into
    streambuf: " << ms(finish2-start2) << " ms\n";

    // tostring()
    sclock::time_point start3 = sclock::now();
    std::string s3 = a.to_string();
    sclock::time_point finish3 = sclock::now();
    std::cout << "Collecting the content in a string buffer of " << s3.length()/(1024*1024) << " MB: " << ms(finish3-start3) << " ms\n";

    sclock::time_point start3b = sclock::now();
    std::ofstream sink3("sink3.txt", std::ios::binary);
    sink3.rdbuf()->sputn(s3.data(), s3.length());
    sink3.close();
    sclock::time_point finish3b = sclock::now();
    std::cout << "Writing the string buffer of " << s3.length()/(1024*1024) << " MB into a disk file: " <<
    ms(finish3b-start3b) << " ms\n";

    // mmap
    sclock::time_point start4 = sclock::now();
    size_t n = a.MaxSerializedSize();
    MMapper sink4("sink4.txt", n);
    size_t m = a.Serialize(sink4.Buffer());
    sink4.Close(m);
    sclock::time_point finish4 = sclock::now();
    std::cout << "Serializing to memory-mapped file: " << ms(finish4-start4) << " ms\n";

    std::cout << "Speedup of mmap, compared to ostream<<int: " << double(ms(finish1-start1))/ms(finish4-start4) << " times\n";


    } catch (const std::exception& e) {
    std::cerr << "EXCEPTION: " << e.what() << "\n";
    return EXIT_FAILURE;
    }
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Juha Nieminen on Wed Oct 6 13:06:32 2021
    Juha Nieminen <nospam@thanks.invalid> writes:

    alessandro volturno <alessandro.volturno@libero.it> wrote:

    Il 17/09/2021 07:36, Juha Nieminen ha scritto:

    alessandro volturno <alessandro.volturno@libero.it> wrote:

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

    This is not really something that belongs to a class that behaves
    like an arithmetic numerical value.

    At most what you could have is a separate

    std::ostream& operator<<(std::ostream&, YourRationalClass);

    function for outputting the value to a std::ostream.

    if you read the two lines right before the one here reported you
    can see I did that.

    I wrote that function to give an extensive description of a
    rational number in a way like this:

    "4/16 reduces to 1/4 and evaluates to 0.25"

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

    That depends on exactly what the function does. If the function
    depends on the object's internal representation or on invariants
    that are not publically available, then certainly defining the
    function as a member function is a more natural choice.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)