• is STC a good supplementary library for C?

    From Mark Summerfield@21:1/5 to All on Sat Aug 3 10:44:11 2024
    As part of relearning C I wanted to find a lightweight library (so not
    GLib) that will provide generic collections.

    I seem to have found such a library: https://github.com/stclib/STC

    It does not appear to be a standard Debian package but I haven't found any equivalent in Debian.

    Is this a reasonable choice? If not, what would you recommend?

    I want a generic (int/str/custom struct) set, map, ordered map, vector.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Mark Summerfield on Sat Aug 3 12:06:00 2024
    Mark Summerfield <[email protected]> wrote or quoted:
    I want a generic (int/str/custom struct) set, map, ordered map, vector.

    C is a stripped-down language designed to get close to
    the hardware with minimal overhead. It skips many of the
    high-level features in C++, like templates, classes, and
    operator overloading. Trying to make C act like C++ by
    building a generic container library can lead to:

    Complexity: Creating generic containers in C often means
    dealing with gnarly macros, void pointers, and type casting,
    which can make the code a pain to read and maintain.

    Inefficiency: Generic containers in C might not be as slick
    as those in C++ due to the lack of compile-time type checking
    and optimizations. And,

    error-prone code: Without the type safety provided by C++ templates,
    generic containers in C are more likely to cause runtime errors.

    Idiomatic C programming rolls with the language's strengths and
    works within its constraints. This often involves:

    Explicit typing: C programmers usually define data structures
    and functions explicitly for each type they need, rather
    than leaning on generic solutions.

    Manual memory management: C programmers are used to managing
    memory by hand, which can be more predictable and efficient than
    relying on a generic container library. And,

    simplicity and clarity: C code is often straightforward and simple,
    focusing on clear and direct solutions rather than abstract
    and generalized ones.

    The old pros of C came up with several techniques to handle the
    lack of generic containers:

    Structs and pointers: Using structs and pointers to create
    custom data structures tailored to specific needs.

    Function pointers: Employing function pointers to pull off a form
    of polymorphism. And,

    Macros: Utilizing preprocessor macros to create reusable code
    snippets, though this can lead to less readable and maintainable code
    if overdone.

    Some problems encountered when using generic container libraries
    in C might be:

    portability: Generic container libraries in C can be less portable
    across different compilers and platforms.

    Debugging: Debugging generic code in C can be more of a
    hassle due to the lack of type information and the use of
    void pointers. And,

    performance: Hand-crafted, type-specific data structures
    and algorithms can often be more performant than generic
    implementations.

    While it's technically possible to whip up a generic container
    library in C, doing so often goes against the grain of
    idiomatic C programming.

    C shines in simplicity, explicitness, and low-level control.

    Embracing these traits leads to more maintainable, efficient, and
    understandable code. Instead of trying to force C to act like C++,
    it's generally better to leverage C's strengths and use techniques
    that are well-suited to the language's design and philosophy.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Harnden@21:1/5 to Mark Summerfield on Sat Aug 3 13:26:01 2024
    On 03/08/2024 11:44, Mark Summerfield wrote:
    As part of relearning C I wanted to find a lightweight library (so not
    GLib) that will provide generic collections.

    I seem to have found such a library: https://github.com/stclib/STC

    It does not appear to be a standard Debian package but I haven't found any equivalent in Debian.

    Is this a reasonable choice? If not, what would you recommend?

    I've never hear of it, but from a very quick look I'd say: no.
    They seem to be trying to write C++ code in C. If you want C++, use C++.


    I want a generic (int/str/custom struct) set, map, ordered map, vector.

    I think this is better (I've never used it, but Jacob does know what
    he's doing): https://github.com/jacob-navia/ccl

    Really though, roll your own. It'll be a good exercise for relearning C.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Sat Aug 3 15:25:09 2024
    [email protected] (Stefan Ram) wrote or quoted:
    Embracing these traits leads to more maintainable, efficient, and >understandable code. Instead of trying to force C to act like C++,
    it's generally better to leverage C's strengths and use techniques
    that are well-suited to the language's design and philosophy.

    If you absolutely need a library, you (Mark) should totally check
    out the Python library! It's been around forever, super reliable,
    and constantly getting better. Here's a quick example program:

    #include <Python.h>

    int main() {
    // Initialize the Python interpreter
    Py_Initialize();

    // Create a Python list
    PyObject* pyList = PyList_New(0);
    if (!pyList) {
    fprintf(stderr, "Failed to create Python list\n");
    Py_Finalize();
    return 1;
    }

    // Add some integers to the list
    for (int i = 0; i < 5; i++) {
    PyObject* pyInt = PyLong_FromLong(i);
    if (!pyInt) {
    fprintf(stderr, "Failed to create Python integer\n");
    Py_DECREF(pyList);
    Py_Finalize();
    return 1;
    }

    // PyList_Append increments the reference count of pyInt
    if (PyList_Append(pyList, pyInt) < 0) {
    fprintf(stderr, "Failed to append to list\n");
    Py_DECREF(pyInt);
    Py_DECREF(pyList);
    Py_Finalize();
    return 1;
    }

    // Decrease reference count of pyInt, as it's now stored in the list
    Py_DECREF(pyInt);
    }

    // Print the list size
    printf("List size: %zd\n", PyList_Size(pyList));

    // Read and print the integers from the list
    for (int i = 0; i < PyList_Size(pyList); i++) {
    PyObject* item = PyList_GetItem(pyList, i); // Borrowed reference
    if (PyLong_Check(item)) {
    long value = PyLong_AsLong(item);
    printf("List item %d: %ld\n", i, value);
    } else {
    fprintf(stderr, "List item %d is not an integer\n", i);
    }
    }

    // Clean up
    Py_DECREF(pyList);
    Py_Finalize();

    return 0;
    }

    , output:

    List size: 5
    List item 0: 0
    List item 1: 1
    List item 2: 2
    List item 3: 3
    List item 4: 4

    .

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Stefan Ram on Sat Aug 3 17:29:59 2024
    On 03/08/2024 16:25, Stefan Ram wrote:
    [email protected] (Stefan Ram) wrote or quoted:
    Embracing these traits leads to more maintainable, efficient, and
    understandable code. Instead of trying to force C to act like C++,
    it's generally better to leverage C's strengths and use techniques
    that are well-suited to the language's design and philosophy.

    If you absolutely need a library, you (Mark) should totally check
    out the Python library! It's been around forever, super reliable,
    and constantly getting better. Here's a quick example program:

    #include <Python.h>

    int main() {
    // Initialize the Python interpreter
    Py_Initialize();

    // Create a Python list
    PyObject* pyList = PyList_New(0);
    if (!pyList) {
    fprintf(stderr, "Failed to create Python list\n");
    Py_Finalize();
    return 1;
    }

    // Add some integers to the list
    for (int i = 0; i < 5; i++) {
    PyObject* pyInt = PyLong_FromLong(i);
    if (!pyInt) {
    fprintf(stderr, "Failed to create Python integer\n");
    Py_DECREF(pyList);
    Py_Finalize();
    return 1;
    }

    // PyList_Append increments the reference count of pyInt
    if (PyList_Append(pyList, pyInt) < 0) {
    fprintf(stderr, "Failed to append to list\n");
    Py_DECREF(pyInt);
    Py_DECREF(pyList);
    Py_Finalize();
    return 1;
    }

    // Decrease reference count of pyInt, as it's now stored in the list
    Py_DECREF(pyInt);
    }

    // Print the list size
    printf("List size: %zd\n", PyList_Size(pyList));

    // Read and print the integers from the list
    for (int i = 0; i < PyList_Size(pyList); i++) {
    PyObject* item = PyList_GetItem(pyList, i); // Borrowed reference
    if (PyLong_Check(item)) {
    long value = PyLong_AsLong(item);
    printf("List item %d: %ld\n", i, value);
    } else {
    fprintf(stderr, "List item %d is not an integer\n", i);
    }
    }

    // Clean up
    Py_DECREF(pyList);
    Py_Finalize();

    return 0;
    }

    , output:

    List size: 5
    List item 0: 0
    List item 1: 1
    List item 2: 2
    List item 3: 3
    List item 4: 4

    .
    This looks like it wouldn't run much faster than in Python. So why not
    just use Python? It would be a lot simpler!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Bart on Sun Aug 4 01:02:19 2024
    On Sat, 3 Aug 2024 17:29:59 +0100, Bart wrote:

    This looks like it wouldn't run much faster than in Python. So why not
    just use Python? It would be a lot simpler!

    Also, such a clunky and repetitive way of doing error-checking and
    cleanup.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mark Summerfield@21:1/5 to Richard Harnden on Sun Aug 4 09:26:47 2024
    On Sat, 3 Aug 2024 13:26:01 +0100, Richard Harnden wrote:
    [snip]
    I've never hear of it, but from a very quick look I'd say: no.
    They seem to be trying to write C++ code in C. If you want C++, use C++.


    I want a generic (int/str/custom struct) set, map, ordered map, vector.

    I think this is better (I've never used it, but Jacob does know what
    he's doing): https://github.com/jacob-navia/ccl

    Really though, roll your own. It'll be a good exercise for relearning C.

    Thanks for all the replies.

    I've started reading Jacob Navia's CCL document.

    This seems to provide all that I'd need (and more besides).

    However, it appears that this was intended to be added to C's standard
    library — 12 years ago! The last update was 4 years ago. So it doesn't
    look to be maintained and presumably was rejected as an addition to the standard library?

    I certainly think the C standard library ought to offer a lot more so that practically every C programmer doesn't end up creating their own basic containers. (An argument strongly made in Navia's document.)

    PS I know I could use Python's library but don't want anything that big
    (hence not GLib); although I might end up using the Tcl/Tk libs for GUI
    apps.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Blue-Maned_Hawk@21:1/5 to Stefan Ram on Sun Aug 4 14:05:00 2024
    The first thing that i have to say about this message is that it looks
    like it was written by an ML system and regurgitated here with minimal
    edits, if any at all. Don't do this—if someone wanted an ML-generated answer, they would go to an ML system on their own volition.

    Stefan Ram wrote:

    C is a stripped-down language designed to get close to the hardware
    with minimal overhead. It skips many of the high-level features in
    C++, like templates, classes, and operator overloading. Trying to make
    C act like C++ by building a generic container library can lead to:

    Complexity: Creating generic containers in C often means dealing with
    gnarly macros, void pointers, and type casting,
    which can make the code a pain to read and maintain.

    I think that this is greatly exaggerated. Macros can get into the realm
    of unreadability, but there's an unfortunate feedback loop here: people
    are told to not use macros because they're unreadable, which means that
    people don't get as much experience with macros, which means that they
    find it hard to read macros, which means people are told that macros are unreadable… I've found myself able to write macros that i've found
    readable and usable perfectly fine—something that i've found to be key to this is to ignore dogma and format the macro code to be readable instead
    of strictly compliant to a ideal of style.

    I don't consider void pointers or type casting to be complex—i'd be
    curious about the reasoning for this claim.

    Inefficiency: Generic containers in C might not be as slick as those
    in C++ due to the lack of compile-time type checking and
    optimizations. And,

    I'd be more concerned about practicality than slickness. I'm not sure
    what's being referred to with a “lack of compile-time type checking”—would
    an example be possible?

    The lack of optimizations _is_ a sound claim, but i don't think it's very relevant here. Optimization is always the last stage of developing a
    piece of software, and even then it's only ever really done for big,
    public projects. For small personal projects, worrying about optimization isn't necessary.

    error-prone code: Without the type safety provided by C++ templates,
    generic containers in C are more likely to cause runtime errors.

    I still don't get this. C _does_ have a type system. Macros _can_ expand
    to constructs that take advantage of this type system.

    Idiomatic C programming rolls with the language's strengths and works
    within its constraints. This often involves:

    Normalcy is orthogonal to optimality.

    Explicit typing: C programmers usually define data structures and
    functions explicitly for each type they need, rather than leaning on
    generic solutions.

    …and by doing so, they violate the principle of nonrepetition. Macros are
    a useful tool, y'all—they aren't inherently evil.

    Manual memory management: C programmers are used to managing memory by
    hand, which can be more predictable and efficient than relying on a
    generic container library. And,

    I cannot see the relevancy of generic types to memory management at all.

    simplicity and clarity: C code is often straightforward and simple,
    focusing on clear and direct solutions rather than abstract and
    generalized ones.

    Doesn't all code do that?

    The old pros of C came up with several techniques to handle the lack
    of generic containers:

    Structs and pointers: Using structs and pointers to create custom data
    structures tailored to specific needs.

    Function pointers: Employing function pointers to pull off a form of
    polymorphism. And,

    These are not remotely specific to C.

    Macros: Utilizing preprocessor macros to create reusable code
    snippets, though this can lead to less readable and maintainable code
    if overdone.

    Any tool can be used incorrectly.

    Some problems encountered when using generic container libraries in C
    might be:

    portability: Generic container libraries in C can be less portable
    across different compilers and platforms.

    GCC's extensions and Clang's extensions can be useful, but standard C is
    plenty powerful enough for genericity. Extension-wielding code can be bracketed with conditional inclusion.

    Here's an example: There's a macro i've written where one of the
    arguments _must_ be a valid identifier. Standard C has no way to check
    for this, but Clang defines the __is_identifier macro that can check for
    this. In the header file, i check if __is_identifier is defined, and
    define it to always evaluate to true if it isn't. This means that i can
    use the macro in static assertions to make sure that the argument to the
    macro is a valid identifier, and if it can be checked, it is, without any problems if it can't be.

    Debugging: Debugging generic code in C can be more of a hassle due to
    the lack of type information and the use of void pointers. And,

    Still don't know what's meant by the “lack of type information”.

    performance: Hand-crafted, type-specific data structures and
    algorithms can often be more performant than generic implementations.

    While it's technically possible to whip up a generic container library
    in C, doing so often goes against the grain of idiomatic C
    programming.

    C shines in simplicity, explicitness, and low-level control.

    Not anymore.

    Embracing these traits leads to more maintainable, efficient, and
    understandable code. Instead of trying to force C to act like C++,
    it's generally better to leverage C's strengths and use techniques
    that are well-suited to the language's design and philosophy.

    Genericity is not exclusive to CXX.



    --
    Blue-Maned_Hawk│shortens to Hawk│/blu.mɛin.dʰak/│he/him/his/himself/Mr. blue-maned_hawk.srht.site
    Why did i arse myself about with this?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Mark Summerfield on Sun Aug 4 17:35:36 2024
    On 8/4/24 05:26, Mark Summerfield wrote:
    ...
    I've started reading Jacob Navia's CCL document.

    This seems to provide all that I'd need (and more besides).

    However, it appears that this was intended to be added to C's standard library — 12 years ago! The last update was 4 years ago. So it doesn't
    look to be maintained and presumably was rejected as an addition to the standard library?

    I'm not sure, but from past experience with Jacob I suspect that he
    never went through the process of making a formal proposal for a change
    to the standard. Such proposals can only be made by members of the
    committee. Therefore, he would have to either become a member of the
    committee, or convince a member of the committee that it would be a good
    idea to propose the change for him. As far as I know, he's never
    attempted to do either of those things. Therefore, it's probably not
    correct to describe his proposal as having been rejected.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to All on Sun Aug 4 22:33:58 2024
    On Sun, 4 Aug 2024 14:05:00 -0000 (UTC), Blue-Maned_Hawk wrote:

    Macros can get into the realm
    of unreadability, but there's an unfortunate feedback loop here: people
    are told to not use macros because they're unreadable, which means that people don't get as much experience with macros, which means that they
    find it hard to read macros ...

    Macros done by manipulating strings in a preprocessor are the wrong way to
    do them.

    The right way to do macros is at the AST level, like Lisp does them.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Blue-Maned_Hawk@21:1/5 to Lawrence D'Oliveiro on Mon Aug 5 16:35:52 2024
    Lawrence D'Oliveiro wrote:

    On Sun, 4 Aug 2024 14:05:00 -0000 (UTC), Blue-Maned_Hawk wrote:

    Macros can get into the realm of unreadability, but there's an
    unfortunate feedback loop here: people are told to not use macros
    because they're unreadable, which means that people don't get as much
    experience with macros, which means that they find it hard to read
    macros ...

    Macros done by manipulating strings in a preprocessor are the wrong way
    to do them.

    The right way to do macros is at the AST level, like Lisp does them.

    Standard C preprocessors are already token-based instead of text-based
    like prestandard ones were.



    --
    Blue-Maned_Hawk│shortens to Hawk│/blu.mɛin.dʰak/│he/him/his/himself/Mr. blue-maned_hawk.srht.site
    Hello. You are tired. Bye.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Blue-Maned_Hawk@21:1/5 to Lawrence D'Oliveiro on Tue Aug 6 00:54:39 2024
    Lawrence D'Oliveiro wrote:

    On Mon, 5 Aug 2024 16:35:52 -0000 (UTC), Blue-Maned_Hawk wrote:

    Lawrence D'Oliveiro wrote:

    Macros done by manipulating strings in a preprocessor are the wrong
    way to do them.

    The right way to do macros is at the AST level, like Lisp does them.

    Standard C preprocessors are already token-based instead of text-based
    like prestandard ones were.

    Not what I said.

    Then what did you say and why isn't my reply relevant to it?



    --
    Blue-Maned_Hawk│shortens to Hawk│/blu.mɛin.dʰak/│he/him/his/himself/Mr. blue-maned_hawk.srht.site
    The exact weight of the twenty-pound note is a state secret for some
    reason.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to All on Tue Aug 6 00:34:54 2024
    On Mon, 5 Aug 2024 16:35:52 -0000 (UTC), Blue-Maned_Hawk wrote:

    Lawrence D'Oliveiro wrote:

    Macros done by manipulating strings in a preprocessor are the wrong way
    to do them.

    The right way to do macros is at the AST level, like Lisp does them.

    Standard C preprocessors are already token-based instead of text-based
    like prestandard ones were.

    Not what I said.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)