• C++ named requirements as concepts

    From jseigh@21:1/5 to All on Sat Sep 21 15:43:19 2024
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.

    template<typename T>
    concept BasicLockable = requires(T a)
    {
    { a.lock() } -> std::same_as<void>;
    { a.unlock() } -> std::same_as<void>;
    };

    template<BasicLockable T>
    ...

    Also if I define some concept for use in function templates,
    C++ doesn't like using primative types, just classes.
    Regular templates don't have the problem but they
    just seem to be glorified macros.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sun Sep 22 08:06:58 2024
    On Sat, 21 Sep 2024 15:43:19 -0400
    jseigh <[email protected]> boringly babbled:
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.

    The signal to noise ratio of useful vs pointless features in recent versions
    of C++ is not very good. All they're achieving is making the language so
    bloody complicated that new devs take one look at irt and flee for the hills. There's a reason Python - and to a lesser extent these days - Java are used
    for teaching in univerisities now, not C++. And if you don't get them young
    you can pretty much forget about getting many of the when they're older.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sun Sep 22 08:59:41 2024
    On Sun, 22 Sep 2024 10:45:01 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 22.09.2024 um 10:06 schrieb [email protected]:
    On Sat, 21 Sep 2024 15:43:19 -0400
    jseigh <[email protected]> boringly babbled:
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.

    The signal to noise ratio of useful vs pointless features in recent versions >> of C++ is not very good. All they're achieving is making the language so
    bloody complicated that new devs take one look at irt and flee for the hills.


    Concepts are a very easy to understand feature of C++20.

    They're also yet another solution looking for a problem that add another
    dollop of slop to the syntatic and semantic soup that is modern C++.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sun Sep 22 09:08:01 2024
    On Sun, 22 Sep 2024 11:03:18 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 22.09.2024 um 10:59 schrieb [email protected]:
    On Sun, 22 Sep 2024 10:45:01 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 22.09.2024 um 10:06 schrieb [email protected]:
    On Sat, 21 Sep 2024 15:43:19 -0400
    jseigh <[email protected]> boringly babbled:
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.

    The signal to noise ratio of useful vs pointless features in recent >versions
    of C++ is not very good. All they're achieving is making the language so >>>> bloody complicated that new devs take one look at irt and flee for the >hills.


    Concepts are a very easy to understand feature of C++20.

    They're also yet another solution looking for a problem that add another
    dollop of slop to the syntatic and semantic soup that is modern C++.


    Without concepts you might have complex errors from inside of a generic >functions. With human readable concept errors which all current C++20 >-compilers support you get easier to read errors which show you which >requirement a generic type missed. That's a real advance over C++17.

    Generating appropriate readable errors is a function of the compiler, not
    the language. g++ errors can be absolutely useless for actual debugging and thats a fault of the gcc devs. Clang errors are usually more helpful but even they can be too long winded at times.

    Why the compiler devs thought printing out literally (in some cases) pages of incomprehensible gibberish just because of some minor templating error was a good idea beats me.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to jseigh on Sun Sep 22 11:46:37 2024
    On 21/09/2024 21:43, jseigh wrote:
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.

    template<typename T>
    concept BasicLockable = requires(T a)
    {
        { a.lock() } -> std::same_as<void>;
        { a.unlock() } -> std::same_as<void>;
    };

    template<BasicLockable T>
    ...

    I think the answer is simply that there are so vastly many concepts that
    people might be interested in that it is impractical to have more than a
    small proportion of the most useful ones in the standard library:

    <https://en.cppreference.com/w/cpp/concepts>

    I would expect that we'll see steadily more added, tied to specific
    templates. (I.e., when the the header <foo> with the template
    std::foo<T> is added, we'll get the concept std::fooable<T> defined in
    the same header <foo> as a requires clause so that error messages are a
    bit neater.)



    Also if I define some concept for use in function templates,
    C++ doesn't like using primative types, just classes.
    Regular templates don't have the problem but they
    just seem to be glorified macros.


    I haven't used concepts much as yet, so I'll leave that for someone
    else. Hopefully you'll get a useful answer to a useful question, rather
    than just yet another Bonita/Muttley pissing contest.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to [email protected] on Sun Sep 22 07:58:56 2024
    On 9/22/24 04:06, [email protected] wrote:
    On Sat, 21 Sep 2024 15:43:19 -0400
    jseigh <[email protected]> boringly babbled:
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.

    The signal to noise ratio of useful vs pointless features in recent versions of C++ is not very good. All they're achieving is making the language so bloody complicated that new devs take one look at irt and flee for the hills. There's a reason Python - and to a lesser extent these days - Java are used for teaching in univerisities now, not C++. And if you don't get them young you can pretty much forget about getting many of the when they're older.


    Actually I do use Java. It has an insane number of libraries for just
    about anything you can think of. And the jit makes it fast enough
    for most purposes. Probably faster since it dynamically optimizes
    code paths. You have to remember to "bake in" a java program before
    you do performance measurements.

    I use C/C++ for different reasons. The C++ concepts look like they
    could be used in some cases like Rust traits which I like better
    than Java interfaces since they can be added without having to
    modify the base class or add a wrapper class.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sun Sep 22 15:15:37 2024
    On Sun, 22 Sep 2024 11:51:25 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 22.09.2024 um 11:08 schrieb [email protected]:

    On Sun, 22 Sep 2024 11:03:18 +0200

    Without concepts you might have complex errors from inside of a generic
    functions. With human readable concept errors which all current C++20
    -compilers support you get easier to read errors which show you which
    requirement a generic type missed. That's a real advance over C++17.

    Generating appropriate readable errors is a function of the compiler, not
    the language. ...

    It's part of the language and therefore there are concepts.

    Congrats on not understanding what I was saying. It wasn't that complicated.

    incomprehensible gibberish just because of some minor templating error was a >> good idea beats me.

    Chose Java if you're overburdened with C++.

    Its too late in my career to change now as I don't fancy starting at the
    bottom again, but if I was just starting out on a systems programming career right now I'd be learning Rust.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sun Sep 22 15:21:42 2024
    On Sun, 22 Sep 2024 07:58:56 -0400
    jseigh <[email protected]> boringly babbled:
    On 9/22/24 04:06, [email protected] wrote:
    On Sat, 21 Sep 2024 15:43:19 -0400
    jseigh <[email protected]> boringly babbled:
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.

    The signal to noise ratio of useful vs pointless features in recent versions >> of C++ is not very good. All they're achieving is making the language so
    bloody complicated that new devs take one look at irt and flee for the hills.

    There's a reason Python - and to a lesser extent these days - Java are used >> for teaching in univerisities now, not C++. And if you don't get them young >> you can pretty much forget about getting many of the when they're older.


    Actually I do use Java. It has an insane number of libraries for just
    about anything you can think of. And the jit makes it fast enough
    for most purposes. Probably faster since it dynamically optimizes
    code paths. You have to remember to "bake in" a java program before
    you do performance measurements.

    The main issue with Java IME was memory hogging and the occasional hang while the garnage collector did its thing. But last time I was involved with it was 10 years ago so I imagine things have changed somewhat since then.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andrey Tarasevich@21:1/5 to jseigh on Sun Sep 22 11:43:28 2024
    On 09/21/24 12:43 PM, jseigh wrote:

    Also if I define some concept for use in function templates,
    C++ doesn't like using primative types, just classes.

    Er... Can you provide an example?

    --
    Best regards,
    Andrey

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Andrey Tarasevich on Sun Sep 22 17:00:19 2024
    On 9/22/24 14:43, Andrey Tarasevich wrote:
    On 09/21/24 12:43 PM, jseigh wrote:

    Also if I define some concept for use in function templates,
    C++ doesn't like using primative types, just classes.

    Er... Can you provide an example?

    #include <concepts>

    template<typename T>
    concept GetRef = requires(T a)
    {
    { getref(a)} -> std::same_as<void *>;
    };

    class test_t {};

    static void * getref(int x) { return 0; }

    static void * getref(test_t x) { return 0; }

    template<GetRef X>
    static void getref_concept(X z) {
    getref(z);
    };

    template<typename T>
    static void getref_template(T t)
    {
    getref(t);
    }

    int main()
    {
    test_t x = {};

    getref_concept(x);
    getref_concept(4);

    // zz(4);

    getref_template(x);
    getref_template(4);

    return 0;
    }

    $ g++ -C -std=c++20 -O3 -fconcepts-diagnostics-depth=4 ctest2.cpp
    ctest2.cpp: In function ‘int main()’:
    ctest2.cpp:31:19: error: no matching function for call to ‘getref_concept(int)’
    31 | getref_concept(4);
    | ~~~~~~~~~~~~~~^~~
    ctest2.cpp:16:13: note: candidate: ‘template<class X> requires
    GetRef<X> void getref_concept(X)’
    16 | static void getref_concept(X z) {
    | ^~~~~~~~~~~~~~
    ctest2.cpp:16:13: note: template argument deduction/substitution failed: ctest2.cpp:16:13: note: constraints not satisfied
    ctest2.cpp: In substitution of ‘template<class X> requires GetRef<X>
    void getref_concept(X) [with X = int]’:
    ctest2.cpp:31:19: required from here
    ctest2.cpp:4:9: required for the satisfaction of ‘GetRef<X>’ [with X = int]
    ctest2.cpp:4:18: in requirements with ‘T a’ [with T = int] ctest2.cpp:6:13: note: the required expression ‘getref(a)’ is invalid, because
    6 | { getref(a)} -> std::same_as<void *>;
    | ~~~~~~^~~
    ctest2.cpp:6:13: error: ‘getref’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
    ctest2.cpp:13:15: note: ‘void* getref(test_t)’ declared here, later in
    the translation unit
    13 | static void * getref(test_t x) { return 0; }
    | ^~~~~~


    No idea except maybe concepts don't like primitives as types.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andrey Tarasevich@21:1/5 to jseigh on Sun Sep 22 14:50:18 2024
    On 09/22/24 2:00 PM, jseigh wrote:
    On 9/22/24 14:43, Andrey Tarasevich wrote:
    On 09/21/24 12:43 PM, jseigh wrote:

    Also if I define some concept for use in function templates,
    C++ doesn't like using primative types, just classes.

    Er... Can you provide an example?

    #include <concepts>

    template<typename T>
    concept GetRef = requires(T a)
    {
        { getref(a)} -> std::same_as<void *>;
    };

    class test_t {};

    static void * getref(int x) { return 0; }

    static void * getref(test_t x) { return 0; }

    template<GetRef X>
    static void getref_concept(X z) {
        getref(z);
    };

    template<typename T>
    static void getref_template(T t)
    {
        getref(t);
    }

    int main()
    {
        test_t x = {};

        getref_concept(x);
        getref_concept(4);

        // zz(4);

        getref_template(x);
        getref_template(4);

        return 0;
    }

    $ g++ -C -std=c++20 -O3 -fconcepts-diagnostics-depth=4 ctest2.cpp
    ctest2.cpp: In function ‘int main()’:
    ctest2.cpp:31:19: error: no matching function for call to ‘getref_concept(int)’
       31 |     getref_concept(4);
          |     ~~~~~~~~~~~~~~^~~
    ctest2.cpp:16:13: note: candidate: ‘template<class X>  requires
    GetRef<X> void getref_concept(X)’
       16 | static void getref_concept(X z) {
          |             ^~~~~~~~~~~~~~
    ctest2.cpp:16:13: note:   template argument deduction/substitution failed: ctest2.cpp:16:13: note: constraints not satisfied
    ctest2.cpp: In substitution of ‘template<class X>  requires  GetRef<X> void getref_concept(X) [with X = int]’:
    ctest2.cpp:31:19:   required from here
    ctest2.cpp:4:9:   required for the satisfaction of ‘GetRef<X>’ [with X =
    int]
    ctest2.cpp:4:18:   in requirements with ‘T a’ [with T = int] ctest2.cpp:6:13: note: the required expression ‘getref(a)’ is invalid, because
        6 |     { getref(a)} -> std::same_as<void *>;
          |       ~~~~~~^~~
    ctest2.cpp:6:13: error: ‘getref’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
    ctest2.cpp:13:15: note: ‘void* getref(test_t)’ declared here, later in the translation unit
       13 | static void * getref(test_t x) { return 0; }
          |               ^~~~~~


    No idea except maybe concepts don't like primitives as types.


    But this is just a two-phase name lookup problem caused by your order of declarations. It has nothing to do with concepts at all. You will get essentially the same error in the following example:

    template <typename T> void foo(T t) { bar(t); }

    void bar(int) {}

    int main()
    {
    foo(42);
    }

    The reason this error happens is that the second-phase of template
    lookup is performed in ADL-associated namespaces only. And built-in
    types (like `int`) do not have associated namespaces.

    For this reason, for built-in types everything you refer to from
    template code has to be declared _above_ that template code.

    So, in your case you have to declare your `getref` functions _above_ the concept declaration and the code will compile. At least the `int`
    version of `getref` has to be declared above the concept

    https://coliru.stacked-crooked.com/a/2d021dbf666f4f93

    --
    Best regards,
    Andrey

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jack@21:1/5 to All on Mon Sep 23 00:15:33 2024
    On Sat, 21 Sep 2024 15:43:19 -0400
    jseigh <[email protected]> boringly babbled:
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.


    Why don't you make a suggestion to people who creates guidelines?

    <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines> <https://isocpp.github.io/CppCoreGuidelines/>

    The C++ Core Guidelines are an initiative led by Bjarne Stroustrup, the inventor of C++, and Herb Sutter, the convener and chair of the C++ ISO
    Working Group, to help programmers write 'Modern C++' by using best
    practices for the language standards C++11 and newer, and to help
    developers of compilers and static checking tools to create rules for
    catching bad programming practices.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 23 07:40:13 2024
    On Sun, 22 Sep 2024 17:34:29 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 22.09.2024 um 17:21 schrieb [email protected]:

    The main issue with Java IME was memory hogging and the occasional hang while

    the garnage collector did its thing. ...

    The incremental garbage collector is there for about 20 years. Memory
    hogging isn't a problem for what Java is used. It's used in places
    where otherwise you'd use scripting languages for the server backend.

    Saying something is less worse than the alternatives is not a good argument.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 23 07:39:40 2024
    On Sun, 22 Sep 2024 17:33:03 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 22.09.2024 um 17:15 schrieb [email protected]:
    Congrats on not understanding what I was saying. It wasn't that complicated.

    If you have requirements on a generic type and they're not fulfilled
    concepts are the only way to handle this conveniently in C++.

    Face <- palm.

    Its too late in my career to change now as I don't fancy starting at the
    bottom again, but if I was just starting out on a systems programming career >> right now I'd be learning Rust.


    Rust will be popular in 10 - 20 years.

    Or maybe it'll fail altogether like D. However it seems a reasonable halfway house between C and C++ with built in memory safety and much less of the syntatic and semantic bollocks that comes with C++.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 23 09:32:15 2024
    On Mon, 23 Sep 2024 10:54:44 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 09:39 schrieb [email protected]:

    Face <- palm.

    Seems you don't undestand concepts.

    And you don't understand english well enough to follow a thread which is
    fair enough, its probably not your first language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 23 09:33:14 2024
    On Mon, 23 Sep 2024 10:55:33 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 09:40 schrieb [email protected]:
    On Sun, 22 Sep 2024 17:34:29 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 22.09.2024 um 17:21 schrieb [email protected]:

    The main issue with Java IME was memory hogging and the occasional hang >while

    the garnage collector did its thing. ...

    The incremental garbage collector is there for about 20 years. Memory
    hogging isn't a problem for what Java is used. It's used in places
    where otherwise you'd use scripting languages for the server backend.

    Saying something is less worse than the alternatives is not a good argument. >>

    Java is good enough for what it's used for.
    Memory is extremely cheap so that no one cares for what you say.

    Spoken like a true windows dev who thinks every system is a windows PC thats only ever running 1 app at a time.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 23 13:56:43 2024
    On Mon, 23 Sep 2024 11:45:15 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 11:32 schrieb [email protected]:
    On Mon, 23 Sep 2024 10:54:44 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 09:39 schrieb [email protected]:

    Face <- palm.

    Seems you don't undestand concepts.

    And you don't understand english well enough to follow a thread which is
    fair enough, its probably not your first language.

    Without concepts you've to deal with the implementation
    of code where you like to deal only with the interface.

    Stop digging.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 23 13:59:04 2024
    On Mon, 23 Sep 2024 11:46:40 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 11:33 schrieb [email protected]:

    On Mon, 23 Sep 2024 10:55:33 +0200

    Java is good enough for what it's used for.
    Memory is extremely cheap so that no one cares for what you say.

    Spoken like a true windows dev who thinks every system is a windows PC thats >> only ever running 1 app at a time.

    Java-developers would agree with me, no matter if they develop
    under Windows or Linux.

    Their opinion is irrelevant as they don't know any better. Memory and CPU cycles costs money whether its your own system, a hosted blade or an AWS EC2 instance so a java app cannot assume its got the machine to itself because these days thats very much not the case.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 23 14:03:13 2024
    On Mon, 23 Sep 2024 16:00:13 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 15:56 schrieb [email protected]:
    On Mon, 23 Sep 2024 11:45:15 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 11:32 schrieb [email protected]:
    On Mon, 23 Sep 2024 10:54:44 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 09:39 schrieb [email protected]:

    Face <- palm.

    Seems you don't undestand concepts.

    And you don't understand english well enough to follow a thread which is >>>> fair enough, its probably not your first language.

    Without concepts you've to deal with the implementation
    of code where you like to deal only with the interface.

    Stop digging.


    C++ is a programming language for people who work with it continuously, >rather than occasionally.

    Stop digging.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 23 14:05:22 2024
    On Mon, 23 Sep 2024 16:02:30 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 23.09.2024 um 15:59 schrieb [email protected]:

    Their opinion is irrelevant as they don't know any better. ..

    They make the rules if they decide to program with Java, not you.

    No, the sys admin makes the rules and if some app decides its going to
    try and allocate most of system memory on startup which blows its quota then that app will be killed.

    Memory and CPU cycles costs money whether its your own system,
    a hosted blade or an AWS EC2 instance so a java app cannot assume
    its got the machine to itself because these days thats very much
    not the case.

    Java is the standard for the server-backend.

    Its a standard. Python is rapidly eating its lunch however in certain areas.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Andrey Tarasevich on Mon Sep 23 10:32:23 2024
    On 9/22/24 17:50, Andrey Tarasevich wrote:
    On 09/22/24 2:00 PM, jseigh wrote:
    On 9/22/24 14:43, Andrey Tarasevich wrote:
    On 09/21/24 12:43 PM, jseigh wrote:

    Also if I define some concept for use in function templates,
    C++ doesn't like using primative types, just classes.

    Er... Can you provide an example?

    #include <concepts>

    template<typename T>
    concept GetRef = requires(T a)
    {
         { getref(a)} -> std::same_as<void *>;
    };

    class test_t {};

    static void * getref(int x) { return 0; }

    static void * getref(test_t x) { return 0; }

    template<GetRef X>
    static void getref_concept(X z) {
         getref(z);
    };

    template<typename T>
    static void getref_template(T t)
    {
         getref(t);
    }

    int main()
    {
         test_t x = {};

         getref_concept(x);
         getref_concept(4);

         // zz(4);

         getref_template(x);
         getref_template(4);

         return 0;
    }

    $ g++ -C -std=c++20 -O3 -fconcepts-diagnostics-depth=4 ctest2.cpp
    ctest2.cpp: In function ‘int main()’:
    ctest2.cpp:31:19: error: no matching function for call to
    ‘getref_concept(int)’
        31 |     getref_concept(4);
           |     ~~~~~~~~~~~~~~^~~
    ctest2.cpp:16:13: note: candidate: ‘template<class X>  requires
    GetRef<X> void getref_concept(X)’
        16 | static void getref_concept(X z) {
           |             ^~~~~~~~~~~~~~
    ctest2.cpp:16:13: note:   template argument deduction/substitution
    failed:
    ctest2.cpp:16:13: note: constraints not satisfied
    ctest2.cpp: In substitution of ‘template<class X>  requires  GetRef<X> >> void getref_concept(X) [with X = int]’:
    ctest2.cpp:31:19:   required from here
    ctest2.cpp:4:9:   required for the satisfaction of ‘GetRef<X>’ [with X >> = int]
    ctest2.cpp:4:18:   in requirements with ‘T a’ [with T = int]
    ctest2.cpp:6:13: note: the required expression ‘getref(a)’ is invalid, >> because
         6 |     { getref(a)} -> std::same_as<void *>;
           |       ~~~~~~^~~
    ctest2.cpp:6:13: error: ‘getref’ was not declared in this scope, and
    no declarations were found by argument-dependent lookup at the point
    of instantiation [-fpermissive]
    ctest2.cpp:13:15: note: ‘void* getref(test_t)’ declared here, later in >> the translation unit
        13 | static void * getref(test_t x) { return 0; }
           |               ^~~~~~


    No idea except maybe concepts don't like primitives as types.


    But this is just a two-phase name lookup problem caused by your order of declarations. It has nothing to do with concepts at all. You will get essentially the same error in the following example:

      template <typename T> void foo(T t) { bar(t); }

      void bar(int) {}

      int main()
      {
        foo(42);
      }

    The reason this error happens is that the second-phase of template
    lookup is performed in ADL-associated namespaces only. And built-in
    types (like `int`) do not have associated namespaces.

    For this reason, for built-in types everything you refer to from
    template code has to be declared _above_ that template code.

    So, in your case you have to declare your `getref` functions _above_ the concept declaration and the code will compile. At least the `int`
    version of `getref` has to be declared above the concept

    https://coliru.stacked-crooked.com/a/2d021dbf666f4f93


    Ok, thanks. That helps a lot.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Bonita Montero on Mon Sep 23 11:08:59 2024
    On 9/22/24 08:10, Bonita Montero wrote:
    Am 22.09.2024 um 13:58 schrieb jseigh:

    Actually I do use Java.  It has an insane number of libraries for just
    about anything you can think of.  And the jit makes it fast enough
    for most purposes.  Probably faster since it dynamically optimizes
    code paths. ...

    It executes each function once interpreteted and makes then its
    conclusions about the code. That's not sufficient.
    In the Computer Languages Benchmark Game Java is about 50% the
    Performance of C++.

    google java jit optimization or https://developers.redhat.com/articles/2021/06/23/how-jit-compiler-boosts-java-performance-openjdk#


    I use C/C++ for different reasons.  The C++ concepts look like they
    could be used in some cases like Rust traits which I like better
    than Java interfaces since they can be added without having to
    modify the base class or add a wrapper class.

    Java hasn't real gericity.


    You mean the type erasure thing?

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andrey Tarasevich@21:1/5 to Bonita Montero on Mon Sep 23 08:11:30 2024
    On 09/23/24 7:55 AM, Bonita Montero wrote:
    Am 22.09.2024 um 23:50 schrieb Andrey Tarasevich:

       template <typename T> void foo(T t)

             requires convertible_to<T, int>

    { bar(t); }


    Not sure why and what you are trying to say by that.

    --
    Best regards,
    Andrey

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bonita Montero on Mon Sep 23 15:48:48 2024
    Bonita Montero <[email protected]> writes:
    Am 23.09.2024 um 09:39 schrieb [email protected]:

    Face <- palm.

    Seems you don't undestand concepts.

    Rust will be popular in 10 - 20 years.

    Or maybe it'll fail altogether like D. However it seems a reasonable halfway >> house between C and C++ with built in memory safety and much less of the
    syntatic and semantic bollocks that comes with C++.

    The memory-safety can be reached while debugging through iterator-debug- >ging. I consequently use iterator debugging, f.e. through spans on raw >memory, and this way out of bounds errors are easy to find. Even for
    s.o. who doesn't know the code.


    All you seem to develop are 100-line programs. Try your techniques
    with a real-world application (half-million lines) and get back to
    us.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to [email protected] on Mon Sep 23 15:47:38 2024
    [email protected] writes:

    Rust will be popular in 10 - 20 years.

    Or maybe it'll fail altogether like D. However it seems a reasonable halfway >house between C and C++ with built in memory safety and much less of the >syntatic and semantic bollocks that comes with C++.

    So far. But then C++ didn't have all the syntactic and semantic bollocks
    when it was first developed; just C with classes for data encapsulation.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Mon Sep 23 16:24:58 2024
    On 9/23/24 15:55, Chris M. Thomasson wrote:
    On 9/23/2024 7:02 AM, Bonita Montero wrote:
    Am 23.09.2024 um 15:59 schrieb [email protected]:

    Their opinion is irrelevant as they don't know any better. ..

    They make the rules if they decide to program with Java, not you.

    Memory and CPU cycles costs money whether its your own system,
    a hosted blade or an AWS EC2 instance so a java app cannot assume
    its got the machine to itself because these days thats very much
    not the case.

    Java is the standard for the server-backend.

    Well, I would not use Java to implement a high performance server... :^)

    ActiveMQ (JMS) is in java
    Apache Kafka is in scala and java
    RabbitMQ (amqp) is in erlang
    QPid (amqp) has both a java broker and a c++ broker

    They are all pretty performant.

    I've used activemq quite a bit. I like the amqp protocol a bit
    more for some of it's message acknowledgement abilities, but
    finding a client that was decent (e.g. not written by one
    person and updated more recently than 5 years ago) can be
    a chore. Plus some amqp protocol versions are backwards
    compatible so that limits your client choices also.

    Plus things like the jms clients for amqp weren't very well
    written. So you couldn't just switch from activemq broker
    to a amqp broker.

    Interestingly, activemq has an amqp connector but I never
    used it. I only noticed it when I tried to run an
    activemq broker and amqp broker at the same time and
    they used the same default ports for amqp.

    Anyway, it isn't like nobody uses java for high performance
    stuff. More a personal preference of the implementers.

    Joe SEigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Mon Sep 23 18:59:49 2024
    On 9/23/24 17:43, Chris M. Thomasson wrote:
    On 9/23/2024 1:24 PM, jseigh wrote:
    On 9/23/24 15:55, Chris M. Thomasson wrote:

    Anyway, it isn't like nobody uses java for high performance
    stuff.  More a personal preference of the implementers.

    Well, I have written some servers in the past, very early 2000's was the
    last time, they were pretty good. 50,000 concurrent connections using
    IOCP on windows, then aio over on the linux side. Not much experience
    with AIO as IOCP.

    I used C way more back then wrt C++... But, how do I access the
    following API's directly in Java and not have to worry about any GC
    bullshit?

    https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatus

    Back in nt 4. Then the "newer" one, the Ex version... Ahhh windows:

    https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatusex

    https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex

    https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_connectex

    https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_transmitpackets

    https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile

    Btw, there is an interesting limitation on the transmitfile and iirc lpfn_transmitpackets functions wrt the version of windows. Server or
    Client iirc. Last time I checked only two of them can be in flight at
    any one time wrt overlapped io.


    Java tries to be platform agnostic so you won't see any platform
    specific stuff in the standard java libraries.

    The current fast io in linux is io_uring which I haven't used
    yet because I don't have anything I need to use it on.

    Anything i/o related will end up c code w/ native methods.
    There might be 3rd party stuff that does that.

    For i/o in java you can use java.nio.ByteBuffer which
    has a reusable internal byte array so no gc.
    java.nio.channels.SocketChannel uses ByteBuffers.

    There's also MappedByteBuffer. You could probably
    do some crazy stuff with that to share non java
    heap memory with a non java process. I'd let some
    3rd party lib work that out though.


    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 07:23:09 2024
    On Mon, 23 Sep 2024 16:24:58 -0400
    jseigh <[email protected]> boringly babbled:
    Anyway, it isn't like nobody uses java for high performance
    stuff. More a personal preference of the implementers.

    Anyone who wants to know how hopeless java can be for large applications
    only needs to use Jira or Eclipse for 5 minutes.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 07:20:24 2024
    On Mon, 23 Sep 2024 15:47:38 GMT
    [email protected] (Scott Lurndal) boringly babbled:
    [email protected] writes:

    Rust will be popular in 10 - 20 years.

    Or maybe it'll fail altogether like D. However it seems a reasonable halfway >>house between C and C++ with built in memory safety and much less of the >>syntatic and semantic bollocks that comes with C++.

    So far. But then C++ didn't have all the syntactic and semantic bollocks >when it was first developed; just C with classes for data encapsulation.

    True. One can hope that whatever team develops Rust knows when to leave well alone and only add important features going forward, not whatever half-arsed idea one of them farts out on the toilet that morning which seems to be how C++ is "designed" these days. Would also help if they avoided idiotic syntatic hacks such as off the top of my head:

    - Unused int arg to denote postfix
    - "= 0" for pure virtuals
    - {} for constructors inconsistent behviour depending on whether one of the
    constructors takes an initaliser list or not.
    -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 08:11:24 2024
    On Tue, 24 Sep 2024 09:33:41 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 09:20 schrieb [email protected]:

    True. One can hope that whatever team develops Rust knows when to leave well >> alone and only add important features going forward, not whatever half-arsed >> idea one of them farts out on the toilet that morning which seems to be how >C++
    is "designed" these days. Would also help if they avoided idiotic syntatic >> hacks such as off the top of my head:

    This is said by someone who thinks concepts, which are a rather simple >feature, are too complex.

    So you don't believe those are hacks? Fair enough. And there's a difference between too complex and pointless.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 08:14:15 2024
    On Tue, 24 Sep 2024 09:34:33 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 09:23 schrieb [email protected]:
    On Mon, 23 Sep 2024 16:24:58 -0400
    jseigh <[email protected]> boringly babbled:
    Anyway, it isn't like nobody uses java for high performance
    stuff. More a personal preference of the implementers.

    Anyone who wants to know how hopeless java can be for large applications
    only needs to use Jira or Eclipse for 5 minutes.


    I'm using IntellIJ Idea

    Never heard of it.

    on a AMD 7950X and it's nearly as fast as
    Visual Studio.

    According to wonkypedia its partly written in Kotlin. Whether that makes
    a difference or not ....

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 10:52:49 2024
    On Tue, 24 Sep 2024 11:46:26 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Unfortunately the standard libary isn't concepted currently, f.e. if
    you modify an element inside the function-object given to std::sort
    you won't get an error. A concept could enforce that you take const

    Bummer. So don't modify them inside the function object.

    If thats the best use case you can come up with to justify them then I won't lose any sleep over not bothering to learn them, particularly since my
    compiler is only partially 2020 compliant anyway.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 10:50:29 2024
    On Tue, 24 Sep 2024 11:17:05 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 10:11 schrieb [email protected]:

    So you don't believe those are hacks? Fair enough. And there's a difference >> between too complex and pointless.

    Concepts aren't a hack and make APIs for those who use it simpler

    I wasn't refering to concepts FFS. I just give up with you, you can't
    follow a simple thread.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 10:59:50 2024
    On Tue, 24 Sep 2024 12:54:34 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 12:52 schrieb [email protected]:
    On Tue, 24 Sep 2024 11:46:26 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Unfortunately the standard libary isn't concepted currently, f.e. if
    you modify an element inside the function-object given to std::sort
    you won't get an error. A concept could enforce that you take const

    Bummer. So don't modify them inside the function object.

    Yes, but this can be safely enforced.
    F.e. if you wrote = instead of == inside such a lambda you get an error.

    Arguments to that type of function object should be const anyway so if a dev doesn't bother with that he's unlikely to bother writing concept code to do
    the same thing. Seems like a re-invention of the wheel in that particular example.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 11:07:53 2024
    On Tue, 24 Sep 2024 13:05:10 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 12:59 schrieb [email protected]:

    Arguments to that type of function object should be const anyway ...

    That's always true, mostly false.

    What?

    Seems like a re-invention of the wheel in that particular example.

    No, it gives more meaningful errors. That's not for me, I understand
    the errors from inside a <algorithm>-function or whatever. That's for
    less C++-skilled people like you.

    I think you have an overrated sense of your own abilities. You may have
    better knowledge of the language than most but your ability to write clear
    and simple code is badly lacking as you frequently demonstrate.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Bonita Montero on Tue Sep 24 08:59:37 2024
    On 9/24/24 03:34, Bonita Montero wrote:
    Am 24.09.2024 um 09:23 schrieb [email protected]:
    On Mon, 23 Sep 2024 16:24:58 -0400
    jseigh <[email protected]> boringly babbled:
    Anyway, it isn't like nobody uses java for high performance
    stuff.  More a personal preference of the implementers.

    Anyone who wants to know how hopeless java can be for large applications
    only needs to use Jira or Eclipse for 5 minutes.


    I'm using IntellIJ Idea on a AMD 7950X and it's nearly as fast as
    Visual Studio.


    Is the community edition any good? Their paid version makes
    no sense for individual users.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to jseigh on Tue Sep 24 09:15:01 2024
    On 9/23/24 18:59, jseigh wrote:
    On 9/23/24 17:43, Chris M. Thomasson wrote:
    On 9/23/2024 1:24 PM, jseigh wrote:
    On 9/23/24 15:55, Chris M. Thomasson wrote:

    Anyway, it isn't like nobody uses java for high performance
    stuff.  More a personal preference of the implementers.

    Well, I have written some servers in the past, very early 2000's was
    the last time, they were pretty good. 50,000 concurrent connections
    using IOCP on windows, then aio over on the linux side. Not much
    experience with AIO as IOCP.

    I used C way more back then wrt C++... But, how do I access the
    following API's directly in Java and not have to worry about any GC
    bullshit?

    https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatus

    Back in nt 4. Then the "newer" one, the Ex version... Ahhh windows:

    https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getqueuedcompletionstatusex

    https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex

    https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_connectex

    https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_transmitpackets

    https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile

    Btw, there is an interesting limitation on the transmitfile and iirc
    lpfn_transmitpackets functions wrt the version of windows. Server or
    Client iirc. Last time I checked only two of them can be in flight at
    any one time wrt overlapped io.


    Java tries to be platform agnostic so you won't see any platform
    specific stuff in the standard java libraries.

    The current fast io in linux is io_uring which I haven't used
    yet because I don't have anything I need to use it on.

    Anything i/o related will end up c code w/ native methods.
    There might be 3rd party stuff that does that.

    For i/o in java you can use java.nio.ByteBuffer which
    has a reusable internal byte array so no gc.
    java.nio.channels.SocketChannel uses ByteBuffers.

    There's also MappedByteBuffer.  You could probably
    do some crazy stuff with that to share non java
    heap memory with a non java process.  I'd let some
    3rd party lib work that out though.


    On second thoght stay away from that last bit. Nobody
    in java land does web servers from scratch. They
    use one of the JAX-RS implementations. Usually
    you just write a request handler and configure all
    the rest. There might be some place you could plug
    in a custom io stream that did all that asyne io
    under the covers. I can say I was not overly fond
    of spring cxf or anything spring in general. Using
    java annotation beans and xml like that was an
    abomination and a PITA. There are worse things though
    like lombak.

    I used Buffers for things like truncating utf-8
    strings to fit into a fixed number of bytes on
    a correct char boundary. For db table columns
    defined in bytes size. You could define the
    columns in chars but the db is going to guess
    how many bytes *on average* you need to fit
    that many chars. Welcome to unicode.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 13:51:25 2024
    On Tue, 24 Sep 2024 13:21:37 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 13:07 schrieb [email protected]:
    On Tue, 24 Sep 2024 13:05:10 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 12:59 schrieb [email protected]:

    Arguments to that type of function object should be const anyway ...

    That's always true, mostly false.

    What?

    In most cases references as function-parameters are non-const if
    you include r-value-references (which can be const altough it doesn't
    make sense).

    No, the point was something can't be always true and mostly false at the
    same time.


    I think you have an overrated sense of your own abilities.

    No, I've worked a long time with C++ before concepts and I learned
    to live with the Swahili errors from the compiler.

    Those errors are a function of the compiler, not the language. As I said in
    a previous post, Clang produces far clearer error messages than the borderline useless rubbish that gcc spits out.

    You may have better knowledge of the language than most but your
    ability to write clear and simple code is badly lacking as you
    frequently demonstrate.

    Clear and simple in a sense that it's understandable for someone
    having only 10 hours experience with C++ is impossible. It's a
    language for people which are constantly working with.

    C++ can be written clearly as well as undertaking complex tasks. Sadly you
    lack the ability to do it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Sep 24 15:43:13 2024
    On Tue, 24 Sep 2024 15:56:31 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 15:51 schrieb [email protected]:

    Those errors are a function of the compiler, not the language. ...

    They arise from the standard.

    What are you talking about? The compiler writers can choose to output errors
    in any way and format they like.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Wed Sep 25 09:49:49 2024
    On 24/09/2024 17:43, [email protected] wrote:
    On Tue, 24 Sep 2024 15:56:31 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 15:51 schrieb [email protected]:

    Those errors are a function of the compiler, not the language. ...

    They arise from the standard.

    What are you talking about? The compiler writers can choose to output errors in any way and format they like.


    There is a fundamental difference in the errors when using concepts and
    when not using concepts.

    Suppose you have a template class A<T> and your template is only
    suitable if you can call "foo" on the type. Then later on you have
    "A<T> a;", and further down the line you call "foo(a);".

    With normal templates, you get an error when you try to call "foo(a)".
    This error is because the compiler can't find a suitable "foo" to call,
    no matter what implicit conversions it tries and what namespaces it
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to list possibilities. No matter where it picks the balance, it will be wrong
    for some cases - either it gives too much information, hiding the help
    in noise, or it gives too little information and missing the useful details.

    Using concepts, however, means the error is found on the first attempt
    to use the type "A<T>" - the compiler can give far clearer information.
    It can say "On line x, you tried to make A<T>, but type T does not
    fulfil the requirement you gave on line y when you defined class A".
    This is massively more direct, and leads you far fast to the source of
    the problem.

    Compilers can do better or worse at their error messages (gcc's messages
    often used to be incomprehensible when clang was the upstart with better messages - since then, gcc's messages have got hugely better.
    Competition is a great thing). And you sometimes want more information, sometimes less. But concepts give the programmer and the compiler a far
    better starting point.


    They also allow neater and clearer code with constrained auto
    declarations, letting you specify something between "this /exact/ type"
    and "whatever seems to fit".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 07:19:00 2024
    On Tue, 24 Sep 2024 17:48:01 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 17:43 schrieb [email protected]:
    On Tue, 24 Sep 2024 15:56:31 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 24.09.2024 um 15:51 schrieb [email protected]:

    Those errors are a function of the compiler, not the language. ...

    They arise from the standard.

    What are you talking about? The compiler writers can choose to output errors >> in any way and format they like.



    Warnings are compiler-specific, errors directly arise from standard >violations.

    Well in that case all errors should be output all the time, but gcc and
    clang have -W*, -pedantic so where does that leave your argument? Also there
    is no reason to print the entire error stack dump, just the first level error (the one they've actually made in their code) will do for most people. If they want the entire stack that could come with -Wall or whatever.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 08:24:19 2024
    On Wed, 25 Sep 2024 09:49:49 +0200
    David Brown <[email protected]> boringly babbled:
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to list

    It knows what line invoked the error so all it needs to do is print that.

    Using concepts, however, means the error is found on the first attempt
    to use the type "A<T>" - the compiler can give far clearer information.
    It can say "On line x, you tried to make A<T>, but type T does not
    fulfil the requirement you gave on line y when you defined class A".

    Tbh if you want to massage templating that much then don't use it in the
    first place, just hard code the functions.

    Competition is a great thing). And you sometimes want more information, >sometimes less. But concepts give the programmer and the compiler a far >better starting point.

    This is where compiler command line switches should come into play.

    They also allow neater and clearer code with constrained auto
    declarations, letting you specify something between "this /exact/ type"
    and "whatever seems to fit".

    Don't use auto in those scenarios then. Its always nicer when people put
    the specific type in the code anyway.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Wed Sep 25 11:36:56 2024
    On 25/09/2024 10:24, [email protected] wrote:
    On Wed, 25 Sep 2024 09:49:49 +0200
    David Brown <[email protected]> boringly babbled:
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to list

    It knows what line invoked the error so all it needs to do is print that.


    But that is typically not where the error lies.

    Compilers give messages that try to help the developer find the problem,
    not just tell you there is a problem. If it just says you can't do
    "foo(a);", that tells me little - I know that line is correct. The
    problem lies with the type of "a", or the definition of that type, or
    the declaration of "foo". That's what I want to know about.

    Using concepts, however, means the error is found on the first attempt
    to use the type "A<T>" - the compiler can give far clearer information.
    It can say "On line x, you tried to make A<T>, but type T does not
    fulfil the requirement you gave on line y when you defined class A".

    Tbh if you want to massage templating that much then don't use it in the first place, just hard code the functions.


    Sometimes you want something in between.

    If you want a template function that can be used with any integral type,
    you can have "auto next(std::integral auto x) { return x + 1; }". You
    are limiting this to integer types (using a standard library concept).
    You don't have to hard-code all the different types of integer.
    Equally, it is not so open that it will also work with pointers - if you
    try "next(&y)", you'll get a nice clear error message.


    Competition is a great thing). And you sometimes want more information,
    sometimes less. But concepts give the programmer and the compiler a far
    better starting point.

    This is where compiler command line switches should come into play.

    They can help, of course - as can a good IDE that interprets the error
    messages and helps you navigate to possible errors. Concepts make the
    whole thing easier and clearer in many cases.

    Generating good, clear and helpful error messages and warnings is
    /really/ difficult. It is typically harder for compilers than merely generating correct object code for correct source code.

    And they also make the code requirements a lot clearer to human readers.
    They let you specify your classes and functions better, in code rather
    than in comments (since comments are often out of sync with the code).


    They also allow neater and clearer code with constrained auto
    declarations, letting you specify something between "this /exact/ type"
    and "whatever seems to fit".

    Don't use auto in those scenarios then. Its always nicer when people put
    the specific type in the code anyway.


    No, it is not always nicer. It is /sometimes/ nicer. At other times,
    type inference is nicer - especially in templates. Constrained type
    inference can be nicer still.


    I am not suggesting that concepts always result in clearer error
    messages, or that they mean compilers don't have to improve their
    messages. I am not suggesting that they should be used for every
    declaration, or at every opportunity.

    I am merely saying that they give you another useful tool that can aid
    writing good, clear code, and getting good help from your tools.

    (And I am not in any way trying to defend Bonita's code style!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to [email protected] on Wed Sep 25 13:11:44 2024
    On Wed, 25 Sep 2024 08:24:19 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 09:49:49 +0200
    David Brown <[email protected]> boringly babbled:
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to list


    It knows what line invoked the error so all it needs to do is print
    that.

    Using concepts, however, means the error is found on the first
    attempt to use the type "A<T>" - the compiler can give far clearer >information. It can say "On line x, you tried to make A<T>, but type
    T does not fulfil the requirement you gave on line y when you
    defined class A".

    Tbh if you want to massage templating that much then don't use it in
    the first place, just hard code the functions.

    Competition is a great thing). And you sometimes want more
    information, sometimes less. But concepts give the programmer and
    the compiler a far better starting point.

    This is where compiler command line switches should come into play.

    They also allow neater and clearer code with constrained auto
    declarations, letting you specify something between "this /exact/
    type" and "whatever seems to fit".

    Don't use auto in those scenarios then. Its always nicer when people
    put the specific type in the code anyway.


    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not
    satisfactory.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Michael S on Wed Sep 25 13:52:51 2024
    On 25.09.2024 13:31, Michael S wrote:
    Below is an example of even more likely user mistake.
    gcc generated 63 lines of errors, MSVC produced 69 lines and clang
    had beaten both of them with 217 lines!
    Even if, by chance, one or two of the messages make sense, they are
    well hidden in piles of garbage.

    void my_sort3(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t* a, uint8_t *b) {
    return tab[*a] < tab[*b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, cmp);
    }


    VStudio 2022 gives pretty clear error messages: cannot convert from an
    integer to a pointer, when calling operator():

    Build started at 13:49...
    ------ Build started: Project: ConsoleTest2022, Configuration: Debug
    x64 ------
    main.cpp
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\xutility(1501,14): error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t
    *,uint8_t *)': cannot convert argument 1 from 'unsigned char' to 'uint8_t *' 1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\algorithm(8068,16): error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t
    *,uint8_t *)': cannot convert argument 1 from 'uint8_t' to 'uint8_t *' 1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\algorithm(8072,76): error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t
    *,uint8_t *)': cannot convert argument 1 from 'uint8_t' to 'uint8_t *' 1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\algorithm(8083,24): error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t
    *,uint8_t *)': cannot convert argument 1 from 'uint8_t' to 'uint8_t *' 1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\algorithm(8097,24): error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t
    *,uint8_t *)': cannot convert argument 1 from 'uint8_t' to 'uint8_t *'
    Done building project "ConsoleTest2022.vcxproj" -- FAILED.
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== ========== Build completed at 13:49 and took 00,390 seconds ==========

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 11:12:45 2024
    On Wed, 25 Sep 2024 13:11:44 +0300
    Michael S <[email protected]> boringly babbled:
    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not >satisfactory.

    My version of Clang produced 305 lines of output. Yet right at the top:

    t.cc:13:3: warning: template argument uses local type '(unnamed struct at t.cc:6
    :3)' [-Wlocal-type-template-args]
    std::sort(buf, buf+buflen, &cmp);

    Which is all it needed to print. The other 304 lines of garbage could have
    been reserved for the -Wall option.

    For some reason Bonita finds this concept (pun intended) had to understand.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Michael S on Wed Sep 25 13:31:34 2024
    On Wed, 25 Sep 2024 13:11:44 +0300
    Michael S <[email protected]> wrote:

    On Wed, 25 Sep 2024 08:24:19 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 09:49:49 +0200
    David Brown <[email protected]> boringly babbled:
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to list


    It knows what line invoked the error so all it needs to do is print
    that.

    Using concepts, however, means the error is found on the first
    attempt to use the type "A<T>" - the compiler can give far clearer >information. It can say "On line x, you tried to make A<T>, but
    type T does not fulfil the requirement you gave on line y when you >defined class A".

    Tbh if you want to massage templating that much then don't use it in
    the first place, just hard code the functions.

    Competition is a great thing). And you sometimes want more
    information, sometimes less. But concepts give the programmer and
    the compiler a far better starting point.

    This is where compiler command line switches should come into play.

    They also allow neater and clearer code with constrained auto >declarations, letting you specify something between "this /exact/
    type" and "whatever seems to fit".

    Don't use auto in those scenarios then. Its always nicer when people
    put the specific type in the code anyway.


    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not satisfactory.




    Below is an example of even more likely user mistake.
    gcc generated 63 lines of errors, MSVC produced 69 lines and clang
    had beaten both of them with 217 lines!
    Even if, by chance, one or two of the messages make sense, they are
    well hidden in piles of garbage.

    void my_sort3(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t* a, uint8_t *b) {
    return tab[*a] < tab[*b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, cmp);
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Paavo Helde on Wed Sep 25 14:06:49 2024
    On Wed, 25 Sep 2024 13:52:51 +0300
    Paavo Helde <[email protected]> wrote:

    On 25.09.2024 13:31, Michael S wrote:
    Below is an example of even more likely user mistake.
    gcc generated 63 lines of errors, MSVC produced 69 lines and clang
    had beaten both of them with 217 lines!
    Even if, by chance, one or two of the messages make sense, they are
    well hidden in piles of garbage.

    void my_sort3(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t* a, uint8_t *b) {
    return tab[*a] < tab[*b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, cmp);
    }


    VStudio 2022 gives pretty clear error messages: cannot convert from
    an integer to a pointer, when calling operator():

    Build started at 13:49...
    ------ Build started: Project: ConsoleTest2022, Configuration:
    Debug
    x64 ------
    main.cpp
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\xutility(1501,14): error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t *,uint8_t *)': cannot convert argument 1 from 'unsigned char' to
    'uint8_t *'
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\algorithm(8068,16):
    error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t *,uint8_t *)': cannot convert argument 1 from 'uint8_t' to 'uint8_t *' 1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\algorithm(8072,76):
    error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t *,uint8_t *)': cannot convert argument 1 from 'uint8_t' to 'uint8_t *' 1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\algorithm(8083,24):
    error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t *,uint8_t *)': cannot convert argument 1 from 'uint8_t' to 'uint8_t *' 1>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\algorithm(8097,24):
    error C2664: 'bool my_sort3::<unnamed-type-cmp>::operator ()(uint8_t *,uint8_t *)': cannot convert argument 1 from 'uint8_t' to 'uint8_t *'
    Done building project "ConsoleTest2022.vcxproj" -- FAILED.
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped
    ========== ========== Build completed at 13:49 and took 00,390
    seconds ==========


    I was testing with MSVC compiler/headers from VS2019
    It produces this message as well, but only on 28th line. In my
    experience it means that typical reader will give up earlier.
    In your part of the world it could be different :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 11:15:02 2024
    On Wed, 25 Sep 2024 11:32:56 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 10:24 schrieb [email protected]:

    Tbh if you want to massage templating that much then don't use it in the
    first place, just hard code the functions.

    To avoid concepts ? LOL.

    This is where compiler command line switches should come into play.

    Without concepts the compiler has no other choice than giving Swahili
    error messages from inside the implementation.

    Don't use auto in those scenarios then. Its always nicer when people put
    the specific type in the code anyway.

    auto-parameters *with* concepts become much cleaner than without.
    There's no choice to hardcode sth. then because you want to be generic.

    Generic is only needed if you're writing a library for others to use. If
    you're writing a self contained program its nothing more than a shortcut so
    in that instance if it causes issues then hard code the functions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to [email protected] on Wed Sep 25 14:30:21 2024
    On Wed, 25 Sep 2024 11:12:45 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 13:11:44 +0300
    Michael S <[email protected]> boringly babbled:
    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not >satisfactory.

    My version of Clang produced 305 lines of output. Yet right at the
    top:

    t.cc:13:3: warning: template argument uses local type '(unnamed
    struct at t.cc:6 :3)' [-Wlocal-type-template-args]
    std::sort(buf, buf+buflen, &cmp);

    Which is all it needed to print. The other 304 lines of garbage could
    have been reserved for the -Wall option.


    First, it's warning, not error.
    Second, I don't know about you, but I personally have no idea what
    is 'local type' and why it possibly could be a problem.
    Even if the warning is somehow related to actual bug, which I doubt, the relationship is far from obvious.

    For some reason Bonita finds this concept (pun intended) had to
    understand.


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Bonita Montero on Wed Sep 25 14:38:58 2024
    On Wed, 25 Sep 2024 13:33:50 +0200
    Bonita Montero <[email protected]> wrote:

    Am 25.09.2024 um 12:11 schrieb Michael S:

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    How about this ?

    void my_sort2 ( uint8_t *buf, int buflen, const uint8_t *trans_tab )
    {
    sort( buf, buf + buflen, [tab = trans_tab]( uint8_t l,
    uint8_t r ) { return tab[l] < tab[r]; } );
    }

    Your post is off topic.
    To remind you, the topic is unsatisfactory error reporting of "classic" non-conceptualized templates, esp. of those in STL.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Wed Sep 25 14:00:22 2024
    On 25/09/2024 13:15, [email protected] wrote:
    On Wed, 25 Sep 2024 11:32:56 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 10:24 schrieb [email protected]:

    Tbh if you want to massage templating that much then don't use it in the >>> first place, just hard code the functions.

    To avoid concepts ? LOL.

    This is where compiler command line switches should come into play.

    Without concepts the compiler has no other choice than giving Swahili
    error messages from inside the implementation.

    Don't use auto in those scenarios then. Its always nicer when people put >>> the specific type in the code anyway.

    auto-parameters *with* concepts become much cleaner than without.
    There's no choice to hardcode sth. then because you want to be generic.

    Generic is only needed if you're writing a library for others to use. If you're writing a self contained program its nothing more than a shortcut so in that instance if it causes issues then hard code the functions.


    I use generic code regularly in my small-systems embedded programming.
    Rather than using run-time class hierarchies with virtual functions and run-time polymorphic code, I use compile-time class hierarchies and
    generic functions. This means more information can be tied to the types
    of objects, resulting in minimal object code and maximal efficiency
    without having to duplicate the source code.

    Of course it has its limitations - the function definition for templates
    has to be seen at compile-time, so headers are bigger and compile and
    link times are slower, debugging can be more awkward, and it is only appropriate for some code.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Wed Sep 25 13:49:26 2024
    On 25/09/2024 12:11, Michael S wrote:
    On Wed, 25 Sep 2024 08:24:19 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 09:49:49 +0200
    David Brown <[email protected]> boringly babbled:
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to list


    It knows what line invoked the error so all it needs to do is print
    that.

    Using concepts, however, means the error is found on the first
    attempt to use the type "A<T>" - the compiler can give far clearer
    information. It can say "On line x, you tried to make A<T>, but type
    T does not fulfil the requirement you gave on line y when you
    defined class A".

    Tbh if you want to massage templating that much then don't use it in
    the first place, just hard code the functions.

    Competition is a great thing). And you sometimes want more
    information, sometimes less. But concepts give the programmer and
    the compiler a far better starting point.

    This is where compiler command line switches should come into play.

    They also allow neater and clearer code with constrained auto
    declarations, letting you specify something between "this /exact/
    type" and "whatever seems to fit".

    Don't use auto in those scenarios then. Its always nicer when people
    put the specific type in the code anyway.


    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not satisfactory.




    This is a rough attempt at using concepts here. I made an "xsort"
    template that checks (at compile time, obviously) a requirement and
    otherwise passes things on to std::sort. The "ComparisonFunctionObject" concept checks that you can call the object with two values of a given
    type and get a result that can be converted to a bool. The requirement
    for the Compare parameter to xsort is that this concept must be
    satisfied with the type you get from dereferencing the iterators.

    The error messages you get are a lot shorter and clearer. There's still
    room for improvement, as always, but it is a /big/ step forward.

    If you think a particular kind of error - such as using a pointer to the comparison function object instead of the object itself - is common, you
    can add extra checks to make the errors even clearer.

    <https://godbolt.org/z/jzqeh8enG>




    #include <concepts>
    #include <type_traits>
    #include <cstdint>
    #include <algorithm>


    template <class T>
    concept Not_pointer = !std::is_pointer_v<T>;

    template<class Compare, class T>
    concept ComparisonFunctionObject = requires (T a, T b)
    {
    { Compare()(a, b) } -> std::convertible_to<bool>;
    };


    template< class RandomIt, class Compare >
    requires
    #if 1 // <- Change this
    Not_pointer<Compare> &&
    #endif
    ComparisonFunctionObject<Compare, std::remove_pointer_t<RandomIt> >
    void xsort( RandomIt first, RandomIt last, Compare comp ) {
    std::sort(first, last, comp);
    }

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;

    xsort(buf, buf+buflen, cmp);
    xsort(buf, buf+buflen, &cmp);
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Wed Sep 25 14:22:35 2024
    On 25/09/2024 13:06, Michael S wrote:

    I was testing with MSVC compiler/headers from VS2019
    It produces this message as well, but only on 28th line. In my
    experience it means that typical reader will give up earlier.
    In your part of the world it could be different :-)


    This might depend on your build environment. Sometimes what you see
    most easily is the last page of error messages, rather than the first
    page. (Of course it is easiest if there is no more than a single page
    or screenful of messages!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Wed Sep 25 14:36:49 2024
    On 25/09/2024 13:45, Bonita Montero wrote:
    Am 25.09.2024 um 13:38 schrieb Michael S:
    On Wed, 25 Sep 2024 13:33:50 +0200
    Bonita Montero <[email protected]> wrote:

    Am 25.09.2024 um 12:11 schrieb Michael S:

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
        struct {
          const uint8_t* tab;
          bool operator() (uint8_t a, uint8_t b) {
            return tab[a] < tab[b];
          }
        } cmp;
        cmp.tab = trans_tab;
        std::sort(buf, buf+buflen, &cmp);
    }

    How about this ?

    void my_sort2 ( uint8_t *buf, int buflen, const uint8_t *trans_tab )
    {
        sort( buf, buf + buflen, [tab = trans_tab]( uint8_t l,
    uint8_t r ) { return tab[l] < tab[r]; } );
    }

    Your post is off topic.
    To remind you, the topic is unsatisfactory error reporting of "classic"
    non-conceptualized templates, esp. of those in STL.



    The topic develops with each step in the thread.
    That's true for most of those large threads.


    That's reasonable if you have something useful to say. Telling people
    that they can use lambdas here is /not/ useful. We all know we could
    use lambdas, but that is totally missing the point of the discussion.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Wed Sep 25 14:34:53 2024
    On 25/09/2024 13:30, Michael S wrote:
    On Wed, 25 Sep 2024 11:12:45 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 13:11:44 +0300
    Michael S <[email protected]> boringly babbled:
    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not
    satisfactory.

    My version of Clang produced 305 lines of output. Yet right at the
    top:

    t.cc:13:3: warning: template argument uses local type '(unnamed
    struct at t.cc:6 :3)' [-Wlocal-type-template-args]
    std::sort(buf, buf+buflen, &cmp);

    Which is all it needed to print. The other 304 lines of garbage could
    have been reserved for the -Wall option.


    First, it's warning, not error.
    Second, I don't know about you, but I personally have no idea what
    is 'local type' and why it possibly could be a problem.

    The "struct {...} cmp" here is a local (anonymous) type. The use of
    such types in template arguments might lead to code bloat, as it would
    be hard to merge the generated template function instantiations later on
    if you have used basically the same local structs multiple times. It's
    a stylistic thing which some people might find useful. But it has
    absolutely /nothing/ to do with the intentional bug in your code.

    Even if the warning is somehow related to actual bug, which I doubt, the relationship is far from obvious.

    For some reason Bonita finds this concept (pun intended) had to
    understand.



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Wed Sep 25 15:17:23 2024
    On Wed, 25 Sep 2024 13:49:26 +0200
    David Brown <[email protected]> wrote:

    On 25/09/2024 12:11, Michael S wrote:
    On Wed, 25 Sep 2024 08:24:19 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 09:49:49 +0200
    David Brown <[email protected]> boringly babbled:
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to
    list

    It knows what line invoked the error so all it needs to do is print
    that.

    Using concepts, however, means the error is found on the first
    attempt to use the type "A<T>" - the compiler can give far clearer
    information. It can say "On line x, you tried to make A<T>, but
    type T does not fulfil the requirement you gave on line y when you
    defined class A".

    Tbh if you want to massage templating that much then don't use it
    in the first place, just hard code the functions.

    Competition is a great thing). And you sometimes want more
    information, sometimes less. But concepts give the programmer and
    the compiler a far better starting point.

    This is where compiler command line switches should come into play.

    They also allow neater and clearer code with constrained auto
    declarations, letting you specify something between "this /exact/
    type" and "whatever seems to fit".

    Don't use auto in those scenarios then. Its always nicer when
    people put the specific type in the code anyway.


    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not satisfactory.




    This is a rough attempt at using concepts here. I made an "xsort"
    template that checks (at compile time, obviously) a requirement and
    otherwise passes things on to std::sort. The
    "ComparisonFunctionObject" concept checks that you can call the
    object with two values of a given type and get a result that can be
    converted to a bool. The requirement for the Compare parameter to
    xsort is that this concept must be satisfied with the type you get
    from dereferencing the iterators.

    The error messages you get are a lot shorter and clearer. There's
    still room for improvement, as always, but it is a /big/ step forward.

    If you think a particular kind of error - such as using a pointer to
    the comparison function object instead of the object itself - is
    common, you can add extra checks to make the errors even clearer.

    <https://godbolt.org/z/jzqeh8enG>




    #include <concepts>
    #include <type_traits>
    #include <cstdint>
    #include <algorithm>


    template <class T>
    concept Not_pointer = !std::is_pointer_v<T>;

    template<class Compare, class T>
    concept ComparisonFunctionObject = requires (T a, T b)
    {
    { Compare()(a, b) } -> std::convertible_to<bool>;
    };


    template< class RandomIt, class Compare >
    requires
    #if 1 // <- Change this
    Not_pointer<Compare> &&
    #endif
    ComparisonFunctionObject<Compare,
    std::remove_pointer_t<RandomIt> > void xsort( RandomIt first,
    RandomIt last, Compare comp ) { std::sort(first, last, comp);
    }

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;

    xsort(buf, buf+buflen, cmp);
    xsort(buf, buf+buflen, &cmp);
    }





    Interesting attempt, but not good enough. It fails in most common
    use case where Compare is function rather than object.

    bool cmp3(uint8_t a, uint8_t b) {
    return a < b;
    }
    void my_sort3(uint8_t* buf, int buflen, const uint8_t* )
    {
    #if 1
    xsort(buf, buf+buflen, cmp3);
    #else
    std::sort(buf, buf+buflen, cmp3);
    #endif
    }

    STL's insistence on [mis]use of static polymorphism in every possible
    and impossible hole strikes again!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Wed Sep 25 14:38:18 2024
    On 25/09/2024 14:03, Bonita Montero wrote:
    Am 25.09.2024 um 13:49 schrieb David Brown:

    template<class Compare, class T>
    concept ComparisonFunctionObject = requires (T a, T b)
    {
         { Compare()(a, b) } -> std::convertible_to<bool>;
    };

    This may fail with a lambda with capture, since the lambda isn't default-constructible but just moveable or copyable. So it should
    look like this:

    template<class Compare, class T>
    concept ComparisonFunctionObject = requires (Compare cmp, T a, T b)
    {
        { cmp(a, b) } -> std::convertible_to<bool>;
    };


    Yes, that is better.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 12:47:26 2024
    On Wed, 25 Sep 2024 14:00:22 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 13:15, [email protected] wrote:
    Generic is only needed if you're writing a library for others to use. If
    you're writing a self contained program its nothing more than a shortcut so >> in that instance if it causes issues then hard code the functions.


    I use generic code regularly in my small-systems embedded programming.
    Rather than using run-time class hierarchies with virtual functions and >run-time polymorphic code, I use compile-time class hierarchies and
    generic functions. This means more information can be tied to the types
    of objects, resulting in minimal object code and maximal efficiency
    without having to duplicate the source code.

    Can't imagine why you'd need any of that in small systems embedded as the
    size of programs you can fit into memory constrains the structural complexity. If you need class inheritance in something that has to fit into 16K or
    whatever then you're doing it wrong.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 12:40:53 2024
    On Wed, 25 Sep 2024 14:30:21 +0300
    Michael S <[email protected]> boringly babbled:
    On Wed, 25 Sep 2024 11:12:45 -0000 (UTC)
    [email protected] wrote:
    My version of Clang produced 305 lines of output. Yet right at the
    top:

    t.cc:13:3: warning: template argument uses local type '(unnamed
    struct at t.cc:6 :3)' [-Wlocal-type-template-args]
    std::sort(buf, buf+buflen, &cmp);

    Which is all it needed to print. The other 304 lines of garbage could
    have been reserved for the -Wall option.


    First, it's warning, not error.

    It leads to an error should it just just error there and quit.

    Second, I don't know about you, but I personally have no idea what
    is 'local type' and why it possibly could be a problem.

    Well the compiler clearly does so there's no reason the compiler devs couldn't have been more specific.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 12:43:03 2024
    On Wed, 25 Sep 2024 13:30:05 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 13:15 schrieb [email protected]:

    Generic is only needed if you're writing a library for others to use.

    I often write generic code that I use myself in different ways,
    each specialized to a set of generic types. I think that's much
    more common than that someone implements a generic API for use
    by the public.
    F.e. this code is a function which concatenates anything which
    can be converted to a basic_string_view to a corrsponding string
    with same char- and traits-tyme.

    Looks like a library function to me albeit only you use. I doubt you'd only
    use it in one program.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Michael S on Wed Sep 25 15:49:15 2024
    On 25.09.2024 15:17, Michael S wrote:
    On Wed, 25 Sep 2024 13:49:26 +0200
    David Brown <[email protected]> wrote:

    On 25/09/2024 12:11, Michael S wrote:
    On Wed, 25 Sep 2024 08:24:19 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 09:49:49 +0200
    David Brown <[email protected]> boringly babbled:
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to
    list

    It knows what line invoked the error so all it needs to do is print
    that.

    Using concepts, however, means the error is found on the first
    attempt to use the type "A<T>" - the compiler can give far clearer
    information. It can say "On line x, you tried to make A<T>, but
    type T does not fulfil the requirement you gave on line y when you
    defined class A".

    Tbh if you want to massage templating that much then don't use it
    in the first place, just hard code the functions.

    Competition is a great thing). And you sometimes want more
    information, sometimes less. But concepts give the programmer and
    the compiler a far better starting point.

    This is where compiler command line switches should come into play.

    They also allow neater and clearer code with constrained auto
    declarations, letting you specify something between "this /exact/
    type" and "whatever seems to fit".

    Don't use auto in those scenarios then. Its always nicer when
    people put the specific type in the code anyway.


    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not
    satisfactory.




    This is a rough attempt at using concepts here. I made an "xsort"
    template that checks (at compile time, obviously) a requirement and
    otherwise passes things on to std::sort. The
    "ComparisonFunctionObject" concept checks that you can call the
    object with two values of a given type and get a result that can be
    converted to a bool. The requirement for the Compare parameter to
    xsort is that this concept must be satisfied with the type you get
    from dereferencing the iterators.

    The error messages you get are a lot shorter and clearer. There's
    still room for improvement, as always, but it is a /big/ step forward.

    If you think a particular kind of error - such as using a pointer to
    the comparison function object instead of the object itself - is
    common, you can add extra checks to make the errors even clearer.

    <https://godbolt.org/z/jzqeh8enG>




    #include <concepts>
    #include <type_traits>
    #include <cstdint>
    #include <algorithm>


    template <class T>
    concept Not_pointer = !std::is_pointer_v<T>;

    template<class Compare, class T>
    concept ComparisonFunctionObject = requires (T a, T b)
    {
    { Compare()(a, b) } -> std::convertible_to<bool>;
    };


    template< class RandomIt, class Compare >
    requires
    #if 1 // <- Change this
    Not_pointer<Compare> &&
    #endif
    ComparisonFunctionObject<Compare,
    std::remove_pointer_t<RandomIt> > void xsort( RandomIt first,
    RandomIt last, Compare comp ) { std::sort(first, last, comp);
    }

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;

    xsort(buf, buf+buflen, cmp);
    xsort(buf, buf+buflen, &cmp);
    }





    Interesting attempt, but not good enough. It fails in most common
    use case where Compare is function rather than object.

    Callback functions are a C thing. In C++ we have functors and lambdas.
    Over the years I have removed all ancient callback functions from my
    code and replaced by functors or lambdas, so your "most common use case"
    is not everybody's use case.

    In this example (a one-line sort helper) a lambda is the superior
    solution anyway.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 12:55:35 2024
    On Wed, 25 Sep 2024 15:49:15 +0300
    Paavo Helde <[email protected]> boringly babbled:
    Callback functions are a C thing. In C++ we have functors and lambdas.
    Over the years I have removed all ancient callback functions from my
    code and replaced by functors or lambdas, so your "most common use case"

    What for? They usually compile down to the same code at the end and lambdas
    are only useful if that function is only used in that one place. If its used more than once then a function pointer is more useful and neater.

    In this example (a one-line sort helper) a lambda is the superior
    solution anyway.

    Why?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Wed Sep 25 14:58:51 2024
    On 25/09/2024 14:17, Michael S wrote:
    On Wed, 25 Sep 2024 13:49:26 +0200
    David Brown <[email protected]> wrote:

    On 25/09/2024 12:11, Michael S wrote:
    On Wed, 25 Sep 2024 08:24:19 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 09:49:49 +0200
    David Brown <[email protected]> boringly babbled:
    looks up. The error message is likely to be complex because the
    compiler doesn't know where you made the mistake, and tries to
    list

    It knows what line invoked the error so all it needs to do is print
    that.

    Using concepts, however, means the error is found on the first
    attempt to use the type "A<T>" - the compiler can give far clearer
    information. It can say "On line x, you tried to make A<T>, but
    type T does not fulfil the requirement you gave on line y when you
    defined class A".

    Tbh if you want to massage templating that much then don't use it
    in the first place, just hard code the functions.

    Competition is a great thing). And you sometimes want more
    information, sometimes less. But concepts give the programmer and
    the compiler a far better starting point.

    This is where compiler command line switches should come into play.

    They also allow neater and clearer code with constrained auto
    declarations, letting you specify something between "this /exact/
    type" and "whatever seems to fit".

    Don't use auto in those scenarios then. Its always nicer when
    people put the specific type in the code anyway.


    Below is example of very simple function with very small
    template-related bug of sort that people sometimes do in real life.
    I tried 3 compilers. Each one produces more than 20 lines of error
    messages none of which was enlightening.

    #include <cstdint>
    #include <algorithm>

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;
    std::sort(buf, buf+buflen, &cmp);
    }

    I don't know if with conceptized <algorithm> error reporting would
    work better. But it is worth a try, because current state is not
    satisfactory.




    This is a rough attempt at using concepts here. I made an "xsort"
    template that checks (at compile time, obviously) a requirement and
    otherwise passes things on to std::sort. The
    "ComparisonFunctionObject" concept checks that you can call the
    object with two values of a given type and get a result that can be
    converted to a bool. The requirement for the Compare parameter to
    xsort is that this concept must be satisfied with the type you get
    from dereferencing the iterators.

    The error messages you get are a lot shorter and clearer. There's
    still room for improvement, as always, but it is a /big/ step forward.

    If you think a particular kind of error - such as using a pointer to
    the comparison function object instead of the object itself - is
    common, you can add extra checks to make the errors even clearer.

    <https://godbolt.org/z/jzqeh8enG>




    #include <concepts>
    #include <type_traits>
    #include <cstdint>
    #include <algorithm>


    template <class T>
    concept Not_pointer = !std::is_pointer_v<T>;

    template<class Compare, class T>
    concept ComparisonFunctionObject = requires (T a, T b)
    {
    { Compare()(a, b) } -> std::convertible_to<bool>;
    };


    template< class RandomIt, class Compare >
    requires
    #if 1 // <- Change this
    Not_pointer<Compare> &&
    #endif
    ComparisonFunctionObject<Compare,
    std::remove_pointer_t<RandomIt> > void xsort( RandomIt first,
    RandomIt last, Compare comp ) { std::sort(first, last, comp);
    }

    void my_sort2(uint8_t* buf, int buflen, const uint8_t* trans_tab)
    {
    struct {
    const uint8_t* tab;
    bool operator() (uint8_t a, uint8_t b) {
    return tab[a] < tab[b];
    }
    } cmp;
    cmp.tab = trans_tab;

    xsort(buf, buf+buflen, cmp);
    xsort(buf, buf+buflen, &cmp);
    }





    Interesting attempt, but not good enough. It fails in most common
    use case where Compare is function rather than object.

    bool cmp3(uint8_t a, uint8_t b) {
    return a < b;
    }
    void my_sort3(uint8_t* buf, int buflen, const uint8_t* )
    {
    #if 1
    xsort(buf, buf+buflen, cmp3);
    #else
    std::sort(buf, buf+buflen, cmp3);
    #endif
    }

    STL's insistence on [mis]use of static polymorphism in every possible
    and impossible hole strikes again!


    With Bonita's correction to the ComparisonFunctionObject concept:

    template<class Compare, class T>
    concept ComparisonFunctionObject = requires (Compare cmp, T a, T b)
    {
    { cmp(a, b) } -> std::convertible_to<bool>;
    };


    and the removable of the "Not_pointer" check, the concept works as intended.

    (The Not_pointer concept could be modified to allow pointers to
    functions and lambdas, but by then its purpose is lost and it should be removed.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Wed Sep 25 15:04:27 2024
    On 25/09/2024 14:39, Bonita Montero wrote:
    Am 25.09.2024 um 14:36 schrieb David Brown:

    That's reasonable if you have something useful to say.  Telling people
    that they can use lambdas here is /not/ useful.  We all know we could
    use lambdas, but that is totally missing the point of the discussion.

    I guess Michael S doesn't know this, otherwrite he would have used
    a lambda himself. That's pre-C++11-style and maybe his knowledge is
    from then.


    Seriously? Sometimes I wonder if you ever bother reading other people's
    posts.

    Of /course/ Michael knows he could use a lambda there. He was not
    writing code for a sorting function - he was writing a constructed code
    snippet to show that template usage can lead to excessive error
    messages, and was asking if concepts could be used to reduce that
    challenge when using real-world compilers. It was a fine example for
    the purpose.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Wed Sep 25 15:00:20 2024
    On 25/09/2024 14:47, [email protected] wrote:
    On Wed, 25 Sep 2024 14:00:22 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 13:15, [email protected] wrote:
    Generic is only needed if you're writing a library for others to use. If >>> you're writing a self contained program its nothing more than a shortcut so >>> in that instance if it causes issues then hard code the functions.


    I use generic code regularly in my small-systems embedded programming.
    Rather than using run-time class hierarchies with virtual functions and
    run-time polymorphic code, I use compile-time class hierarchies and
    generic functions. This means more information can be tied to the types
    of objects, resulting in minimal object code and maximal efficiency
    without having to duplicate the source code.

    Can't imagine why you'd need any of that in small systems embedded as the size of programs you can fit into memory constrains the structural complexity.
    If you need class inheritance in something that has to fit into 16K or whatever then you're doing it wrong.


    That is just because you can't imagine.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Wed Sep 25 15:01:15 2024
    On 25/09/2024 14:38, Bonita Montero wrote:
    Am 25.09.2024 um 14:34 schrieb David Brown:

    The "struct {...} cmp" here is a local (anonymous) type.  The use of
    such types in template arguments might lead to code bloat, as it would
    be hard to merge the generated template function instantiations later
    on if you have used basically the same local structs multiple times.

    This "bloat" actually doesn't hurt since the sort()-function has enough locality in itself.


    Sure. But I believe that is the reasoning behind this particular clang
    warning flag, and I'm sure some people find it useful for some kinds of
    code or particular choices of style rules.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Paavo Helde on Wed Sep 25 15:07:26 2024
    On 25/09/2024 14:49, Paavo Helde wrote:
    On 25.09.2024 15:17, Michael S wrote:

    Interesting attempt, but not good enough. It fails in most common
    use case where Compare is function rather than object.

    Callback functions are a C thing. In C++ we have functors and lambdas.
    Over the years I have removed all ancient callback functions from my
    code and replaced by functors or lambdas, so your "most common use case"
    is not everybody's use case.

    In this example (a one-line sort helper) a lambda is the superior
    solution anyway.


    As with Bonita, you are missing the point completely and stating the
    obvious (at least, obvious to experienced C++ programmers). This code
    was not for finding the most elegant way to call "sort", but to consider
    if concepts can make error messages clearer for some template mistakes
    without limiting various types of correct usage.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to [email protected] on Wed Sep 25 16:22:43 2024
    On 25.09.2024 15:55, [email protected] wrote:
    On Wed, 25 Sep 2024 15:49:15 +0300
    Paavo Helde <[email protected]> boringly babbled:
    Callback functions are a C thing. In C++ we have functors and lambdas.
    Over the years I have removed all ancient callback functions from my
    code and replaced by functors or lambdas, so your "most common use case"

    What for? They usually compile down to the same code at the end and lambdas are only useful if that function is only used in that one place. If its used more than once then a function pointer is more useful and neater.

    One can pack state with a lambda. With a callback function one needs to
    pass state via an extra parameter, which is clumsy, error-prone and is
    not supported by STL.

    If you want reuse, you can call a common function from the lambda, it's
    not like this is prohibited or something.

    In this example (a one-line sort helper) a lambda is the superior
    solution anyway.

    Why?

    Because the sorting criteria is right there in the code where the
    sorting happens, and one also avoids one of the two most hard problems
    in computer science (naming things - https://martinfowler.com/bliki/TwoHardThings.html).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 13:24:26 2024
    On Wed, 25 Sep 2024 15:08:09 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 14:55 schrieb [email protected]:

    What for? They usually compile down to the same code at the end and lambdas >> are only useful if that function is only used in that one place. If its used >> more than once then a function pointer is more useful and neater.

    Usually you have state along with your function-object, this can't be

    Rarely used. Eg sorting functor for STL containers.

    attached conveniently to a function-pointer. With lambdas that's easy,
    their state can be copied and moved.

    A lambda is just an inline function. Its syntatic sugar.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 13:22:46 2024
    On Wed, 25 Sep 2024 15:00:20 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 14:47, [email protected] wrote:
    On Wed, 25 Sep 2024 14:00:22 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 13:15, [email protected] wrote:
    Generic is only needed if you're writing a library for others to use. If >>>> you're writing a self contained program its nothing more than a shortcut so

    in that instance if it causes issues then hard code the functions.


    I use generic code regularly in my small-systems embedded programming.
    Rather than using run-time class hierarchies with virtual functions and
    run-time polymorphic code, I use compile-time class hierarchies and
    generic functions. This means more information can be tied to the types >>> of objects, resulting in minimal object code and maximal efficiency
    without having to duplicate the source code.

    Can't imagine why you'd need any of that in small systems embedded as the
    size of programs you can fit into memory constrains the structural >complexity.
    If you need class inheritance in something that has to fit into 16K or
    whatever then you're doing it wrong.


    That is just because you can't imagine.

    Funny. Misra-C++ is it? No? Then you're just playing with toys, not doing proper embedded.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 13:34:32 2024
    On Wed, 25 Sep 2024 16:22:43 +0300
    Paavo Helde <[email protected]> boringly babbled:
    On 25.09.2024 15:55, [email protected] wrote:
    On Wed, 25 Sep 2024 15:49:15 +0300
    Paavo Helde <[email protected]> boringly babbled:
    Callback functions are a C thing. In C++ we have functors and lambdas.
    Over the years I have removed all ancient callback functions from my
    code and replaced by functors or lambdas, so your "most common use case"

    What for? They usually compile down to the same code at the end and lambdas >> are only useful if that function is only used in that one place. If its used >> more than once then a function pointer is more useful and neater.

    One can pack state with a lambda. With a callback function one needs to
    pass state via an extra parameter, which is clumsy, error-prone and is

    You think that makes any difference at the assembler level?

    If you want reuse, you can call a common function from the lambda, it's
    not like this is prohibited or something.

    I'm not saying lambdas shouldn't be used, but I've seen a fair amount of
    code with the same lambda code being used in different functions instead of just writing one function and passing a function pointer. Its messy.

    In this example (a one-line sort helper) a lambda is the superior
    solution anyway.

    Why?

    Because the sorting criteria is right there in the code where the
    sorting happens, and one also avoids one of the two most hard problems
    in computer science (naming things - >https://martinfowler.com/bliki/TwoHardThings.html).

    Thats not why, thats "because I prefer it".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 14:11:44 2024
    On Wed, 25 Sep 2024 15:44:21 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 15:36 schrieb [email protected]:

    If you're writing C++ you're not doing functional programming, period.

    C++ supports functional programming since C++11, but doesn't mandate
    pure functional programming.

    Functional style programming != functional programming.

    Functional requires polymorphism by value which C++ does not support.

    Functional programming in C++ allows for compile-time polymporphism
    with generic function-objects and and runtime polymporphism with >std::function<>.

    Which part of polymorphism by value did you not understand?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 13:36:07 2024
    On Wed, 25 Sep 2024 15:28:15 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 15:24 schrieb [email protected]:
    On Wed, 25 Sep 2024 15:08:09 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 14:55 schrieb [email protected]:

    What for? They usually compile down to the same code at the end and lambdas

    are only useful if that function is only used in that one place. If its >used
    more than once then a function pointer is more useful and neater.

    Usually you have state along with your function-object, this can't be

    Rarely used. Eg sorting functor for STL containers.

    I'm using functional programmg all the day and most lambdss I write
    have state.

    If you're writing C++ you're not doing functional programming, period. Functional requires polymorphism by value which C++ does not support.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Wed Sep 25 17:14:38 2024
    On Wed, 25 Sep 2024 15:04:27 +0200
    David Brown <[email protected]> wrote:

    On 25/09/2024 14:39, Bonita Montero wrote:
    Am 25.09.2024 um 14:36 schrieb David Brown:

    That's reasonable if you have something useful to say.  Telling
    people that they can use lambdas here is /not/ useful.  We all
    know we could use lambdas, but that is totally missing the point
    of the discussion.

    I guess Michael S doesn't know this, otherwrite he would have used
    a lambda himself. That's pre-C++11-style and maybe his knowledge is
    from then.


    Seriously? Sometimes I wonder if you ever bother reading other
    people's posts.

    Of /course/ Michael knows he could use a lambda there.

    [O.T.]
    I know that they can be used, but I never use lambdas myself.
    Because of that my knowledge is theoretical and I am not fluent with
    syntax.

    Why I am not using lambdas myself? Because I think that lambda with
    captures makes code harder to follow and to understand (that's my 1st
    hand experience from reading big corpus of Ada83 code. Ada83 does not
    have lambdas, but it has nested procedures that can access parent's
    variable, similarly to lambda with [&] default capture).
    And lambda without captures does not provide enough of advantage over
    named functions to bother with mastering new concept.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to [email protected] on Wed Sep 25 17:16:46 2024
    On Wed, 25 Sep 2024 14:11:44 -0000 (UTC)
    [email protected] wrote:

    On Wed, 25 Sep 2024 15:44:21 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 15:36 schrieb [email protected]:

    If you're writing C++ you're not doing functional programming,
    period.

    C++ supports functional programming since C++11, but doesn't mandate
    pure functional programming.

    Functional style programming != functional programming.


    Don't be ridiculous.
    If you can.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Wed Sep 25 17:12:15 2024
    On 25/09/2024 15:22, [email protected] wrote:
    On Wed, 25 Sep 2024 15:00:20 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 14:47, [email protected] wrote:
    On Wed, 25 Sep 2024 14:00:22 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 13:15, [email protected] wrote:
    Generic is only needed if you're writing a library for others to use. If >>>>> you're writing a self contained program its nothing more than a shortcut so

    in that instance if it causes issues then hard code the functions.


    I use generic code regularly in my small-systems embedded programming. >>>> Rather than using run-time class hierarchies with virtual functions and >>>> run-time polymorphic code, I use compile-time class hierarchies and
    generic functions. This means more information can be tied to the types >>>> of objects, resulting in minimal object code and maximal efficiency
    without having to duplicate the source code.

    Can't imagine why you'd need any of that in small systems embedded as the >>> size of programs you can fit into memory constrains the structural
    complexity.
    If you need class inheritance in something that has to fit into 16K or
    whatever then you're doing it wrong.


    That is just because you can't imagine.

    Funny. Misra-C++ is it? No? Then you're just playing with toys, not doing proper embedded.


    If you think MISRA is required for embedded development, or even if you
    think it is a good idea that promotes safe and reliable coding, then you
    have little concept of the field. There are certainly markets where
    MISRA is strongly encouraged or even required, but that is all about
    legal arse-covering, not actual safety or reliability.

    And anyway, MISRA C++ is quite happy with templates and generic code.

    However, the last MISRA C++ version I have is from 2008, so perhaps in
    the they have decided to ban templates for MISRA C++ 2023 (covering
    C++17), though I strongly doubt it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Wed Sep 25 17:18:16 2024
    On 25/09/2024 16:23, Bonita Montero wrote:
    Am 25.09.2024 um 16:14 schrieb Michael S:

    I know that they can be used, but I never use lambdas myself.

    That's nearly the same as what I've said.

    In the sense that saying something completely different is "nearly" the
    same.

    You claimed Michael didn't know that he could use lambdas, otherwise he
    would have used them. It turns out that he /did/ know you could use a
    lambda, but intentionally did not - because using a lambda here would be
    worse than useless.


    Why I am not using lambdas myself? Because I think that lambda with
    captures makes code harder to follow and to understand (...).

    Lambdas are much less code and for me are therefore more readable.

    I agree that lambdas can be useful and make code clearer when used appropriately.

    But a lambda in Michael's example code would not have shown the issue he
    was demonstrating.


    And lambda without captures does not provide enough of advantage
    over named functions to bother with mastering new concept.
    Named functions haven't state.


    Again, your failure to read is obvious.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Wed Sep 25 17:27:12 2024
    On 25/09/2024 15:34, [email protected] wrote:
    On Wed, 25 Sep 2024 16:22:43 +0300
    Paavo Helde <[email protected]> boringly babbled:
    On 25.09.2024 15:55, [email protected] wrote:
    On Wed, 25 Sep 2024 15:49:15 +0300
    Paavo Helde <[email protected]> boringly babbled:
    Callback functions are a C thing. In C++ we have functors and lambdas. >>>> Over the years I have removed all ancient callback functions from my
    code and replaced by functors or lambdas, so your "most common use case" >>>
    What for? They usually compile down to the same code at the end and lambdas >>> are only useful if that function is only used in that one place. If its used
    more than once then a function pointer is more useful and neater.

    One can pack state with a lambda. With a callback function one needs to
    pass state via an extra parameter, which is clumsy, error-prone and is

    You think that makes any difference at the assembler level?


    Sometimes there is a difference, sometimes not.

    Typically if you compare a C-style callback function pointer with a
    void* parameter, to a C++ style function object (either an explicit
    class like Michael's example, or a lambda with capture), the C code will
    result in a single generic function while the C++ code will have
    multiple specialised functions for each type used. If you have lots of
    uses with different types, the C code will be smaller in total but
    slower, and if you only have one or a few types, the C++ code will be
    faster and smaller.

    But sometimes there is no significant difference in the results.


    However, the intention is to improve the source code, not just the
    generated object code.

    If you want reuse, you can call a common function from the lambda, it's
    not like this is prohibited or something.

    I'm not saying lambdas shouldn't be used, but I've seen a fair amount of
    code with the same lambda code being used in different functions instead of just writing one function and passing a function pointer. Its messy.


    There are no features that can't be misused or used to write messier code.

    In this example (a one-line sort helper) a lambda is the superior
    solution anyway.

    Why?

    Because the sorting criteria is right there in the code where the
    sorting happens, and one also avoids one of the two most hard problems
    in computer science (naming things -
    https://martinfowler.com/bliki/TwoHardThings.html).

    Thats not why, thats "because I prefer it".


    It seems to me to be a good reason why he prefers lambdas (in cases like
    this one - if the purpose of the code had been to do some sorting rather
    than to show how bad error messages can be).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 15:33:23 2024
    On Wed, 25 Sep 2024 16:14:28 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 16:11 schrieb [email protected]:
    On Wed, 25 Sep 2024 15:44:21 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 15:36 schrieb [email protected]:

    If you're writing C++ you're not doing functional programming, period.

    C++ supports functional programming since C++11, but doesn't mandate
    pure functional programming.

    Functional style programming != functional programming.

    You make up your own definitions so that
    you somehow feel like you were right.

    Which part of polymorphism by value did you not understand?

    I understand both types of polymorphism, you nothing.

    You don't have clue. This is the sort of thing I'm talking abouit:

    def main(argv) ->
    func("",["hello","cruel","world","this","is","a","test"])
    : 0
    ;

    def func(_,[]) -> "";

    def func(_,[head<tail]) -> printnl head,",",tail : func(head[0],tail);

    def func("world",[head<tail]) ->
    printnl "GOT WORLD" : func(head,tail);

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 15:49:15 2024
    On Wed, 25 Sep 2024 17:33:41 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 17:32 schrieb [email protected]:

    I understand both types of polymorphism, you nothing.

    You don't have clue. ...

    And you have your own definition of polymorphism.

    Thanks for proving my point. A proper functional language has value polymorphism (which clearly you don't understand) as well as type
    polymorphism.

    https://chrisdone.com/posts/value-polymorphism/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Sep 25 15:35:34 2024
    On Wed, 25 Sep 2024 17:12:15 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 15:22, [email protected] wrote:
    Funny. Misra-C++ is it? No? Then you're just playing with toys, not doing
    proper embedded.


    If you think MISRA is required for embedded development, or even if you
    think it is a good idea that promotes safe and reliable coding, then you
    have little concept of the field. There are certainly markets where

    I didn't embedded in the UK defense industry so I probably have a bit more of
    a clue than you piddling around with your arduino or PIC writing code for
    a toaster.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Wed Sep 25 19:19:24 2024
    On 25/09/2024 17:35, [email protected] wrote:
    On Wed, 25 Sep 2024 17:12:15 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 15:22, [email protected] wrote:
    Funny. Misra-C++ is it? No? Then you're just playing with toys, not doing >>> proper embedded.


    If you think MISRA is required for embedded development, or even if you
    think it is a good idea that promotes safe and reliable coding, then you
    have little concept of the field. There are certainly markets where

    I didn't embedded in the UK defense industry so I probably have a bit more of a clue than you piddling around with your arduino or PIC writing code for
    a toaster.


    You "didn't embedded in the UK defense industry" - that I believe.

    It's harder to believe that you /did/ work with embedded systems related
    to the UK defence industry. From my own experience, I know there are
    people in that field who are good at what they do, and others that go
    through the motions. And I know that arse-covering is often higher
    priority than actually trying to do good development - "You can't sue us
    for writing bad software, because we use industry standard MISRA rules".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Michael S on Wed Sep 25 21:24:42 2024
    On 25.09.2024 17:14, Michael S wrote:

    Why I am not using lambdas myself? Because I think that lambda with
    captures makes code harder to follow and to understand (that's my 1st
    hand experience from reading big corpus of Ada83 code. Ada83 does not
    have lambdas, but it has nested procedures that can access parent's
    variable, similarly to lambda with [&] default capture).

    That's why in production code one should generally not use lambda with
    the [&] or [=] blanket captures.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to [email protected] on Wed Sep 25 22:37:04 2024
    On 25.09.2024 16:34, [email protected] wrote:
    On Wed, 25 Sep 2024 16:22:43 +0300
    Paavo Helde <[email protected]> boringly babbled:
    On 25.09.2024 15:55, [email protected] wrote:
    On Wed, 25 Sep 2024 15:49:15 +0300
    Paavo Helde <[email protected]> boringly babbled:
    Callback functions are a C thing. In C++ we have functors and lambdas. >>>> Over the years I have removed all ancient callback functions from my
    code and replaced by functors or lambdas, so your "most common use case" >>>
    What for? They usually compile down to the same code at the end and lambdas >>> are only useful if that function is only used in that one place. If its used
    more than once then a function pointer is more useful and neater.

    One can pack state with a lambda. With a callback function one needs to
    pass state via an extra parameter, which is clumsy, error-prone and is

    You think that makes any difference at the assembler level?

    Why should it make any difference at the assembler level? Programming
    languages are meant for people, both for writing and reading the code.

    I agree that if someone is not familiar with C++ lambdas, one might feel themselves lost as they do not immediately understand what the code
    does. But this can be easily alleviated by spending 30 minutes for
    actually learning the lambda syntax.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to jseigh on Wed Sep 25 15:23:47 2024
    On 9/21/24 15:43, jseigh wrote:
    Trying to come up to speed on C++ concepts. If they're are useful
    why wouldn't they define named requirements as a concept, e.g.

    template<typename T>
    concept BasicLockable = requires(T a)
    {
        { a.lock() } -> std::same_as<void>;
        { a.unlock() } -> std::same_as<void>;
    };

    template<BasicLockable T>
    ...

    Ok, all good I think.

    The question of why wouldn't they define named requirements that
    way was about whether there was some technical reason for not
    doing that.

    On a different note, now that figured out how to abuse regular
    templates to insert arbitrary blocks of code where I want it
    I can try porting some performance testing code from C to C++,
    assuming I can reliably get it inlined. When you are testing
    code that takes 0.8 nsecs inlined and 2.4 nsecs when called,
    it does matter. Otherwise when you are comparing different
    implementations the call overhead is going to dominate and
    they are going to look the same performance wise.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Thu Sep 26 07:36:29 2024
    On Wed, 25 Sep 2024 19:19:24 +0200
    David Brown <[email protected]> boringly babbled:
    On 25/09/2024 17:35, [email protected] wrote:
    I didn't embedded in the UK defense industry so I probably have a bit more of

    a clue than you piddling around with your arduino or PIC writing code for
    a toaster.


    You "didn't embedded in the UK defense industry" - that I believe.
    It's harder to believe that you /did/ work with embedded systems related
    to the UK defence industry. From my own experience, I know there are

    Believe what you like matey. Misra-C and LDRA were the order of the day.

    priority than actually trying to do good development - "You can't sue us
    for writing bad software, because we use industry standard MISRA rules".

    Law isn't my area so no idea.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Thu Sep 26 07:34:51 2024
    On Wed, 25 Sep 2024 17:53:58 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 17:49 schrieb [email protected]:

    Thanks for proving my point. A proper functional language has
    value polymorphism (which clearly you don't understand) ...

    You've probably never dealt with std::function<> objects. That's
    value polymorphism! I use that all the dayd, f.e. with this function:

    [Usual unreadable mess snipped]

    You can pass a lambda to this function and the type-polymorphism
    becomes a value-polymophism.

    Oh dear. Thats not value polymorphism, thats a very complicated way of doing if-then.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Thu Sep 26 07:38:04 2024
    On Wed, 25 Sep 2024 22:37:04 +0300
    Paavo Helde <[email protected]> boringly babbled:
    On 25.09.2024 16:34, [email protected] wrote:
    On Wed, 25 Sep 2024 16:22:43 +0300
    Paavo Helde <[email protected]> boringly babbled:
    On 25.09.2024 15:55, [email protected] wrote:
    On Wed, 25 Sep 2024 15:49:15 +0300
    Paavo Helde <[email protected]> boringly babbled:
    Callback functions are a C thing. In C++ we have functors and lambdas. >>>>> Over the years I have removed all ancient callback functions from my >>>>> code and replaced by functors or lambdas, so your "most common use case" >>>>
    What for? They usually compile down to the same code at the end and lambdas

    are only useful if that function is only used in that one place. If its >used
    more than once then a function pointer is more useful and neater.

    One can pack state with a lambda. With a callback function one needs to
    pass state via an extra parameter, which is clumsy, error-prone and is

    You think that makes any difference at the assembler level?

    Why should it make any difference at the assembler level? Programming >languages are meant for people, both for writing and reading the code.

    I only mentioned it because efficiency was mentioned at one point.

    I agree that if someone is not familiar with C++ lambdas, one might feel >themselves lost as they do not immediately understand what the code
    does. But this can be easily alleviated by spending 30 minutes for
    actually learning the lambda syntax.

    The lambda syntax is another mess which only adds to the mess modern C++
    has become. I'm pretty sure they could have come up with something much
    tidier that doesn't look like the proverbial explosion in a typewriter
    factory.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to wij on Thu Sep 26 12:23:41 2024
    On Thu, 26 Sep 2024 16:46:08 +0800
    wij <[email protected]> wrote:

    On Thu, 2024-09-26 at 10:20 +0200, Bonita Montero wrote:
    Am 26.09.2024 um 09:34 schrieb [email protected]:
    On Wed, 25 Sep 2024 17:53:58 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 17:49 schrieb [email protected]:

    Thanks for proving my point. A proper functional language has
    value polymorphism (which clearly you don't understand) ...

    You've probably never dealt with std::function<> objects. That's
    value polymorphism! I use that all the dayd, f.e. with this
    function:

    [Usual unreadable mess snipped]

    My collegue calls my code "too beautiful".


    I would call "too academic" or too much brain-washed by c++std stuff.

    From the last time I saw your ring_deque, I found you don't understand
    what the ring buffer is. And, a for loop caught my attention, it
    should be like this (just a few from my memory, because I had some memory C/C++ beginners like to write 'smart' programs):

    for(size_t i=arr.capacity(); i--; ) {
    // access all element of arr
    }

    Normally, the for loop should be like "for(size_t i=0 ; i>=0; --i) {
    /* stuff */ } (I forgot to chk whether 'capacity' is correct or not)


    It looks like infinite loop.
    Didn't you mean either
    for(size_t i=arr.capacity() ; i>0; --i)
    or
    for(ptrdiff_t i=ptrdiff_t(arr.capacity())-1; i>=0; --i)
    ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Thu Sep 26 10:03:00 2024
    On Thu, 26 Sep 2024 10:20:53 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 26.09.2024 um 09:34 schrieb [email protected]:
    On Wed, 25 Sep 2024 17:53:58 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 25.09.2024 um 17:49 schrieb [email protected]:

    Thanks for proving my point. A proper functional language has
    value polymorphism (which clearly you don't understand) ...

    You've probably never dealt with std::function<> objects. That's
    value polymorphism! I use that all the dayd, f.e. with this function:

    [Usual unreadable mess snipped]

    My collegue calls my code "too beautiful".

    Sarcasm probably.

    You can pass a lambda to this function and the type-polymorphism
    becomes a value-polymophism.

    Oh dear. Thats not value polymorphism, thats a very complicated way of doing >> if-then.

    You can consider it like that, but it's sill polymorphism because theres >state and a pointer-dispatched function which is caalled on this state.

    Value polymorphism requires the value to be in the function prototype, not buried in some code underneath. Like all polymorphism its just a syntatic
    and semantic nicety as it can simply be done using if-then style code.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Thu Sep 26 14:09:42 2024
    On Thu, 26 Sep 2024 13:33:49 +0200
    Bonita Montero <[email protected]> boringly babbled:
    Am 26.09.2024 um 12:03 schrieb [email protected]:

    Value polymorphism requires the value to be in the function prototype, not >> buried in some code underneath. Like all polymorphism its just a syntatic
    and semantic nicety as it can simply be done using if-then style code.

    Calling a function<>-object is always value polymorphism.

    I give up, believe what you like.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to [email protected] on Sat Sep 28 04:28:49 2024
    [email protected] writes:

    On Fri, 27 Sep 2024 02:27:52 -0700
    Tim Rentsch <[email protected]> boringly babbled:

    [email protected] writes:

    Thanks for proving my point. A proper functional language has value
    polymorphism (which clearly you don't understand) as well as type
    polymorphism.

    https://chrisdone.com/posts/value-polymorphism/

    Neither "value polymorphism" nor "polymorphism by value" is a
    common term.

    Because not many languages support it.

    They mean different things.

    Not in the version of english I speak they don't.

    Polymorphism by value was discussed in a 1993 paper by Xavier
    Leroy.

    Who?

    Value polymorphism, as it is described in the cited web page, is
    simply overloading of variables rather than functions.
    (Overloading is often called "ad hoc polymorphism".)

    Thats his opinion.

    Neither overloading of functions nor overloading of variables has
    anything to do with functional programming. Overloading might be

    Without it many of the standard examples of functional programming simply won't run.

    that don't have facilities for polymorphism, as for example the
    original Lisp.

    Since when was Lisp a functional language? Scheme maybe.

    Judging by these responses, it seems you have no real interest in
    having a useful conversation.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sat Sep 28 13:55:14 2024
    On Sat, 28 Sep 2024 04:28:49 -0700
    Tim Rentsch <[email protected]> gabbled:
    [email protected] writes:

    On Fri, 27 Sep 2024 02:27:52 -0700
    Tim Rentsch <[email protected]> boringly babbled:

    [email protected] writes:

    Thanks for proving my point. A proper functional language has value
    polymorphism (which clearly you don't understand) as well as type
    polymorphism.

    https://chrisdone.com/posts/value-polymorphism/

    Neither "value polymorphism" nor "polymorphism by value" is a
    common term.

    Because not many languages support it.

    They mean different things.

    Not in the version of english I speak they don't.

    Polymorphism by value was discussed in a 1993 paper by Xavier
    Leroy.

    Who?

    Value polymorphism, as it is described in the cited web page, is
    simply overloading of variables rather than functions.
    (Overloading is often called "ad hoc polymorphism".)

    Thats his opinion.

    Neither overloading of functions nor overloading of variables has
    anything to do with functional programming. Overloading might be

    Without it many of the standard examples of functional programming simply
    won't run.

    that don't have facilities for polymorphism, as for example the
    original Lisp.

    Since when was Lisp a functional language? Scheme maybe.

    Judging by these responses, it seems you have no real interest in
    having a useful conversation.

    Thank you for your valuable insight and contribution.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Sat Sep 28 17:33:46 2024
    On 28/09/2024 11:12, [email protected] wrote:
    On Fri, 27 Sep 2024 18:24:11 +0200
    David Brown <[email protected]> gabbled:
    On 27/09/2024 17:25, [email protected] wrote:
    That applies to all types of polymorphism. All decisional code
    however its
    written eventually ends up as some kind of assembler cmp/jmp
    combination.
    Might be 2 opcodes, might be 1, doesn't matter, same thing.



    The key point of polymorphism - as I see it - is that the source code
    doing the dispatching does not know the details of the possible
    matches or targets.  Thus C++ virtual methods support polymorphism - a
    function

    Not sure how that differs with value polymorphism.


    I explained that - look at my answer below for another attempt.

    call call "p->foo()" for "p" of type "T*" without knowing anything
    about how many descendent types of "T" exist or how they different.
    All it needs to know is that the base class "T" has a virtual method
    "foo".

    This cannot be done with a series of cmp/jmp instructions - it ends up
    as an indirect call instruction.

    It could quite easily, but yes, a call is more likely. Point still stands however.


    No, it could not be done - thus your point does /not/ stand.

    Suppose you have these files :

    // foo.h
    struct Foo {
    virtual void doFoo();
    };

    // foo.cpp
    #include <stdio.h>
    #include "foo.h"

    void Foo::doFoo() {
    printf("I'm a Foo, and I'm doing foo\n");
    }


    // bar.h
    extern void doLotsOfFoo(Foo * pf);

    // bar.cpp
    #include "foo.h"
    void doLotsOfFoo(Foo * pf)
    {
    for (int i = 0; i < 10; i++) {
    pf->doFoo();
    }
    }

    // foobar.cpp
    #include <stdio.h>
    #include "foo.h"
    #include "bar.h"

    struct FooBar : Foo {
    void doFoo();
    };

    void FooBar::doFoo() {
    printf("I'm a FooBar, and I'm doing foo\n");
    }

    void testFoo() {
    FooBar fb;

    doLotsOfFoo(&fb);
    }


    That's run-time polymorphism using class inheritance and virtual
    functions. When compiling doLotsOfFoo(), there is no way for the
    compiler to know what types it might be called with - there is no way it
    could be compiled as a selection of comparisons. Baring full-program optimisation, indirect calls are the only way to handle it.


    I am pretty confident that what you seem to be talking about (AFAIUI)
    is not something many people would refer to as "polymorphism"

    When you say "people" you seem to be talking about people in the C++ world
    or perhaps C-type language world. Polymorphism is more than just type
    and virtual functions.


    I realise the term is used in other languages too (although the emphasis
    here is of course on C++, since we are in c.l.c++). But no, I am not restricting "people" to C++ programmers - they may be programmers of any languages, including functional programming languages.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sat Sep 28 15:47:45 2024
    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> gabbled:
    On 28/09/2024 11:12, [email protected] wrote:
    On Fri, 27 Sep 2024 18:24:11 +0200
    Not sure how that differs with value polymorphism.


    I explained that - look at my answer below for another attempt.

    No you didn't because like Bonita you have no idea what value polymorphism is.

    It could quite easily, but yes, a call is more likely. Point still stands
    however.


    No, it could not be done - thus your point does /not/ stand.

    Really? What exactly do you think an assembler call instruction is other
    than a single opcode stack push and jump?

    That's run-time polymorphism using class inheritance and virtual
    functions. When compiling doLotsOfFoo(), there is no way for the
    compiler to know what types it might be called with - there is no way it >could be compiled as a selection of comparisons. Baring full-program >optimisation, indirect calls are the only way to handle it.

    And you don't think indirect jump instructions exist?

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

    We can add assembler to the list of things you don't understand.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Sun Sep 29 13:41:27 2024
    On 28/09/2024 17:47, [email protected] wrote:
    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> gabbled:
    On 28/09/2024 11:12, [email protected] wrote:
    On Fri, 27 Sep 2024 18:24:11 +0200
    Not sure how that differs with value polymorphism.


    I explained that - look at my answer below for another attempt.

    No you didn't because like Bonita you have no idea what value
    polymorphism is.


    The term "polymorphism" is used in reference to /types/, not /values/.
    I am not new to programming, and have used a large variety of languages (including functional programming languages), but have not heard the
    phrase "value polymorphism" before. So I am trying to get /you/ to say
    what /you/ mean by it. Maybe it's just a name you and a few other
    people use for pattern matching.


    It could quite easily, but yes, a call is more likely. Point still
    stands
    however.


    No, it could not be done - thus your point does /not/ stand.

    Really? What exactly do you think an assembler call instruction is other
    than a single opcode stack push and jump?

    Yes, that's what a call instruction sequence is on many (but certainly
    not all) processors. But that's not what you wrote. You wrote that
    "all types of polymorphism" are just conditionals that boil down to
    "cmp/jmp" instructions.

    Maybe you misread, or expressed yourself badly, or mixed up what you
    were trying to say.


    That's run-time polymorphism using class inheritance and virtual
    functions.  When compiling doLotsOfFoo(), there is no way for the
    compiler to know what types it might be called with - there is no way
    it could be compiled as a selection of comparisons.  Baring
    full-program optimisation, indirect calls are the only way to handle it.

    And you don't think indirect jump instructions exist?

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


    A call is, fundamentally, just a jump with a returned address stored in
    some way. I'm not making a distinction between indirect calls and
    indirect jumps, as that's just detail.

    We can add assembler to the list of things you don't understand.


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Sun Sep 29 14:37:57 2024
    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> wrote:

    On 28/09/2024 11:12, [email protected] wrote:
    On Fri, 27 Sep 2024 18:24:11 +0200
    David Brown <[email protected]> gabbled:

    This cannot be done with a series of cmp/jmp instructions - it
    ends up as an indirect call instruction.

    It could quite easily, but yes, a call is more likely. Point still
    stands however.


    No, it could not be done - thus your point does /not/ stand.


    It could be done.
    It could be done relatively easily with whole program compiler.
    Without whole program compiler it still could be done, but would need
    some co-operation from linker that would have to glue code segments.
    I'd guess, majority of linkers already can do something of this sort
    for other purposes.
    Of course, if class hierarchy is sufficiently big then implementation
    based on comparisons, branches and direct calls would be rather
    inefficient relatively to indirect call (actually dual-indirect call in
    most typical C++ implementations).

    They point that you were probably missing when claiming that it is
    impossible is that every instance of given class can carry its Class Id.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Sun Sep 29 14:49:13 2024
    On Sun, 29 Sep 2024 13:41:27 +0200
    David Brown <[email protected]> wrote:

    On 28/09/2024 17:47, [email protected] wrote:
    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> gabbled:
    On 28/09/2024 11:12, [email protected] wrote:
    On Fri, 27 Sep 2024 18:24:11 +0200
    Not sure how that differs with value polymorphism.


    I explained that - look at my answer below for another attempt.

    No you didn't because like Bonita you have no idea what value
    polymorphism is.


    The term "polymorphism" is used in reference to /types/, not
    /values/. I am not new to programming, and have used a large variety
    of languages (including functional programming languages), but have
    not heard the phrase "value polymorphism" before. So I am trying to
    get /you/ to say what /you/ mean by it. Maybe it's just a name you
    and a few other people use for pattern matching.


    May be, 'polymorphism by type of return value' is what he has in mind?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Sun Sep 29 15:42:06 2024
    On 29/09/2024 13:37, Michael S wrote:
    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> wrote:

    On 28/09/2024 11:12, [email protected] wrote:
    On Fri, 27 Sep 2024 18:24:11 +0200
    David Brown <[email protected]> gabbled:

    This cannot be done with a series of cmp/jmp instructions - it
    ends up as an indirect call instruction.

    It could quite easily, but yes, a call is more likely. Point still
    stands however.


    No, it could not be done - thus your point does /not/ stand.


    It could be done.
    It could be done relatively easily with whole program compiler.

    I think I mentioned that - and I specifically mentioned separate
    compilation. But of course if the compiler has full knowledge of the
    actual types being used at the time, then it can use conditionals or
    other techniques (like code cloning) to improve the efficiency.
    Compilers do de-virtualisation when they can, and with whole program optimisation, they can do so more often.

    Still, the key point is that the source code is written independently of
    the actual type used - there are no "if" or "switch" clauses in the
    source, or any kind of pattern matching between a pre-specified set of
    types.

    Without whole program compiler it still could be done, but would need
    some co-operation from linker that would have to glue code segments.
    I'd guess, majority of linkers already can do something of this sort
    for other purposes.

    You are perhaps thinking of things like sequences of pre-main
    constructors or initialisation functions, that are often joined together
    by the linker?

    It's certainly conceivable that the base class code for the virtual
    function could be generated with a template for a series of "if the real
    type is this, do that" blocks in a named segment, with a default
    handler, then each inheriting class which overrides the method could add
    "if the real type is this type, do this" block to this named segment.
    Then the linker would put it all together.

    I would be extremely surprised if that was more efficient at run-time
    than function-pointer style overloads using virtual method tables, and
    it would be a lot more complex to implement, but I'll agree it should be possible.

    Of course, if class hierarchy is sufficiently big then implementation
    based on comparisons, branches and direct calls would be rather
    inefficient relatively to indirect call (actually dual-indirect call in
    most typical C++ implementations).

    They point that you were probably missing when claiming that it is
    impossible is that every instance of given class can carry its Class Id.


    I will accept that it is /possible/ to use conditionals, rather than
    indirect jumps or calls. But it is not possible without more
    information available when implementing the polymorphic code - whether
    by whole-program optimisation, or smart linkers, or by having all the
    code in one translation unit.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sun Sep 29 15:00:26 2024
    On Sun, 29 Sep 2024 13:41:27 +0200
    David Brown <[email protected]> boringly babbled:
    On 28/09/2024 17:47, [email protected] wrote:
    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> gabbled:
    On 28/09/2024 11:12, [email protected] wrote:
    On Fri, 27 Sep 2024 18:24:11 +0200
    Not sure how that differs with value polymorphism.


    I explained that - look at my answer below for another attempt.

    No you didn't because like Bonita you have no idea what value
    polymorphism is.


    The term "polymorphism" is used in reference to /types/, not /values/.

    Says who?

    I am not new to programming, and have used a large variety of languages >(including functional programming languages), but have not heard the

    Could have fooled me.

    phrase "value polymorphism" before. So I am trying to get /you/ to say
    what /you/ mean by it. Maybe it's just a name you and a few other
    people use for pattern matching.

    I don't know how many more bloody times I can explain it, its not complicated! I even posted some functional code a few days ago demonstrating it! Frankly I can't be bothered arguing the toss any longer. Clearly you don't understand what it is so tough luck, thats your problem , not mine.

    Really? What exactly do you think an assembler call instruction is other
    than a single opcode stack push and jump?

    Yes, that's what a call instruction sequence is on many (but certainly
    not all) processors. But that's not what you wrote. You wrote that
    "all types of polymorphism" are just conditionals that boil down to
    "cmp/jmp" instructions.

    They are conditions and could be compiled down to a compare and jump just
    like any other conditional code.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Sun Sep 29 11:23:51 2024
    Michael S <[email protected]> writes:

    On Sun, 29 Sep 2024 13:41:27 +0200
    David Brown <[email protected]> wrote:

    On 28/09/2024 17:47, [email protected] wrote:

    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> gabbled:

    On 28/09/2024 11:12, [email protected] wrote:

    On Fri, 27 Sep 2024 18:24:11 +0200
    Not sure how that differs with value polymorphism.

    I explained that - look at my answer below for another attempt.

    No you didn't because like Bonita you have no idea what value
    polymorphism is.

    The term "polymorphism" is used in reference to /types/, not
    /values/. I am not new to programming, and have used a large variety
    of languages (including functional programming languages), but have
    not heard the phrase "value polymorphism" before. So I am trying to
    get /you/ to say what /you/ mean by it. Maybe it's just a name you
    and a few other people use for pattern matching.

    May be, 'polymorphism by type of return value' is what he has in mind?

    In a previous posting Muttley cited this url:

    https://chrisdone.com/posts/value-polymorphism/

    In a different previous posting Muttley gave this example (slightly
    reformatted for line length):

    def main(argv) ->
    func("",["hello","cruel","world","this","is","a","test"])
    : 0
    ;

    def func(_,[]) -> "";

    def func(_,[head<tail]) ->
    printnl head,",",tail : func(head[0],tail);

    def func("world",[head<tail]) ->
    printnl "GOT WORLD" : func(head,tail);

    It's not clear what programming language is intended here. Based on
    my experience with other functional languages, it looks like this
    example is (a) defined wrongly, (b) wouldn't compile because of a
    type mismatch, and (c) is not polymorphic. But of course we can't
    be sure without knowing more about what language is intended.

    The web page does use the phrase "value polymorphism", but it's
    about something else altogether. The programming language Haskell
    has a facility that might be called "variable overloading". It's
    like what C or C++ would be if they allowed, for example:

    int poly;
    double poly[10];

    and later on in the program a declaration such as

    double *p = poly;

    would know to use the double array 'poly', because the other 'poly'
    doesn't type check.

    My guess is Muttley is out of his depth and doesn't really know what
    he means by these different phrases. But I found it impossible to
    tell because in his postings he doesn't interact in any meaningful
    way.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 30 07:40:02 2024
    On Mon, 30 Sep 2024 07:26:04 -0000 (UTC)
    [email protected] boring babbled:
    fenris$ cat testprogs/functional3.fl
    fenris$ fling < progs/functional3.fl

    And before anyone mentions progs vs testprogs, its a soft link:

    fenris$ ls -ld testprogs
    lrwxr-xr-x 1 la332 staff 5 30 Jan 2019 testprogs -> progs

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 30 07:26:04 2024
    On Sun, 29 Sep 2024 11:23:51 -0700
    Tim Rentsch <[email protected]> boring babbled:
    Michael S <[email protected]> writes:
    def main(argv) ->
    func("",["hello","cruel","world","this","is","a","test"])
    : 0
    ;

    def func(_,[]) -> "";

    def func(_,[head<tail]) ->
    printnl head,",",tail : func(head[0],tail);

    def func("world",[head<tail]) ->
    printnl "GOT WORLD" : func(head,tail);

    It's not clear what programming language is intended here. Based on
    my experience with other functional languages, it looks like this
    example is (a) defined wrongly, (b) wouldn't compile because of a
    type mismatch, and (c) is not polymorphic. But of course we can't
    be sure without knowing more about what language is intended.

    Christ you are so up your own arrogant backside. It was a language used in
    a specialist task, it wasn't made public. Here your go smartass:

    fenris$ cat testprogs/functional3.fl
    def main(argv) ->
    func("",["hello","cruel","world","this","is","a","test"])
    : 0
    ;

    def func(_,[]) -> "";

    def func(_,[head<tail]) -> printnl head,",",tail : func(head[0],tail);

    def func("world",[head<tail]) ->
    printnl "GOT WORLD" : func(head,tail);
    fenris$ fling < progs/functional3.fl ['hello'],['hello']['cruel','world','this','is','a','test'] ['cruel'],['cruel']['world','this','is','a','test'] ['world'],['world']['this','is','a','test']
    GOT WORLD
    ['is'],['is']['a','test']
    ['a'],['a']['test']
    ['test'],['test'][]
    fenris$

    The web page does use the phrase "value polymorphism", but it's

    Its not only in the URL , its on the first bloody line! Are you a complete idiot??

    My guess is Muttley is out of his depth and doesn't really know what

    LOL! Look in the mirror mate!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Tim Rentsch on Mon Sep 30 10:57:45 2024
    On 29/09/2024 20:23, Tim Rentsch wrote:
    Michael S <[email protected]> writes:

    On Sun, 29 Sep 2024 13:41:27 +0200
    David Brown <[email protected]> wrote:

    On 28/09/2024 17:47, [email protected] wrote:

    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> gabbled:

    On 28/09/2024 11:12, [email protected] wrote:

    On Fri, 27 Sep 2024 18:24:11 +0200
    Not sure how that differs with value polymorphism.

    I explained that - look at my answer below for another attempt.

    No you didn't because like Bonita you have no idea what value
    polymorphism is.

    The term "polymorphism" is used in reference to /types/, not
    /values/. I am not new to programming, and have used a large variety
    of languages (including functional programming languages), but have
    not heard the phrase "value polymorphism" before. So I am trying to
    get /you/ to say what /you/ mean by it. Maybe it's just a name you
    and a few other people use for pattern matching.

    May be, 'polymorphism by type of return value' is what he has in mind?

    In a previous posting Muttley cited this url:

    https://chrisdone.com/posts/value-polymorphism/

    In a different previous posting Muttley gave this example (slightly reformatted for line length):

    def main(argv) ->
    func("",["hello","cruel","world","this","is","a","test"])
    : 0
    ;

    def func(_,[]) -> "";

    def func(_,[head<tail]) ->
    printnl head,",",tail : func(head[0],tail);

    def func("world",[head<tail]) ->
    printnl "GOT WORLD" : func(head,tail);

    It's not clear what programming language is intended here. Based on
    my experience with other functional languages, it looks like this
    example is (a) defined wrongly, (b) wouldn't compile because of a
    type mismatch, and (c) is not polymorphic. But of course we can't
    be sure without knowing more about what language is intended.

    The web page does use the phrase "value polymorphism", but it's
    about something else altogether. The programming language Haskell
    has a facility that might be called "variable overloading". It's
    like what C or C++ would be if they allowed, for example:

    int poly;
    double poly[10];

    and later on in the program a declaration such as

    double *p = poly;

    would know to use the double array 'poly', because the other 'poly'
    doesn't type check.


    You can get some way towards all this with template variables in C++,
    and with classes with templated type conversion operators to give return
    type overloading. But typically you need a bit more explicit mention of
    the type than is described in that web page or your example, and that's
    perhaps no bad thing.

    For the "poly" case, you can write :

    typedef double double_array[10];

    template <typename T> T poly;

    template<> int poly<int>;
    template<> double_array poly<double_array>;

    double * p = poly<double_array>;

    You'll get a compile-time error if the last line uses a poly<T> of an incompatible type, but you do need an explicit type. There could, after
    all, be many poly instances that are compatible with assignment to
    double*, and IMHO it's better that you have to be explicit rather than
    having the language determine the "best" choice in some way.

    You can also do something like this :

    struct Poly {
    template <typename T> static T poly_imp;
    template <typename T> operator T () { return poly_imp<T>; }
    };
    Poly poly;

    template <> int Poly::poly_imp<int> = 123;

    int xx = poly;
    double * p = poly;
    auto q = (std::array<double, 10>) poly;




    My guess is Muttley is out of his depth and doesn't really know what
    he means by these different phrases. But I found it impossible to
    tell because in his postings he doesn't interact in any meaningful
    way.

    So it's not just me that thinks this.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Mon Sep 30 12:24:43 2024
    On 30/09/2024 09:26, [email protected] wrote:
    On Sun, 29 Sep 2024 11:23:51 -0700
    Tim Rentsch <[email protected]> boring babbled:

    But of course we can't
    be sure without knowing more about what language is intended.

    It was a language used in
    a specialist task, it wasn't made public.


    Oh, that makes it /much/ clearer.

    Basically, you use "value polymorphism" as your own private term, and
    have tried to explain it using a link to a web page describing something entirely different, and some example code in your own private language.

    Time to drop this, I think.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Mon Sep 30 05:29:18 2024
    Michael S <[email protected]> writes:

    On Sun, 29 Sep 2024 13:41:27 +0200
    David Brown <[email protected]> wrote:

    On 28/09/2024 17:47, [email protected] wrote:

    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> gabbled:

    On 28/09/2024 11:12, [email protected] wrote:

    On Fri, 27 Sep 2024 18:24:11 +0200
    Not sure how that differs with value polymorphism.

    I explained that - look at my answer below for another attempt.

    No you didn't because like Bonita you have no idea what value
    polymorphism is.

    The term "polymorphism" is used in reference to /types/, not
    /values/. I am not new to programming, and have used a large variety
    of languages (including functional programming languages), but have
    not heard the phrase "value polymorphism" before. So I am trying to
    get /you/ to say what /you/ mean by it. Maybe it's just a name you
    and a few other people use for pattern matching.

    May be, 'polymorphism by type of return value' is what he has in mind?

    We have now learned from a subsequent posting that the language used
    in the example Muttley gave "was a language used in a specialist
    task, it wasn't made public." So we aren't able to draw any
    conclusions about what he meant (and apparently that has been his
    intention all along - any attempt to elicit more information has
    resulted in insults and nothing more).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Mon Sep 30 15:21:22 2024
    On 29/09/2024 13:49, Michael S wrote:
    On Sun, 29 Sep 2024 13:41:27 +0200
    David Brown <[email protected]> wrote:

    On 28/09/2024 17:47, [email protected] wrote:
    On Sat, 28 Sep 2024 17:33:46 +0200
    David Brown <[email protected]> gabbled:
    On 28/09/2024 11:12, [email protected] wrote:
    On Fri, 27 Sep 2024 18:24:11 +0200
    Not sure how that differs with value polymorphism.


    I explained that - look at my answer below for another attempt.

    No you didn't because like Bonita you have no idea what value
    polymorphism is.


    The term "polymorphism" is used in reference to /types/, not
    /values/. I am not new to programming, and have used a large variety
    of languages (including functional programming languages), but have
    not heard the phrase "value polymorphism" before. So I am trying to
    get /you/ to say what /you/ mean by it. Maybe it's just a name you
    and a few other people use for pattern matching.


    May be, 'polymorphism by type of return value' is what he has in mind?


    Certainly that is an established kind of polymorphism, and pretty much
    the only hit when googling "value polymorphism" is "return value
    polymorphism". It is found in Ada, Haskell, and Rust (I think). You
    can also do it in C++, at least to some extent, by making types with
    conversion operators to different types. (It can be used in expression templates, for example.)

    But that does not at all fit with the examples he gave in his
    "specialist" language, which was just pattern matching. It fits better
    with the link he gave, though that was more like C++ template variables.

    I think Tim's conclusion that Muttley is confused is more likely.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 30 15:47:05 2024
    On Mon, 30 Sep 2024 12:24:43 +0200
    David Brown <[email protected]> boring babbled:
    On 30/09/2024 09:26, [email protected] wrote:
    On Sun, 29 Sep 2024 11:23:51 -0700
    Tim Rentsch <[email protected]> boring babbled:

    But of course we can't
    be sure without knowing more about what language is intended.

    It was a language used in
    a specialist task, it wasn't made public.


    Oh, that makes it /much/ clearer.

    Its a pretty clear language using similar constructs to other functional languages so I have no idea what your comprehension problem is.

    Time to drop this, I think.

    Yes, best before you and some others make total fools of yourselves. You're
    so stuck in the C++ programming paradigm your minds can't cope with one completely different.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 30 16:00:02 2024
    On Mon, 30 Sep 2024 15:21:22 +0200
    David Brown <[email protected]> boring babbled:
    Certainly that is an established kind of polymorphism, and pretty much
    the only hit when googling "value polymorphism" is "return value >polymorphism". It is found in Ada, Haskell, and Rust (I think). You
    can also do it in C++, at least to some extent, by making types with >conversion operators to different types. (It can be used in expression >templates, for example.)

    But that does not at all fit with the examples he gave in his
    "specialist" language, which was just pattern matching. It fits better
    with the link he gave, though that was more like C++ template variables.

    I think Tim's conclusion that Muttley is confused is more likely.

    Please explain what you find so complicated about a polymorphic function
    call being based on the VALUE of one or more parameters passed to it rather than the type of parameter? Imagine in C++ if you could do:

    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that would run now it has your familiar comfy C++ syntax.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Mon Sep 30 16:09:06 2024
    On Mon, 30 Sep 2024 16:00:02 -0000 (UTC)
    [email protected] boring babbled:
    void func(int i = 1) { cout << "One\n"; }

    Before the pedants pile in, yes it would have to be:

    void func(int i == 1) { cout << "One\n"; }

    for c++. Typed it on the fly so...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to [email protected] on Mon Sep 30 19:43:43 2024
    On Mon, 30 Sep 2024 16:00:02 -0000 (UTC)
    [email protected] wrote:

    On Mon, 30 Sep 2024 15:21:22 +0200
    David Brown <[email protected]> boring babbled:
    Certainly that is an established kind of polymorphism, and pretty
    much the only hit when googling "value polymorphism" is "return
    value polymorphism". It is found in Ada, Haskell, and Rust (I
    think). You can also do it in C++, at least to some extent, by
    making types with conversion operators to different types. (It can
    be used in expression templates, for example.)

    But that does not at all fit with the examples he gave in his
    "specialist" language, which was just pattern matching. It fits
    better with the link he gave, though that was more like C++ template >variables.

    I think Tim's conclusion that Muttley is confused is more likely.

    Please explain what you find so complicated about a polymorphic
    function call being based on the VALUE of one or more parameters
    passed to it rather than the type of parameter? Imagine in C++ if you
    could do:

    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that
    would run now it has your familiar comfy C++ syntax.


    You forgot to mention what you expect as an output.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Mon Sep 30 19:51:14 2024
    On 30/09/2024 18:00, [email protected] wrote:
    On Mon, 30 Sep 2024 15:21:22 +0200
    David Brown <[email protected]> boring babbled:
    Certainly that is an established kind of polymorphism, and pretty much
    the only hit when googling "value polymorphism" is "return value
    polymorphism". It is found in Ada, Haskell, and Rust (I think). You
    can also do it in C++, at least to some extent, by making types with
    conversion operators to different types. (It can be used in expression
    templates, for example.)

    But that does not at all fit with the examples he gave in his
    "specialist" language, which was just pattern matching. It fits better
    with the link he gave, though that was more like C++ template variables.

    I think Tim's conclusion that Muttley is confused is more likely.

    Please explain what you find so complicated about a polymorphic function
    call being based on the VALUE of one or more parameters passed to it rather than the type of parameter?

    Nobody finds the concept of pattern matching difficult to understand.
    Nor is your private functional programming language example difficult to
    follow - unless there is something non-obvious that we can't see,
    because it is a private language whose details are unknown.

    Remember, you are talking to people who are more knowledgeable than you
    in C++ (since you have pretty much given up anything beyond C++98), and
    who have, to varying degrees, knowledge and experience in functional programming. I have plenty of disagreements with both Bonita and Tim in
    regard to their posting styles, the way they talk to others, and their
    coding styles. But there is a difference between not liking the way
    they write code, and not understanding the concepts they use. Bonita's knowledge of C++ far exceeds yours, and Tim's knowledge of many
    programming languages and language paradigms exceeds that of most people
    I have come across.

    We know what the code you wrote does. We disagree that it is
    "polymorphism", or that "value polymorphism" is anything but a rather
    obscure term that has no wide-spread meaning.

    Imagine in C++ if you could do:

    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }


    Okay...

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that would run now it has your familiar comfy C++ syntax.


    Yes, it's obvious what you intend it to mean.

    But that's not polymorphism.

    First, you are mixing in the concept of overloading - so let's remove
    that by throwing out the func overloads with string types, and
    concentrating on those with an int parameter.

    Now you have pattern matching - a switch, with a default case. The
    twist (and it might be an interesting feature in a programming language,
    but I am not sure it would be worth having) is that you allow the
    definition of "func" to be split up.

    However, it is not polymorphism - the code generated for "func" must
    know about all possible specialisations.

    C++ already allows this for compile-time constants:

    template <int i = 0> void func() { cout << "Int default\n"; }
    template <> void func<1>() { cout << "One\n"; }
    template <> void func<2>() { cout << "Two\n"; }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to [email protected] on Mon Sep 30 10:18:38 2024
    [email protected] writes:

    On Mon, 30 Sep 2024 15:21:22 +0200
    David Brown <[email protected]> boring babbled:

    Certainly that is an established kind of polymorphism, and pretty
    much the only hit when googling "value polymorphism" is "return
    value polymorphism". It is found in Ada, Haskell, and Rust (I
    think). You can also do it in C++, at least to some extent, by
    making types with conversion operators to different types. (It can
    be used in expression templates, for example.)

    But that does not at all fit with the examples he gave in his
    "specialist" language, which was just pattern matching. It fits
    better with the link he gave, though that was more like C++
    template variables.

    I think Tim's conclusion that Muttley is confused is more likely.

    Please explain what you find so complicated about a polymorphic
    function call being based on the VALUE of one or more parameters
    passed to it rather than the type of parameter? Imagine in C++ if
    you could do:

    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that
    would run now it has your familiar comfy C++ syntax.

    Until you describe what you mean in terms of an existing, public
    language, such as Haskell, and without any imaginary extensions, and
    with an example that can be compiled as is and run successfully,
    there is no reason to pay attention to anything you say.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 07:31:51 2024
    On Mon, 30 Sep 2024 19:43:43 +0300
    Michael S <[email protected]> boring babbled:
    On Mon, 30 Sep 2024 16:00:02 -0000 (UTC)
    [email protected] wrote:
    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that
    would run now it has your familiar comfy C++ syntax.


    You forgot to mention what you expect as an output.

    You seriously can't figure it out?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 07:32:42 2024
    On Mon, 30 Sep 2024 10:18:38 -0700
    Tim Rentsch <[email protected]> boring babbled: >[email protected] writes:
    Please explain what you find so complicated about a polymorphic
    function call being based on the VALUE of one or more parameters
    passed to it rather than the type of parameter? Imagine in C++ if
    you could do:

    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that
    would run now it has your familiar comfy C++ syntax.

    Until you describe what you mean in terms of an existing, public
    language, such as Haskell, and without any imaginary extensions, and
    with an example that can be compiled as is and run successfully,
    there is no reason to pay attention to anything you say.

    You've already demonstrated you're a bit dim when it comes to
    understanding this concept, no need to keep digging.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 07:36:55 2024
    On Mon, 30 Sep 2024 19:51:14 +0200
    David Brown <[email protected]> boring babbled:
    On 30/09/2024 18:00, [email protected] wrote:
    Please explain what you find so complicated about a polymorphic function
    call being based on the VALUE of one or more parameters passed to it rather >> than the type of parameter?

    Nobody finds the concept of pattern matching difficult to understand.
    Nor is your private functional programming language example difficult to >follow - unless there is something non-obvious that we can't see,
    because it is a private language whose details are unknown.

    Remember, you are talking to people who are more knowledgeable than you
    in C++ (since you have pretty much given up anything beyond C++98), and

    This isn't about C++. Hadn't you figured that out yet?

    they write code, and not understanding the concepts they use. Bonita's >knowledge of C++ far exceeds yours, and Tim's knowledge of many
    programming languages and language paradigms exceeds that of most people
    I have come across.

    Given his apparently inability to understand simple example code I
    very much doubt that. He probably struggles with something like SQL
    being so completely different to C++.

    We know what the code you wrote does. We disagree that it is
    "polymorphism", or that "value polymorphism" is anything but a rather
    obscure term that has no wide-spread meaning.

    Describe what you think polymorphism is in general terms then.

    Yes, it's obvious what you intend it to mean.

    But that's not polymorphism.

    Yes, it is.

    Now you have pattern matching - a switch, with a default case. The
    twist (and it might be an interesting feature in a programming language,
    but I am not sure it would be worth having) is that you allow the
    definition of "func" to be split up.

    So descriminating a function call by type is polymorphism but but
    value isn't. According to you. Whatever you say.

    C++ already allows this for compile-time constants:

    Big deal. This is runtime, not compile time.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to [email protected] on Tue Oct 1 11:01:29 2024
    On Tue, 1 Oct 2024 07:31:51 -0000 (UTC)
    [email protected] wrote:

    On Mon, 30 Sep 2024 19:43:43 +0300
    Michael S <[email protected]> boring babbled:
    On Mon, 30 Sep 2024 16:00:02 -0000 (UTC)
    [email protected] wrote:
    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that
    would run now it has your familiar comfy C++ syntax.


    You forgot to mention what you expect as an output.

    You seriously can't figure it out?


    No, I can't.
    I see two possibilities and don't know which one was chosen by
    definitions of your private language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Tue Oct 1 10:42:06 2024
    On 01/10/2024 10:00, Bonita Montero wrote:
    Am 01.10.2024 um 09:36 schrieb [email protected]:

    Given his apparently inability to understand simple example code
    I very much doubt that. He probably struggles with something like
    SQL being so completely different to C++.

    Do you mean me with "he" ? I've got a OCP-DBA for Oracle and I've
    been a DBA two years.
    You don't even try to read my code, telling that my code doesn't
    make sense and it's too complicated.

    Big deal. This is runtime, not compile time.

    Tell me which popular language implements this "value-polymorphism".
    It's a word Wikipedia doesn't know.


    Of course Wikipedia doesn't know it, since it is his own made-up term.
    (Well, his and one other person.)

    The word "polymorphism" means "multiple kinds" or "multiple shapes" - it
    is a term for code that can handle a parameter that can be of many
    different types. So in C++ terms (since this is comp.lang.c++, even
    though Muttley seems to think it is comp.lang.made-up-stuff), you can
    have run-time polymorphism using pointers to base classes and virtual functions, and compile-time polymorphism using generics and templates.

    What you can't have is "value" polymorphism - it's an oxymoron. The
    common term for code that can handle parameters taking multiple
    different values is "function".


    Muttley doesn't even seem to know what he means by the term. He has
    referred to a webpage that incorrectly uses the term for describing
    type-based overloading when defining a function in Haskell (in a single
    generic definition). The author of that page thinks the concept is
    unique to Haskell, though the same basic idea can be expressed in other languages including Ada and C++ (albeit with more explicit typing in C++).

    Then Muttley showed some pattern matching in his made-up language.
    Later, he has shown more pattern matching in made up C++ extensions.

    None of this shows anything that could reasonably be called "value polymorphism" in any sense. Nor is any of it required for functional programming - either for pure functional programming languages, or for
    using functional programming styles in multi-paradigm languages.

    Pattern matching can definitely be a nice way to structure code. And
    being able to split a function definition into parts with an implicit
    if/else list, switch, or pattern matching is an interesting idea that is
    common (but not essential) in functional programming languages and
    exists in C++ in the form of template specialisations. (C++ might
    acquire it for run-time functions once reflection and metaclasses are in place.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Tue Oct 1 12:53:32 2024
    On Tue, 1 Oct 2024 10:42:06 +0200
    David Brown <[email protected]> wrote:

    On 01/10/2024 10:00, Bonita Montero wrote:
    Am 01.10.2024 um 09:36 schrieb [email protected]:

    Given his apparently inability to understand simple example code
    I very much doubt that. He probably struggles with something like
    SQL being so completely different to C++.

    Do you mean me with "he" ? I've got a OCP-DBA for Oracle and I've
    been a DBA two years.
    You don't even try to read my code, telling that my code doesn't
    make sense and it's too complicated.

    Big deal. This is runtime, not compile time.

    Tell me which popular language implements this "value-polymorphism".
    It's a word Wikipedia doesn't know.


    Of course Wikipedia doesn't know it, since it is his own made-up
    term. (Well, his and one other person.)

    The word "polymorphism" means "multiple kinds" or "multiple shapes" -
    it is a term for code that can handle a parameter that can be of many different types. So in C++ terms (since this is comp.lang.c++, even
    though Muttley seems to think it is comp.lang.made-up-stuff), you can
    have run-time polymorphism using pointers to base classes and virtual functions, and compile-time polymorphism using generics and templates.

    What you can't have is "value" polymorphism - it's an oxymoron.

    I don't think so.
    IMHO, C++ does have features that can be called compile-time value
    polymorphism without overstretching definition of the word
    'polymorphism'.
    You demonstrated it yourself few posts ago using relatively modern
    C++ features. But for class templates (as opposed to function
    templates) something that can be reasonably called 'value polymorphism'
    existed for as long as C++ has templates (1990 ?).

    The feature appears useful in 'pure functional' languages like C++
    template sub-language. Of course, it is less useful, and probably not
    desirable in mixed functional/imperative environments where you can
    achieve the same result in several simpler ways.

    The
    common term for code that can handle parameters taking multiple
    different values is "function".


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 09:56:09 2024
    On Tue, 1 Oct 2024 10:00:57 +0200
    Bonita Montero <[email protected]> boring babbled:
    Am 01.10.2024 um 09:36 schrieb [email protected]:

    Given his apparently inability to understand simple example code
    I very much doubt that. He probably struggles with something like
    SQL being so completely different to C++.

    Do you mean me with "he" ? I've got a OCP-DBA for Oracle and I've

    No.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 09:58:50 2024
    On Tue, 1 Oct 2024 10:06:17 +0200
    Bonita Montero <[email protected]> boring babbled:
    Am 01.10.2024 um 10:01 schrieb Michael S:
    On Tue, 1 Oct 2024 07:31:51 -0000 (UTC)
    [email protected] wrote:

    On Mon, 30 Sep 2024 19:43:43 +0300
    Michael S <[email protected]> boring babbled:
    On Mon, 30 Sep 2024 16:00:02 -0000 (UTC)
    [email protected] wrote:
    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that
    would run now it has your familiar comfy C++ syntax.


    You forgot to mention what you expect as an output.

    You seriously can't figure it out?


    No, I can't.
    I see two possibilities and don't know which one was chosen by
    definitions of your private language.

    There's no output but may compiler errors because the code defines
    three identical overloads for the int call and twi identical overloads
    for the string call.

    Because its not valid C++! I was using modified C++ syntax to keep people happy since they couldn't figure out the syntax of the functional language I used.

    I'm beginning to wonder if I'm talking to bots.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 09:57:40 2024
    On Tue, 1 Oct 2024 11:01:29 +0300
    Michael S <[email protected]> boring babbled:
    On Tue, 1 Oct 2024 07:31:51 -0000 (UTC)
    [email protected] wrote:

    On Mon, 30 Sep 2024 19:43:43 +0300
    Michael S <[email protected]> boring babbled:
    On Mon, 30 Sep 2024 16:00:02 -0000 (UTC)
    [email protected] wrote:
    void func(int i = 1) { cout << "One\n"; }
    void func(int i = 2) { cout << "Two\n"; }
    void func(string s = "hello") { cout << "Hello!\n"; }
    void func(int i) { cout << "Int default\n"; }
    void func(string s) { cout << "String default\n"; }

    int main()
    {
    for(int i=0;i < 5;++i) func(i);
    func("hello");
    func("world");
    }

    I'm sure even a thickheads like you and Rensch can figure how that
    would run now it has your familiar comfy C++ syntax.


    You forgot to mention what you expect as an output.

    You seriously can't figure it out?


    No, I can't.

    Says it all.

    I see two possibilities and don't know which one was chosen by
    definitions of your private language.

    Int Default
    One
    Two
    Int Default
    Int Default
    Int Default
    Hello!
    String default

    If you still can't figure out why it would do that then maybe programming
    isn't for you.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 10:01:22 2024
    On Tue, 1 Oct 2024 10:42:06 +0200
    David Brown <[email protected]> boring babbled:
    What you can't have is "value" polymorphism - it's an oxymoron. The

    No it isn't, your brain just can't understand the concept even with now
    2 pieces of example code.

    common term for code that can handle parameters taking multiple
    different values is "function".

    So C++ can differentiate a functions with the same name based on the
    passed value at runtime can it? Not last time I checked.

    Muttley doesn't even seem to know what he means by the term. He has

    I know perfectly well what it means, you're just dim.

    tl;dr

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 10:02:48 2024
    On Tue, 1 Oct 2024 12:53:32 +0300
    Michael S <[email protected]> boring babbled:
    The feature appears useful in 'pure functional' languages like C++
    template sub-language. Of course, it is less useful, and probably not >desirable in mixed functional/imperative environments where you can
    achieve the same result in several simpler ways.

    All polymorphism can be achieved in simpler/cruder ways. Its simply a
    syntatic nicety.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to [email protected] on Tue Oct 1 13:11:41 2024
    On Tue, 1 Oct 2024 10:02:48 -0000 (UTC)
    [email protected] wrote:

    On Tue, 1 Oct 2024 12:53:32 +0300
    Michael S <[email protected]> boring babbled:
    The feature appears useful in 'pure functional' languages like C++
    template sub-language. Of course, it is less useful, and probably not >desirable in mixed functional/imperative environments where you can
    achieve the same result in several simpler ways.

    All polymorphism can be achieved in simpler/cruder ways. Its simply a syntatic nicety.


    The point is that if your language is not 'pure functional' then those
    other ways (if, switch) are not 'cruder'. They are finer.
    The selection written as if/switch is both shorter and easier to follow
    than selection based on 'value polymorphism'.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Tue Oct 1 13:06:02 2024
    On 01/10/2024 11:53, Michael S wrote:
    On Tue, 1 Oct 2024 10:42:06 +0200
    David Brown <[email protected]> wrote:

    On 01/10/2024 10:00, Bonita Montero wrote:
    Am 01.10.2024 um 09:36 schrieb [email protected]:

    Given his apparently inability to understand simple example code
    I very much doubt that. He probably struggles with something like
    SQL being so completely different to C++.

    Do you mean me with "he" ? I've got a OCP-DBA for Oracle and I've
    been a DBA two years.
    You don't even try to read my code, telling that my code doesn't
    make sense and it's too complicated.

    Big deal. This is runtime, not compile time.

    Tell me which popular language implements this "value-polymorphism".
    It's a word Wikipedia doesn't know.


    Of course Wikipedia doesn't know it, since it is his own made-up
    term. (Well, his and one other person.)

    The word "polymorphism" means "multiple kinds" or "multiple shapes" -
    it is a term for code that can handle a parameter that can be of many
    different types. So in C++ terms (since this is comp.lang.c++, even
    though Muttley seems to think it is comp.lang.made-up-stuff), you can
    have run-time polymorphism using pointers to base classes and virtual
    functions, and compile-time polymorphism using generics and templates.

    What you can't have is "value" polymorphism - it's an oxymoron.

    I don't think so.
    IMHO, C++ does have features that can be called compile-time value polymorphism without overstretching definition of the word
    'polymorphism'.
    You demonstrated it yourself few posts ago using relatively modern
    C++ features.

    It is not polymorphism. What I demonstrated is value pattern matching,
    and splitting the definition up. You could, at a stretch, call it
    overloading by compile-time constant value.

    Polymorphism is about /types/. And the distinguishing feature from
    overloading is that the polymorphic code is generic to types with
    certain characteristics, not a pre-defined limited set of types.

    Thus :

    void foo(int);
    void foo(double);

    is a set of overloads, while:

    void foo(auto x);

    is (compile-time) polymorphic.


    In compile-time polymorphic code, the function cannot be compiled when
    it is defined - it is only when the function is used that the types are
    known and the function can be compiled. This is different from
    overloading.

    For run-time polymorphic code, the polymorphic function /can/ be
    compiled because the parameter passed contains enough information to
    determine the real type, or at least the required real functionality of
    the type. In C++, this is usually done by virtual functions, but it can
    also be done using std::any.


    But for class templates (as opposed to function
    templates) something that can be reasonably called 'value polymorphism' existed for as long as C++ has templates (1990 ?).

    Class and function templates are polymorphic when they have type
    parameters, and these have been around from early on (I think some time
    between the second edition of "The C++ Programming Language" in 1991,
    and the first C++ standard in 1998). I believe non-type template
    parameters came later than type template parameters, but I don't know
    the historical details. They have, certainly, been around for a long time.

    But while non-type template parameters are perhaps a better candidate
    for "value polymorphism" than anything else in C++, they are not
    polymorphic.


    The feature appears useful in 'pure functional' languages like C++
    template sub-language.

    Templates and template specialisation are certainly useful, as is the
    pattern matching found in functional languages.

    I am not arguing that this kind of thing does not exist in languages, or
    that it is not useful - I am arguing that it is not known as "value polymorphism" and is not "polymorphism" at all, as the term is generally
    used.


    Of course, it is less useful, and probably not
    desirable in mixed functional/imperative environments where you can
    achieve the same result in several simpler ways.

    The
    common term for code that can handle parameters taking multiple
    different values is "function".



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Tue Oct 1 13:08:31 2024
    On 01/10/2024 12:01, [email protected] wrote:
    On Tue, 1 Oct 2024 10:42:06 +0200
    David Brown <[email protected]> boring babbled:
    What you can't have is "value" polymorphism - it's an oxymoron. The

    No it isn't, your brain just can't understand the concept even with now
    2 pieces of example code.

    I know exactly what you mean by your example. But it is not
    "polymorphism" of any sort.


    common term for code that can handle parameters taking multiple
    different values is "function".

    So C++ can differentiate a functions with the same name based on the
    passed value at runtime can it? Not last time I checked.


    void foo(int x) {
    if (x == 0) {
    printf("Muttley ");
    } else if (x == 1) {
    printf("has no idea ");
    } else {
    printf("what he is talking about.\n");
    }
    }


    Muttley doesn't even seem to know what he means by the term. He has

    I know perfectly well what it means, you're just dim.

    tl;dr


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 16:14:10 2024
    On Tue, 1 Oct 2024 12:58:32 +0200
    Bonita Montero <[email protected]> boring babbled:
    Am 01.10.2024 um 11:58 schrieb [email protected]:

    Because its not valid C++! I was using modified C++ syntax to keep people >happy
    since they couldn't figure out the syntax of the functional language I used.

    Talk about real languages an not languages you've invented ad-hoc.
    The code you've shown doesn't make sense at all.

    You're little more than a dictionary. You know the C++ syntax inside
    out but you don't really understand computer science concepts.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 16:13:29 2024
    On Tue, 1 Oct 2024 13:11:41 +0300
    Michael S <[email protected]> boring babbled:
    On Tue, 1 Oct 2024 10:02:48 -0000 (UTC)
    [email protected] wrote:

    On Tue, 1 Oct 2024 12:53:32 +0300
    Michael S <[email protected]> boring babbled:
    The feature appears useful in 'pure functional' languages like C++
    template sub-language. Of course, it is less useful, and probably not
    desirable in mixed functional/imperative environments where you can
    achieve the same result in several simpler ways.

    All polymorphism can be achieved in simpler/cruder ways. Its simply a
    syntatic nicety.


    The point is that if your language is not 'pure functional' then those
    other ways (if, switch) are not 'cruder'. They are finer.
    The selection written as if/switch is both shorter and easier to follow
    than selection based on 'value polymorphism'.

    Personally I prefer seperate function names instead of overloaded
    functions and I don't often like operator overloading but they're
    part of C++. Presumably you feel the same way? Can't have it both
    ways mate.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Tue Oct 1 16:15:19 2024
    On Tue, 1 Oct 2024 13:08:31 +0200
    David Brown <[email protected]> boring babbled:
    On 01/10/2024 12:01, [email protected] wrote:
    On Tue, 1 Oct 2024 10:42:06 +0200
    David Brown <[email protected]> boring babbled:
    What you can't have is "value" polymorphism - it's an oxymoron. The

    No it isn't, your brain just can't understand the concept even with now
    2 pieces of example code.

    I know exactly what you mean by your example. But it is not
    "polymorphism" of any sort.

    Whatever. I'm tired of arguing semantics. You're just moving
    goalposts in order not to look stupid in hindsight. Have it
    your way.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to [email protected] on Tue Oct 1 21:50:50 2024
    On Tue, 1 Oct 2024 16:13:29 -0000 (UTC)
    [email protected] wrote:

    On Tue, 1 Oct 2024 13:11:41 +0300
    Michael S <[email protected]> boring babbled:
    On Tue, 1 Oct 2024 10:02:48 -0000 (UTC)
    [email protected] wrote:

    On Tue, 1 Oct 2024 12:53:32 +0300
    Michael S <[email protected]> boring babbled:
    The feature appears useful in 'pure functional' languages like C++
    template sub-language. Of course, it is less useful, and probably
    not desirable in mixed functional/imperative environments where
    you can achieve the same result in several simpler ways.

    All polymorphism can be achieved in simpler/cruder ways. Its
    simply a syntatic nicety.


    The point is that if your language is not 'pure functional' then
    those other ways (if, switch) are not 'cruder'. They are finer.
    The selection written as if/switch is both shorter and easier to
    follow than selection based on 'value polymorphism'.

    Personally I prefer seperate function names instead of overloaded
    functions and I don't often like operator overloading but they're
    part of C++. Presumably you feel the same way? Can't have it both
    ways mate.


    I do feel the same way, but that's completely differrent issue.

    The best C++ solution (actually, it is the best solution not just in C++
    but in any language that is not pure functional) for your 'value
    polimorphism' example is not separte function names, but a single
    function with switch in the body.

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Tue Oct 1 20:06:20 2024
    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From User@21:1/5 to Tim Rentsch on Wed Oct 2 05:47:58 2024
    On 02/10/2024 04:06, Tim Rentsch wrote:
    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?


    F# (a.k.a F sharp)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Oct 2 07:13:53 2024
    On Tue, 1 Oct 2024 21:50:50 +0300
    Michael S <[email protected]> boring babbled:
    On Tue, 1 Oct 2024 16:13:29 -0000 (UTC)
    [email protected] wrote:
    Personally I prefer seperate function names instead of overloaded
    functions and I don't often like operator overloading but they're
    part of C++. Presumably you feel the same way? Can't have it both
    ways mate.


    I do feel the same way, but that's completely differrent issue.

    The best C++ solution (actually, it is the best solution not just in C++
    but in any language that is not pure functional) for your 'value >polimorphism' example is not separte function names, but a single
    function with switch in the body.

    Yes, obviously. But thats wandering into the "C can do anything C++ can do" (and same for assember and C) territory. Thats not the point , the point is
    to make things simpler in some circumstances.

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    Well I don't use them day to day either.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Oct 2 07:11:48 2024
    On Tue, 1 Oct 2024 19:43:29 +0200
    Bonita Montero <[email protected]> boring babbled:
    Am 01.10.2024 um 18:14 schrieb [email protected]:
    On Tue, 1 Oct 2024 12:58:32 +0200
    Bonita Montero <[email protected]> boring babbled:
    Am 01.10.2024 um 11:58 schrieb [email protected]:

    Because its not valid C++! I was using modified C++ syntax to keep people >>> happy
    since they couldn't figure out the syntax of the functional language I >used.

    Talk about real languages an not languages you've invented ad-hoc.
    The code you've shown doesn't make sense at all.

    You're little more than a dictionary. You know the C++ syntax inside
    out but you don't really understand computer science concepts.


    I've studied applied computer sciences in Germany / Iserlohn in the 90s.

    Doesn't mean you remember any of it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Wed Oct 2 13:02:36 2024
    On Tue, 01 Oct 2024 20:06:20 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    C++ templates sub-languges. I.e. approximately compile-time part of
    C++ taken in isolation from run-time part and without C++11 and later additions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andrey Tarasevich@21:1/5 to Paavo Helde on Thu Sep 26 18:22:17 2024
    On 09/25/24 5:49 AM, Paavo Helde wrote:

    Callback functions are a C thing. In C++ we have functors and lambdas.
    Over the years I have removed all ancient callback functions from my
    code and replaced by functors or lambdas, so your "most common use case"
    is not everybody's use case.


    "Functors and lambdas" require compile-time polymorphism, which makes
    them applicable in fairly compact algorithms only. The moment the
    calling code ceases to be compact we end up with massive template code
    bloat. And the solution to code bloat is run-time polymorphism, which is essentially... callbacks.

    To be fair, C++ offers run-time polymorphism combined with type-erasure
    nicely wrapped into `std::function<>`, which works as a remedy for
    template code bloat. But expectedly, you pay for `std::function<>` with
    the same performance-related overhead as callbacks, if not more.

    --
    Best regards,
    Andrey

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to [email protected] on Fri Sep 27 02:27:52 2024
    [email protected] writes:

    On Wed, 25 Sep 2024 17:33:41 +0200
    Bonita Montero <[email protected]> boringly babbled:

    Am 25.09.2024 um 17:32 schrieb [email protected]:

    I understand both types of polymorphism, you nothing.

    You don't have clue. ...

    And you have your own definition of polymorphism.

    Thanks for proving my point. A proper functional language has value polymorphism (which clearly you don't understand) as well as type polymorphism.

    https://chrisdone.com/posts/value-polymorphism/

    Neither "value polymorphism" nor "polymorphism by value" is a
    common term.

    They mean different things.

    Polymorphism by value was discussed in a 1993 paper by Xavier
    Leroy.

    Value polymorphism, as it is described in the cited web page, is
    simply overloading of variables rather than functions.
    (Overloading is often called "ad hoc polymorphism".)

    Neither overloading of functions nor overloading of variables has
    anything to do with functional programming. Overloading might be
    supported in some functional programming languages (and it is in
    some non-functional languages, notably C++), but overloading is
    orthogonal to the notion of functional programming.

    Supporting polymorphism is not a pre-requisite either for doing
    functional programming or for a language being a functional
    language. There are plenty of functional programming languages
    that don't have facilities for polymorphism, as for example the
    original Lisp.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Fri Sep 27 11:11:35 2024
    On Fri, 27 Sep 2024 02:27:52 -0700
    Tim Rentsch <[email protected]> boringly babbled: >[email protected] writes:
    Thanks for proving my point. A proper functional language has value
    polymorphism (which clearly you don't understand) as well as type
    polymorphism.

    https://chrisdone.com/posts/value-polymorphism/

    Neither "value polymorphism" nor "polymorphism by value" is a
    common term.

    Because not many languages support it.

    They mean different things.

    Not in the version of english I speak they don't.

    Polymorphism by value was discussed in a 1993 paper by Xavier
    Leroy.

    Who?

    Value polymorphism, as it is described in the cited web page, is
    simply overloading of variables rather than functions.
    (Overloading is often called "ad hoc polymorphism".)

    Thats his opinion.

    Neither overloading of functions nor overloading of variables has
    anything to do with functional programming. Overloading might be

    Without it many of the standard examples of functional programming simply
    won't run.

    that don't have facilities for polymorphism, as for example the
    original Lisp.

    Since when was Lisp a functional language? Scheme maybe.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Fri Sep 27 16:14:29 2024
    On 27/09/2024 13:11, [email protected] wrote:
    On Fri, 27 Sep 2024 02:27:52 -0700
    Tim Rentsch <[email protected]> boringly babbled:
    [email protected] writes:
    Thanks for proving my point. A proper functional language has value
    polymorphism (which clearly you don't understand) as well as type
    polymorphism.

    https://chrisdone.com/posts/value-polymorphism/

    Neither "value polymorphism" nor "polymorphism by value" is a
    common term.

    <snip>
    Neither overloading of functions nor overloading of variables has
    anything to do with functional programming. Overloading might be

    Without it many of the standard examples of functional programming simply won't run.


    Are you talking about what is more commonly referred to as pattern matching?

    factorial 0 = 1
    factorial n = n * factorial (n - 1)


    That is not what is generally meant by polymorphism, it's just an
    alternative (but often very neat) way to write a conditional :

    factorial n = if n < 2
    then 1
    else n * factorial (n - 1)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Fri Sep 27 15:25:20 2024
    On Fri, 27 Sep 2024 16:14:29 +0200
    David Brown <[email protected]> boringly babbled:
    On 27/09/2024 13:11, [email protected] wrote:
    On Fri, 27 Sep 2024 02:27:52 -0700
    Tim Rentsch <[email protected]> boringly babbled:
    [email protected] writes:
    Thanks for proving my point. A proper functional language has value
    polymorphism (which clearly you don't understand) as well as type
    polymorphism.

    https://chrisdone.com/posts/value-polymorphism/

    Neither "value polymorphism" nor "polymorphism by value" is a
    common term.

    <snip>
    Neither overloading of functions nor overloading of variables has
    anything to do with functional programming. Overloading might be

    Without it many of the standard examples of functional programming simply
    won't run.


    Are you talking about what is more commonly referred to as pattern matching?

    I've already posted a link to an article about it. Whatever you want to call it, the polymorphic function called is based on the value passed to it, not
    the type.


    factorial 0 = 1
    factorial n = n * factorial (n - 1)


    That is not what is generally meant by polymorphism, it's just an
    alternative (but often very neat) way to write a conditional :

    That applies to all types of polymorphism. All decisional code however its written eventually ends up as some kind of assembler cmp/jmp combination.
    Might be 2 opcodes, might be 1, doesn't matter, same thing.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to [email protected] on Fri Sep 27 18:24:11 2024
    On 27/09/2024 17:25, [email protected] wrote:
    On Fri, 27 Sep 2024 16:14:29 +0200
    David Brown <[email protected]> boringly babbled:
    On 27/09/2024 13:11, [email protected] wrote:
    On Fri, 27 Sep 2024 02:27:52 -0700
    Tim Rentsch <[email protected]> boringly babbled:
    [email protected] writes:
    Thanks for proving my point. A proper functional language has value >>>>> polymorphism (which clearly you don't understand) as well as type
    polymorphism.

    https://chrisdone.com/posts/value-polymorphism/

    Neither "value polymorphism" nor "polymorphism by value" is a
    common term.

    <snip>
    Neither overloading of functions nor overloading of variables has
    anything to do with functional programming. Overloading might be

    Without it many of the standard examples of functional programming simply >>> won't run.


    Are you talking about what is more commonly referred to as pattern matching?

    I've already posted a link to an article about it. Whatever you want to call it, the polymorphic function called is based on the value passed to it, not the type.


    factorial 0 = 1
    factorial n = n * factorial (n - 1)


    That is not what is generally meant by polymorphism, it's just an
    alternative (but often very neat) way to write a conditional :

    That applies to all types of polymorphism. All decisional code however its written eventually ends up as some kind of assembler cmp/jmp combination. Might be 2 opcodes, might be 1, doesn't matter, same thing.



    The key point of polymorphism - as I see it - is that the source code
    doing the dispatching does not know the details of the possible matches
    or targets. Thus C++ virtual methods support polymorphism - a function
    call call "p->foo()" for "p" of type "T*" without knowing anything about
    how many descendent types of "T" exist or how they different. All it
    needs to know is that the base class "T" has a virtual method "foo".

    This cannot be done with a series of cmp/jmp instructions - it ends up
    as an indirect call instruction.


    For static or compile-time polymorphism, the details of the generated
    code are not as important, but you still want the code that uses the polymorphic types, values, objects, whatever, to be independent of the
    things themselves. You get that in C++ CRTP templates, for example.


    I don't claim to have any kind of "official" definition of the term, but
    I am pretty confident that what you seem to be talking about (AFAIUI) is
    not something many people would refer to as "polymorphism"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sat Sep 28 09:12:56 2024
    On Fri, 27 Sep 2024 18:24:11 +0200
    David Brown <[email protected]> gabbled:
    On 27/09/2024 17:25, [email protected] wrote:
    That applies to all types of polymorphism. All decisional code however its >> written eventually ends up as some kind of assembler cmp/jmp combination.
    Might be 2 opcodes, might be 1, doesn't matter, same thing.



    The key point of polymorphism - as I see it - is that the source code
    doing the dispatching does not know the details of the possible matches
    or targets. Thus C++ virtual methods support polymorphism - a function

    Not sure how that differs with value polymorphism.

    call call "p->foo()" for "p" of type "T*" without knowing anything about
    how many descendent types of "T" exist or how they different. All it
    needs to know is that the base class "T" has a virtual method "foo".

    This cannot be done with a series of cmp/jmp instructions - it ends up
    as an indirect call instruction.

    It could quite easily, but yes, a call is more likely. Point still stands however.

    I am pretty confident that what you seem to be talking about (AFAIUI) is
    not something many people would refer to as "polymorphism"

    When you say "people" you seem to be talking about people in the C++ world
    or perhaps C-type language world. Polymorphism is more than just type and virtual functions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to User on Fri Oct 4 06:52:40 2024
    User <[email protected]> writes:

    On 02/10/2024 04:06, Tim Rentsch wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    F# (a.k.a F sharp)

    F# has mutable* variables, mutable* record fields, mutable arrays,
    mutable hash tables, for loops, while loops, and no doubt other
    imperative constructs such as I/O and sequencing (where the *
    means mutable is an optional attribute).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Fri Oct 4 13:57:11 2024
    On Fri, 04 Oct 2024 06:52:40 -0700
    Tim Rentsch <[email protected]> boring babbled:
    User <[email protected]> writes:

    On 02/10/2024 04:06, Tim Rentsch wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    F# (a.k.a F sharp)

    F# has mutable* variables, mutable* record fields, mutable arrays,
    mutable hash tables, for loops, while loops, and no doubt other
    imperative constructs such as I/O and sequencing (where the *
    means mutable is an optional attribute).

    Surely a "pure" functional language doesn't have imperative loop constructs?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Fri Oct 4 06:57:32 2024
    Michael S <[email protected]> writes:

    On Tue, 01 Oct 2024 20:06:20 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    C++ templates sub-languges. I.e. approximately compile-time part of
    C++ taken in isolation from run-time part and without C++11 and later additions.

    If that's your only example then not very much is excluded.
    It's like saying you don't want to program Turing Machines.
    Are there any mainstream languages you would count as purely
    functional? (I think it's fair to say that the C++ template
    sub-language is not a mainstream language.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Sun Oct 6 14:19:07 2024
    On Fri, 04 Oct 2024 06:57:32 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Tue, 01 Oct 2024 20:06:20 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    C++ templates sub-languges. I.e. approximately compile-time part of
    C++ taken in isolation from run-time part and without C++11 and
    later additions.

    If that's your only example then not very much is excluded.

    Since I don't like functional programming it seems to me rather natural
    that I am positioned as far as it goes from being an expert in the
    field.

    So far I found only one field of computer programming that I like even
    less - regular expressions.

    It's like saying you don't want to program Turing Machines.
    Are there any mainstream languages you would count as purely
    functional? (I think it's fair to say that the C++ template
    sub-language is not a mainstream language.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Sun Oct 6 14:22:47 2024
    On 06/10/2024 13:19, Michael S wrote:
    On Fri, 04 Oct 2024 06:57:32 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Tue, 01 Oct 2024 20:06:20 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    C++ templates sub-languges. I.e. approximately compile-time part of
    C++ taken in isolation from run-time part and without C++11 and
    later additions.

    If that's your only example then not very much is excluded.

    Since I don't like functional programming it seems to me rather natural
    that I am positioned as far as it goes from being an expert in the
    field.


    Perhaps it would help if you describe what the term "functional
    programming" means to you. We could look at particular aspects or
    features that are commonly considered relevant to functional
    programming, and think about whether there are some things you like and
    others that you find distasteful for some reason. (I am not trying to
    persuade you to switch to Haskell or to change your opinions, but
    perhaps you'll get a better understanding why some people like
    functional programming, and others will get a better understanding of
    why some people dislike it.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Mon Oct 7 09:11:29 2024
    Michael S <[email protected]> writes:

    On Fri, 04 Oct 2024 06:57:32 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Tue, 01 Oct 2024 20:06:20 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    C++ templates sub-languges. I.e. approximately compile-time part of
    C++ taken in isolation from run-time part and without C++11 and
    later additions.

    If that's your only example then not very much is excluded.

    Since I don't like functional programming it seems to me rather
    natural that I am positioned as far as it goes from being an
    expert in the field.

    Sorry, I think my comment came across wrongly. The point of my
    question is not to criticize your reactions but to understand
    just what things you are reacting to. Different people have
    different ideas of what "functional programming" means. What
    language qualities make a language one you would rather avoid?
    Or conversely, what attributes tend to make a language attractive
    or one that you would prefer?

    So far I found only one field of computer programming that I like
    even less - regular expressions.

    I admit to being puzzled by this reaction. Regular expressions tend
    not to be very useful outside of a rather narrow niche, but inside
    their domain of application they are pretty handy. Are you saying
    that you would rather not use regular expressions even in situations
    where they are convenient? Or is it that you don't find such cases
    coming up in your regular programming activities?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Mon Oct 7 22:53:15 2024
    On Mon, 07 Oct 2024 09:11:29 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Fri, 04 Oct 2024 06:57:32 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Tue, 01 Oct 2024 20:06:20 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure functional
    languges is to avoid programming in such languages.

    What do you count as a pure functional language?

    C++ templates sub-languges. I.e. approximately compile-time part
    of C++ taken in isolation from run-time part and without C++11 and
    later additions.

    If that's your only example then not very much is excluded.

    Since I don't like functional programming it seems to me rather
    natural that I am positioned as far as it goes from being an
    expert in the field.

    Sorry, I think my comment came across wrongly. The point of my
    question is not to criticize your reactions but to understand
    just what things you are reacting to. Different people have
    different ideas of what "functional programming" means. What
    language qualities make a language one you would rather avoid?

    Since we are in C++ group, let's take examples from C++.
    I never use std::for_each().
    I don't use lambda expressions as argument for 'compare' parameter in std::sort or std::nth_element. If it was possible, I wouldn't use
    object of class with operator() for such parameter either. Instead I
    would prefer pointer to normal named member function. May be, it is
    possible, but I don't know the syntax. I hate functional stuff pushed
    down my throat by <random> and would very much prefer the same very
    useful functionality provided in other way.

    Or conversely, what attributes tend to make a language attractive
    or one that you would prefer?


    I prefer to see sequence of steps. Or, at least to have some idea about
    it in 'as if' fashion.

    So far I found only one field of computer programming that I like
    even less - regular expressions.

    I admit to being puzzled by this reaction. Regular expressions tend
    not to be very useful outside of a rather narrow niche, but inside
    their domain of application they are pretty handy. Are you saying
    that you would rather not use regular expressions even in situations
    where they are convenient?

    Yes, if I could, I wouldn't use regular expressions at all.
    But CAD tools for FPGA development are build in such ways that
    sometimes regular expressions are necessary to achieve my objectives.
    The result is that not very often, but far more often than I would
    like, results do not match expectations. And when it happens, it is
    *always* very hard to find a reason.

    Or is it that you don't find such cases
    coming up in your regular programming activities?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Michael S on Tue Oct 8 18:11:40 2024
    On 07.10.2024 22:53, Michael S wrote:
    I don't use lambda expressions as argument for 'compare' parameter in std::sort or std::nth_element. If it was possible, I wouldn't use
    object of class with operator() for such parameter either. Instead I
    would prefer pointer to normal named member function.

    I prefer to see sequence of steps. Or, at least to have some idea about
    it in 'as if' fashion.

    You can easily use a normal named member function for comparison, you
    just need a small lambda for calling it.

    #include <vector>
    #include <algorithm>
    #include <iostream>

    class A {
    public:
    int key_;
    int type_;

    bool MyLess(const A& other) const {
    return key_ < other.key_ || (key_ == other.key_ && type_ < other.type_);
    }
    };


    int main() {
    std::vector<A> vv{ {12, 50}, {13,12}, {3,7}, {12, 49} };
    std::sort(vv.begin(), vv.end(), [](const A& x, const A& y) {return x.MyLess(y); });
    for (A& ref : vv) {
    std::cout << ref.key_ << " " << ref.type_ << "\n";
    }
    }

    I like lambda because here I "see the sequence of steps". The earlier std::bind1st et al were horrific, never used them. Lambda is much better.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Paavo Helde on Tue Oct 8 22:48:16 2024
    On Tue, 8 Oct 2024 18:11:40 +0300
    Paavo Helde <[email protected]> wrote:

    On 07.10.2024 22:53, Michael S wrote:
    I don't use lambda expressions as argument for 'compare' parameter
    in std::sort or std::nth_element. If it was possible, I wouldn't use
    object of class with operator() for such parameter either. Instead I
    would prefer pointer to normal named member function.

    I prefer to see sequence of steps. Or, at least to have some idea
    about it in 'as if' fashion.

    You can easily use a normal named member function for comparison, you
    just need a small lambda for calling it.

    #include <vector>
    #include <algorithm>
    #include <iostream>

    class A {
    public:
    int key_;
    int type_;

    bool MyLess(const A& other) const {
    return key_ < other.key_ || (key_ == other.key_ &&
    type_ < other.type_); }
    };


    int main() {
    std::vector<A> vv{ {12, 50}, {13,12}, {3,7}, {12, 49} };
    std::sort(vv.begin(), vv.end(), [](const A& x, const A& y)
    {return x.MyLess(y); });
    for (A& ref : vv) {
    std::cout << ref.key_ << " " << ref.type_ << "\n";
    }
    }

    I like lambda because here I "see the sequence of steps". The earlier std::bind1st et al were horrific, never used them. Lambda is much
    better.


    You has shown an easy case of context free comparison and how to avoid operator<() in this easy case.
    I was talking about less trivial case of context-aware comparison and
    about my desire to avoid operator().

    Much better(IMHO) solution for your simple case was available since day
    one of STL:

    #include <algorithm>
    #include <cstdio>

    class A {
    public:
    int key_;
    int type_;

    static inline bool MyLess(const A& a, const A& b) {
    return a.key_ < b.key_ || (a.key_ == b.key_ && a.type_
    < b.type_); }
    };


    int main() {
    A vv[] = { {12, 50}, {13,12}, {3,7}, {12, 49} };
    std::sort(&vv[0], &vv[4], A::MyLess);
    for (int i = 0; i < 4; ++i)
    printf("%d %d\n", vv[i].key_, vv[i].type_);
    }




    Here is an example of more interesting sort that demonstrates what I was talking about and where I would like to use bwt_cmp_t::less directly
    instead of via operator():

    #include <cstdint>
    #include <cstring>
    #include <algorithm>

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen)
    {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen-b);
    if (diff == 0) {
    diff = memcmp(&src[a+srclen-b], &src[0], b-a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b-a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    bool operator() (int a, int b) const {
    return less(a, b);
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;
    std::sort(dst, dst+srclen, cmp);
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Michael S on Wed Oct 9 00:12:25 2024
    On 08.10.2024 22:48, Michael S wrote:
    On Tue, 8 Oct 2024 18:11:40 +0300
    Paavo Helde <[email protected]> wrote:

    On 07.10.2024 22:53, Michael S wrote:
    I don't use lambda expressions as argument for 'compare' parameter
    in std::sort or std::nth_element. If it was possible, I wouldn't use
    object of class with operator() for such parameter either. Instead I
    would prefer pointer to normal named member function.

    I prefer to see sequence of steps. Or, at least to have some idea
    about it in 'as if' fashion.

    You can easily use a normal named member function for comparison, you
    just need a small lambda for calling it.

    #include <vector>
    #include <algorithm>
    #include <iostream>

    class A {
    public:
    int key_;
    int type_;

    bool MyLess(const A& other) const {
    return key_ < other.key_ || (key_ == other.key_ &&
    type_ < other.type_); }
    };


    int main() {
    std::vector<A> vv{ {12, 50}, {13,12}, {3,7}, {12, 49} };
    std::sort(vv.begin(), vv.end(), [](const A& x, const A& y)
    {return x.MyLess(y); });
    for (A& ref : vv) {
    std::cout << ref.key_ << " " << ref.type_ << "\n";
    }
    }

    I like lambda because here I "see the sequence of steps". The earlier
    std::bind1st et al were horrific, never used them. Lambda is much
    better.


    You has shown an easy case of context free comparison and how to avoid operator<() in this easy case.
    I was talking about less trivial case of context-aware comparison and
    about my desire to avoid operator().

    Much better(IMHO) solution for your simple case was available since day
    one of STL:

    #include <algorithm>
    #include <cstdio>

    class A {
    public:
    int key_;
    int type_;

    static inline bool MyLess(const A& a, const A& b) {
    return a.key_ < b.key_ || (a.key_ == b.key_ && a.type_
    < b.type_); }
    };


    int main() {
    A vv[] = { {12, 50}, {13,12}, {3,7}, {12, 49} };
    std::sort(&vv[0], &vv[4], A::MyLess);
    for (int i = 0; i < 4; ++i)
    printf("%d %d\n", vv[i].key_, vv[i].type_);
    }




    Here is an example of more interesting sort that demonstrates what I was talking about and where I would like to use bwt_cmp_t::less directly
    instead of via operator():

    #include <cstdint>
    #include <cstring>
    #include <algorithm>

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen)
    {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen-b);
    if (diff == 0) {
    diff = memcmp(&src[a+srclen-b], &src[0], b-a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b-a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    bool operator() (int a, int b) const {
    return less(a, b);
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;
    std::sort(dst, dst+srclen, cmp);
    }


    The context state is the bread and butter of lambda. If all you want is
    to avoid operator(), this can be done easily:

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen) {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen - b);
    if (diff == 0) {
    diff = memcmp(&src[a + srclen - b], &src[0], b - a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b - a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;
    std::sort(dst, dst + srclen, [&cmp](int a, int b) {return
    cmp.less(a, b); });
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Paavo Helde on Wed Oct 9 01:06:05 2024
    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:



    The context state is the bread and butter of lambda. If all you want
    is to avoid operator(), this can be done easily:


    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to] object +
    [pointer to] its honest old member function. And I am not obsessed
    with idea that it has to be a single prameter at all cost; I see nothing
    wrong if two separate parameters needed to do the job.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Michael S on Wed Oct 9 08:25:20 2024
    On 09.10.2024 01:06, Michael S wrote:
    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:



    The context state is the bread and butter of lambda. If all you want
    is to avoid operator(), this can be done easily:


    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to] object +
    [pointer to] its honest old member function. And I am not obsessed
    with idea that it has to be a single prameter at all cost; I see nothing wrong if two separate parameters needed to do the job.


    Not quite sure why you might want this, but here it goes:

    // Ugly lambda hidden in a common header
    namespace std2 {
    template<class ELEM, class COMP>
    void sort(ELEM* begin, ELEM* end, const COMP& comp, bool (COMP::* member)(ELEM, ELEM) const) {
    std::sort(begin, end, [&comp, member](const ELEM& a, const
    ELEM& b) {return (comp.*member)(a, b); });
    }
    }

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen) {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen - b);
    if (diff == 0) {
    diff = memcmp(&src[a + srclen - b], &src[0], b - a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b - a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;

    // Usage without lambda as desired
    std2::sort(dst, dst + srclen, cmp, &bwt_cmp_t::less);
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Bonita Montero on Wed Oct 9 10:26:31 2024
    On 09.10.2024 09:28, Bonita Montero wrote:
    Am 09.10.2024 um 07:25 schrieb Paavo Helde:

    Not quite sure why you might want this, but here it goes:

    // Ugly lambda hidden in a common header
    namespace std2 {
         template<class ELEM, class COMP>
         void sort(ELEM* begin, ELEM* end, const COMP& comp, bool (COMP::* >> member)(ELEM, ELEM) const) {
             std::sort(begin, end, [&comp, member](const ELEM& a, const >> ELEM& b) {return (comp.*member)(a, b); });
         }
    }

    Use iterators !

    Iterators, concepts and any needed type deduction is left as an exercise
    for the reader ;-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Wed Oct 9 09:31:55 2024
    On Wed, 9 Oct 2024 10:26:31 +0300
    Paavo Helde <[email protected]> boring babbled:
    On 09.10.2024 09:28, Bonita Montero wrote:
    Am 09.10.2024 um 07:25 schrieb Paavo Helde:

    Not quite sure why you might want this, but here it goes:

    // Ugly lambda hidden in a common header
    namespace std2 {
         template<class ELEM, class COMP>
         void sort(ELEM* begin, ELEM* end, const COMP& comp, bool (COMP::* >>> member)(ELEM, ELEM) const) {
             std::sort(begin, end, [&comp, member](const ELEM& a, const

    ELEM& b) {return (comp.*member)(a, b); });
         }
    }

    Use iterators !

    Iterators, concepts and any needed type deduction is left as an exercise
    for the reader ;-)

    A C-style function pointer to a member function - been a while since I've
    seen one of them!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Paavo Helde on Wed Oct 9 13:58:25 2024
    On Wed, 9 Oct 2024 08:25:20 +0300
    Paavo Helde <[email protected]> wrote:

    On 09.10.2024 01:06, Michael S wrote:
    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:



    The context state is the bread and butter of lambda. If all you
    want is to avoid operator(), this can be done easily:


    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to] object + [pointer to] its honest old member function. And I am not obsessed
    with idea that it has to be a single prameter at all cost; I see
    nothing wrong if two separate parameters needed to do the job.


    Not quite sure why you might want this, but here it goes:

    // Ugly lambda hidden in a common header
    namespace std2 {
    template<class ELEM, class COMP>
    void sort(ELEM* begin, ELEM* end, const COMP& comp, bool
    (COMP::* member)(ELEM, ELEM) const) {
    std::sort(begin, end, [&comp, member](const ELEM& a, const
    ELEM& b) {return (comp.*member)(a, b); });
    }
    }

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen) {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen - b);
    if (diff == 0) {
    diff = memcmp(&src[a + srclen - b], &src[0], b - a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b - a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;

    // Usage without lambda as desired
    std2::sort(dst, dst + srclen, cmp, &bwt_cmp_t::less);
    }




    Unfortunately, it is not the same.
    Unlike all previous variant, compiler implements this one via dynamic
    dispatch (indirect call).
    At least that's what I see with gcc compiler both at -O2 and at -O3.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Michael S on Wed Oct 9 14:39:34 2024
    On 09.10.2024 13:58, Michael S wrote:
    On Wed, 9 Oct 2024 08:25:20 +0300
    Paavo Helde <[email protected]> wrote:

    On 09.10.2024 01:06, Michael S wrote:
    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:



    The context state is the bread and butter of lambda. If all you
    want is to avoid operator(), this can be done easily:


    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to] object +
    [pointer to] its honest old member function. And I am not obsessed
    with idea that it has to be a single prameter at all cost; I see
    nothing wrong if two separate parameters needed to do the job.


    Not quite sure why you might want this, but here it goes:

    // Ugly lambda hidden in a common header
    namespace std2 {
    template<class ELEM, class COMP>
    void sort(ELEM* begin, ELEM* end, const COMP& comp, bool
    (COMP::* member)(ELEM, ELEM) const) {
    std::sort(begin, end, [&comp, member](const ELEM& a, const
    ELEM& b) {return (comp.*member)(a, b); });
    }
    }

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen) {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen - b);
    if (diff == 0) {
    diff = memcmp(&src[a + srclen - b], &src[0], b - a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b - a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;

    // Usage without lambda as desired
    std2::sort(dst, dst + srclen, cmp, &bwt_cmp_t::less);
    }




    Unfortunately, it is not the same.
    Unlike all previous variant, compiler implements this one via dynamic dispatch (indirect call).
    At least that's what I see with gcc compiler both at -O2 and at -O3.

    That's right, one reason for preferring functional style functors and
    lambdas over bare function pointers is that they can be optimized better
    by the compiler, in general. But beauty requires sacrifice, so you have
    to live with that!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Paavo Helde on Wed Oct 9 19:59:14 2024
    On Wed, 9 Oct 2024 14:39:34 +0300
    Paavo Helde <[email protected]> wrote:

    On 09.10.2024 13:58, Michael S wrote:
    On Wed, 9 Oct 2024 08:25:20 +0300
    Paavo Helde <[email protected]> wrote:

    On 09.10.2024 01:06, Michael S wrote:
    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:



    The context state is the bread and butter of lambda. If all you
    want is to avoid operator(), this can be done easily:


    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to]
    object + [pointer to] its honest old member function. And I am
    not obsessed with idea that it has to be a single prameter at all
    cost; I see nothing wrong if two separate parameters needed to do
    the job.

    Not quite sure why you might want this, but here it goes:

    // Ugly lambda hidden in a common header
    namespace std2 {
    template<class ELEM, class COMP>
    void sort(ELEM* begin, ELEM* end, const COMP& comp, bool
    (COMP::* member)(ELEM, ELEM) const) {
    std::sort(begin, end, [&comp, member](const ELEM& a,
    const ELEM& b) {return (comp.*member)(a, b); });
    }
    }

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen) {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen - b);
    if (diff == 0) {
    diff = memcmp(&src[a + srclen - b], &src[0], b -
    a); if (diff == 0) {
    diff = memcmp(&src[0], &src[b - a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;

    // Usage without lambda as desired
    std2::sort(dst, dst + srclen, cmp, &bwt_cmp_t::less);
    }




    Unfortunately, it is not the same.
    Unlike all previous variant, compiler implements this one via
    dynamic dispatch (indirect call).
    At least that's what I see with gcc compiler both at -O2 and at
    -O3.

    That's right, one reason for preferring functional style functors and
    lambdas over bare function pointers is that they can be optimized
    better by the compiler, in general. But beauty requires sacrifice, so
    you have to live with that!






    Here is a variant without sacrifice. It is less pretty at the call site
    - too many template arguments.
    The advantage of it that it works the same both with std::sort and for std::nth_element.
    This variant uses normal function instead of member function. Not
    because it is impossible to do the same with member, but because I am
    not fluent with necessary syntax.

    #include <cstdint>
    #include <cstring>
    #include <algorithm>

    // Ugly template hidden in a common header
    template < typename ELEM, typename Comparison_context,
    bool Compare(Comparison_context,ELEM,ELEM) >
    class TCompare3 {
    const Comparison_context& m_context;
    public:
    TCompare3(const Comparison_context& a):m_context(a){};
    bool operator() (ELEM a, ELEM b) {
    return Compare(m_context, a, b);
    }
    };

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen)
    {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    static
    inline
    bool less(bwt_cmp_t* obj, int a, int b) {
    if (a >= b) {
    if (a > b)
    return !less(obj, b, a);
    return false; // a == b
    }
    // a < b;
    const uint8_t* src = obj->src;
    const int srclen = obj->srclen;
    int diff = memcmp(&src[a], &src[b], srclen - b);
    if (diff == 0) {
    diff = memcmp(&src[a + srclen - b], &src[0], b - a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b - a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;
    std::sort(dst, dst + srclen,
    TCompare3<int, bwt_cmp_t*, bwt_cmp_t::less>(&cmp));
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Michael S on Wed Oct 9 22:37:19 2024
    On 09.10.2024 19:59, Michael S wrote:
    On Wed, 9 Oct 2024 14:39:34 +0300
    Paavo Helde <[email protected]> wrote:

    On 09.10.2024 13:58, Michael S wrote:
    On Wed, 9 Oct 2024 08:25:20 +0300
    Paavo Helde <[email protected]> wrote:

    On 09.10.2024 01:06, Michael S wrote:
    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:



    The context state is the bread and butter of lambda. If all you
    want is to avoid operator(), this can be done easily:


    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to]
    object + [pointer to] its honest old member function. And I am
    not obsessed with idea that it has to be a single prameter at all
    cost; I see nothing wrong if two separate parameters needed to do
    the job.

    Not quite sure why you might want this, but here it goes:

    // Ugly lambda hidden in a common header
    namespace std2 {
    template<class ELEM, class COMP>
    void sort(ELEM* begin, ELEM* end, const COMP& comp, bool
    (COMP::* member)(ELEM, ELEM) const) {
    std::sort(begin, end, [&comp, member](const ELEM& a,
    const ELEM& b) {return (comp.*member)(a, b); });
    }
    }

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen) {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen - b);
    if (diff == 0) {
    diff = memcmp(&src[a + srclen - b], &src[0], b -
    a); if (diff == 0) {
    diff = memcmp(&src[0], &src[b - a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;

    // Usage without lambda as desired
    std2::sort(dst, dst + srclen, cmp, &bwt_cmp_t::less);
    }




    Unfortunately, it is not the same.
    Unlike all previous variant, compiler implements this one via
    dynamic dispatch (indirect call).
    At least that's what I see with gcc compiler both at -O2 and at
    -O3.

    That's right, one reason for preferring functional style functors and
    lambdas over bare function pointers is that they can be optimized
    better by the compiler, in general. But beauty requires sacrifice, so
    you have to live with that!






    Here is a variant without sacrifice. It is less pretty at the call site
    - too many template arguments.
    The advantage of it that it works the same both with std::sort and for std::nth_element.
    This variant uses normal function instead of member function. Not
    because it is impossible to do the same with member, but because I am
    not fluent with necessary syntax.

    #include <cstdint>
    #include <cstring>
    #include <algorithm>

    // Ugly template hidden in a common header
    template < typename ELEM, typename Comparison_context,
    bool Compare(Comparison_context,ELEM,ELEM) >
    class TCompare3 {
    const Comparison_context& m_context;
    public:
    TCompare3(const Comparison_context& a):m_context(a){};
    bool operator() (ELEM a, ELEM b) {
    return Compare(m_context, a, b);
    }
    };

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen)
    {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    static
    inline
    bool less(bwt_cmp_t* obj, int a, int b) {
    if (a >= b) {
    if (a > b)
    return !less(obj, b, a);
    return false; // a == b
    }
    // a < b;
    const uint8_t* src = obj->src;
    const int srclen = obj->srclen;
    int diff = memcmp(&src[a], &src[b], srclen - b);
    if (diff == 0) {
    diff = memcmp(&src[a + srclen - b], &src[0], b - a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b - a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;
    std::sort(dst, dst + srclen,
    TCompare3<int, bwt_cmp_t*, bwt_cmp_t::less>(&cmp));
    }


    Interesting. Here, the address of the member function bwt_cmp_t::less is
    not passed at run time, but rather the function is used as a template parameter. I guess that's what avoids the "sacrifice".

    The more I look at this, the more I like the lambda!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Paavo Helde on Thu Oct 10 11:47:07 2024
    On Wed, 9 Oct 2024 22:37:19 +0300
    Paavo Helde <[email protected]> wrote:


    The more I look at this, the more I like the lambda!


    I am ready to admit that my requirement of "don't force user to write
    glue function with predefined name, especially so with predefined name
    starting with 'operator'" was artificial.
    In practice, writing one-liners operator(), as in my first post, is not
    a big deal.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Fri Oct 11 03:57:47 2024
    Michael S <[email protected]> writes:

    On Mon, 07 Oct 2024 09:11:29 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Fri, 04 Oct 2024 06:57:32 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Tue, 01 Oct 2024 20:06:20 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    And best (for me, personally, YMMV) solution in pure
    functional languges is to avoid programming in such
    languages.

    What do you count as a pure functional language?

    C++ templates sub-languges. I.e. approximately compile-time
    part of C++ taken in isolation from run-time part and without
    C++11 and later additions.

    If that's your only example then not very much is excluded.

    Since I don't like functional programming it seems to me rather
    natural that I am positioned as far as it goes from being an
    expert in the field.

    Sorry, I think my comment came across wrongly. The point of my
    question is not to criticize your reactions but to understand
    just what things you are reacting to. Different people have
    different ideas of what "functional programming" means. What
    language qualities make a language one you would rather avoid?

    Since we are in C++ group, let's take examples from C++.
    I never use std::for_each().
    I don't use lambda expressions as argument for 'compare' parameter
    in std::sort or std::nth_element. If it was possible, I wouldn't
    use object of class with operator() for such parameter either.
    Instead I would prefer pointer to normal named member function.
    May be, it is possible, but I don't know the syntax. I hate
    functional stuff pushed down my throat by <random> and would very
    much prefer the same very useful functionality provided in other
    way.

    Or conversely, what attributes tend to make a language attractive
    or one that you would prefer?

    I prefer to see sequence of steps. Or, at least to have some idea
    about it in 'as if' fashion.

    I must confess I am still somewhat baffled, although I do get
    a sense of what you're reacting to. For now I will leave it
    at that; thank you for the explanation.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Fri Oct 11 04:58:29 2024
    Michael S <[email protected]> writes:

    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:

    The context state is the bread and butter of lambda. If all you
    want is to avoid operator(), this can be done easily:

    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to] object
    + [pointer to] its honest old member function. And I am not
    obsessed with idea that it has to be a single prameter at all
    cost; I see nothing wrong if two separate parameters needed to do
    the job.

    I think I understand your position. Without meaning to challenge
    that, I would like to offer my perspective on the situation.

    There are several ways a "stateful function" argument might be
    provided; some examples:

    pointer to function, along with either a separate context
    pointer or a bundled context/function pointer (illustrated
    in a recent post in comp.lang.c)

    having a parameter type of pointer to abstract superclass,
    with a virtual function to accommodate caller-specific
    functionality (not sure if a separate pointer-to-member
    argument makes sense here)

    a pointer-to templated class parameter, using either a
    fixed member function name or a separate pointer-to-member
    argument

    a lambda (which could be either a stateful lambda or a
    pure lambda along with a separate context argument)

    To me all of these choices are conceptually pretty much the same,
    having only minor differences in the details. A plausible
    analogy is comparing for() and while(), or if-then-else and
    switch().

    Because I don't see much difference between them, what I want is
    whatever makes it most convenient for the caller. Usually "most
    convenient" means the choice that uses the least code in the
    caller, although that might be affected by how clunky the code
    is for the different cases.

    Of course which choice is most convenient depends on what is
    going on in the caller. In some cases a lambda is easiest;
    in other cases a templated class parameter with a separate
    pointer-to-member could be better. Which choice or choices
    should be accommodated depends on what the expected use cases
    are. The guiding principle remains What offers the easiest
    and best fit in the caller (or callers plural)?

    So for what it's worth there is my approach to the question.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Fri Oct 11 16:03:49 2024
    On Fri, 11 Oct 2024 04:58:29 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:

    The context state is the bread and butter of lambda. If all you
    want is to avoid operator(), this can be done easily:

    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to] object
    + [pointer to] its honest old member function. And I am not
    obsessed with idea that it has to be a single prameter at all
    cost; I see nothing wrong if two separate parameters needed to do
    the job.

    I think I understand your position. Without meaning to challenge
    that, I would like to offer my perspective on the situation.

    There are several ways a "stateful function" argument might be
    provided; some examples:

    pointer to function, along with either a separate context
    pointer or a bundled context/function pointer (illustrated
    in a recent post in comp.lang.c)

    having a parameter type of pointer to abstract superclass,
    with a virtual function to accommodate caller-specific
    functionality (not sure if a separate pointer-to-member
    argument makes sense here)

    a pointer-to templated class parameter, using either a
    fixed member function name or a separate pointer-to-member
    argument

    a lambda (which could be either a stateful lambda or a
    pure lambda along with a separate context argument)

    To me all of these choices are conceptually pretty much the same,
    having only minor differences in the details. A plausible
    analogy is comparing for() and while(), or if-then-else and
    switch().

    Because I don't see much difference between them, what I want is
    whatever makes it most convenient for the caller. Usually "most
    convenient" means the choice that uses the least code in the
    caller, although that might be affected by how clunky the code
    is for the different cases.

    Of course which choice is most convenient depends on what is
    going on in the caller. In some cases a lambda is easiest;
    in other cases a templated class parameter with a separate
    pointer-to-member could be better. Which choice or choices
    should be accommodated depends on what the expected use cases
    are. The guiding principle remains What offers the easiest
    and best fit in the caller (or callers plural)?

    So for what it's worth there is my approach to the question.

    I am looking at it from the point that one of the main promises of functionality supplied by <algorithm> header is zero cost of
    abstraction.
    For me it means that comparison routine can be inlined by compiler
    when appropriate and called with direct call otherwise. Experiments
    presented in other posts of this thread demonstrate that [current crop
    of major] compilers can't do it with your solution #1.
    It seems plausible to assume, even without experiments, that they can't
    do it with your solution # 2.
    For solution #4 it depends on details. At least the variant, proposed
    by Paavo is not sufficient.
    Solution #3 sort of works, but too many details, most critically types
    of parameters in comparison operations, have to be specified on the
    call site. I.e. solution #3 does not satisfy DRY principle, which is no
    less important than zero cost of abstraction.

    At the end, the original way (class with operator() as a glue) is
    practically the best, even if for my taste it feels "too functional".
    I consider this outcome as defect in STL API definitions. Mileage of
    others may vary.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Sat Oct 12 07:41:17 2024
    Michael S <[email protected]> writes:

    On Fri, 11 Oct 2024 04:58:29 -0700
    Tim Rentsch <[email protected]> wrote:

    Michael S <[email protected]> writes:

    On Wed, 9 Oct 2024 00:12:25 +0300
    Paavo Helde <[email protected]> wrote:

    The context state is the bread and butter of lambda. If all you
    want is to avoid operator(), this can be done easily:

    I want neither operator() nor lambda.
    I want a way to feed std::sort with honest old [pointer to] object
    + [pointer to] its honest old member function. And I am not
    obsessed with idea that it has to be a single prameter at all
    cost; I see nothing wrong if two separate parameters needed to do
    the job.

    I think I understand your position. Without meaning to challenge
    that, I would like to offer my perspective on the situation.

    There are several ways a "stateful function" argument might be
    provided; some examples:

    pointer to function, along with either a separate context
    pointer or a bundled context/function pointer (illustrated
    in a recent post in comp.lang.c)

    having a parameter type of pointer to abstract superclass,
    with a virtual function to accommodate caller-specific
    functionality (not sure if a separate pointer-to-member
    argument makes sense here)

    a pointer-to templated class parameter, using either a
    fixed member function name or a separate pointer-to-member
    argument

    a lambda (which could be either a stateful lambda or a
    pure lambda along with a separate context argument)

    To me all of these choices are conceptually pretty much the same,
    having only minor differences in the details. A plausible
    analogy is comparing for() and while(), or if-then-else and
    switch().

    Because I don't see much difference between them, what I want is
    whatever makes it most convenient for the caller. Usually "most
    convenient" means the choice that uses the least code in the
    caller, although that might be affected by how clunky the code
    is for the different cases.

    Of course which choice is most convenient depends on what is
    going on in the caller. In some cases a lambda is easiest;
    in other cases a templated class parameter with a separate
    pointer-to-member could be better. Which choice or choices
    should be accommodated depends on what the expected use cases
    are. The guiding principle remains What offers the easiest
    and best fit in the caller (or callers plural)?

    So for what it's worth there is my approach to the question.

    I am looking at it from the point that one of the main promises
    of functionality supplied by <algorithm> header is zero cost of
    abstraction.

    I understand that our criteria for what choice to make in various
    circumstances are not the same. I wasn't meaning to criticize
    your choices, just to explain my own.

    For me it means that comparison routine can be inlined by compiler
    when appropriate and called with direct call otherwise. Experiments presented in other posts of this thread demonstrate that [current
    crop of major] compilers can't do it with your solution #1.
    It seems plausible to assume, even without experiments, that they
    can't do it with your solution # 2.
    For solution #4 it depends on details. [...]
    Solution #3 sort of works,

    All of the four techniques listed above could be specialized or
    inlined by a suitable compiler. I accept that current compilers
    do that for only some of the techniques listed, but I see no
    reason to suppose that any of the four techniques are inherently
    better than the others in this regard.

    but too many details, most critically
    types of parameters in comparison operations, have to be specified
    on the call site. I.e. solution #3 does not satisfy DRY principle,
    which is no less important than zero cost of abstraction.

    I need to ask for further explanation here. It is commonly
    accepted, at least in the C/C++ world, that giving the same type
    name in two or more places is usually not "repeating yourself"
    but giving a redundant specification for the purpose of doing
    type checking, so there is value in forcing the redundancy. It
    seems like what you're objecting to is inherent in the C/C++ view
    of the world, and not something specific to stateful functions
    as arguments or parameters.

    At the end, the original way (class with operator() as a glue) is
    practically the best, even if for my taste it feels "too functional".
    I consider this outcome as defect in STL API definitions. [...]

    I am baffled by your reaction to using operator(). To me it
    seems simple, natural, and a good fit to the most common cases
    while also being flexible enough to handle more elaborate cases.
    To me it seems no more or less functional than any of the other
    techniques being discussed. So I don't understand what it is
    about using operator() that you find objectionable.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Sat Oct 12 08:18:34 2024
    Michael S <[email protected]> writes:

    [...]

    Here is an example of more interesting sort that demonstrates what
    I was talking about and where I would like to use bwt_cmp_t::less
    directly instead of via operator():

    #include <cstdint>
    #include <cstring>
    #include <algorithm>

    // BWT sort - sort in lexicographic order with circular shift
    void bwt_sort(int* dst, const uint8_t* src, int srclen)
    {
    for (int i = 0; i < srclen; ++i)
    dst[i] = i;

    struct bwt_cmp_t {
    const uint8_t* src;
    int srclen;
    bool less(int a, int b) const {
    if (a >= b) {
    if (a > b)
    return !less(b, a);
    return false; // a == b
    }
    // a < b;
    int diff = memcmp(&src[a], &src[b], srclen-b);
    if (diff == 0) {
    diff = memcmp(&src[a+srclen-b], &src[0], b-a);
    if (diff == 0) {
    diff = memcmp(&src[0], &src[b-a], a);
    if (diff == 0)
    return true; // stable sort
    }
    }
    return diff < 0;
    }
    bool operator() (int a, int b) const {
    return less(a, b);
    }
    } cmp;
    cmp.src = src;
    cmp.srclen = srclen;
    std::sort(dst, dst+srclen, cmp);
    }

    I appreciate that this code illustrates your coding preferences.

    For comparison here is an alternate approach to writing the
    central routine (and also some incidental differences in other
    parts of the code but those are not so important).


    #include <cstring>
    #include <algorithm>

    // code for sorting rotations of a string in lexicographic order

    typedef unsigned char U8;

    class bwt_cmp_t {
    const U8* s;
    unsigned n;

    public:
    bwt_cmp_t( const U8 *s0, unsigned n0 ) : s(s0), n( n0 ) {}

    bool
    operator()( unsigned a, unsigned b ) const {
    unsigned j, k, a1, b1, a2, b2;
    int mc0, mc1, mc2;

    if( a<b ) j = n-b, k = b-a, a1 = a+j, b1 = 0, a2 = 0, b2 = k;
    else j = n-a, k = a-b, a1 = 0, b1 = b+j, a2 = k, b2 = 0;

    if( mc0 = memcmp( s+a, s+b, j ), mc0 ) return mc0 < 0;
    if( mc1 = memcmp( s+a1, s+b1, k ), mc1 ) return mc1 < 0;

    mc2 = memcmp( s+a2, s+b2, n-j-k );
    return mc2 < 0 || mc2 == 0 && a <= b;
    }
    };


    void
    bwt_sort( unsigned* dst, U8* s, unsigned n ){
    for( unsigned i = 0; i < n; ++i ) dst[i] = i;

    std::sort( dst, dst + n, bwt_cmp_t( s, n ) );
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)