• Re: do { quit; } else { }

    From bart@21:1/5 to Thiago Adams on Fri Apr 4 21:18:45 2025
    On 04/04/2025 20:23, Thiago Adams wrote:
      What do you think of this control block?

      do
      {
         FILE f = fopen("file.txt", "r");

         if (f == NULL) quit; /*goes to else part*/

         /*success here*/
         for (int i =0; i < 10; i++){
             ...
             if (error) quit;
         }

      }
      else
      {
         /*some error*/
      }


    As a new language feature?

    I think 'do {}' would be confused 'do {} while' (a parser - or a human -
    won't know this isn't a loop until the 'else' is seen. And then there's
    a possibility that that 'else' belongs to an 'if' but an omission or
    inclusion of a braces has screwed things up.

    Perhaps a new keyword ('try' maybe) is better.

    You'd also need to specify how nested do-else blocks will work. Or will
    'quit' (so you have a new keyword anyway) only work at this level?

    What about chained versions: do {} else do {} else ...; I guess 'quit'
    will just go to the next else block rather than quit the whole chain?

    Note that this can be emulated in C now using:

    if
    {
    goto quit001;
    }
    else
    {quit001:
    }

    Perhaps what C needs is a way to do that jump without an explicit goto:

    if
    {
    quit001;
    }
    else
    {quit001:
    }

    You can require that such jumps can only go forwards.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Thiago Adams on Fri Apr 4 20:34:44 2025
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }


    The else part might need access to some local variables
    in the main part.

    do {
    char *name = calculate_path(PATH_PREFIX "/", name, ".txt");
    FILE *f = fopen(...)

    if (!f)
    quit;
    ...
    }
    else
    {
    printf("unable to open %s\n", name);
    ...
    }

    If you make that work, you're creating scope wormholes between
    disjoint curly braces, which is not allowed if youre name isn't
    Bjarne Stroustrup.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Kaz Kylheku on Fri Apr 4 20:39:31 2025
    On 2025-04-04, Kaz Kylheku <643-408-1753@kylheku.com> wrote:
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }


    The else part might need access to some local variables
    in the main part.

    do {
    char *name = calculate_path(PATH_PREFIX "/", name, ".txt");
    FILE *f = fopen(...)

    if (!f)
    quit;
    ...
    }
    else
    {
    printf("unable to open %s\n", name);
    ...
    }

    If you make that work, you're creating scope wormholes between
    disjoint curly braces, which is not allowed if youre name isn't
    Bjarne Stroustrup.

    How about: do/else if/else if/else with argument passing to first
    clause whose signature can take the argument list:

    do {
    ...
    quit("rage"); // goes to (char *arg)
    ...
    quit(42); // goes to (int arg)
    ...
    }
    else if (char *arg) // or just else? multiple elses on do, why not.
    {
    }
    else (int arg)
    {
    }

    Friday `f`noons, eh?

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Thiago Adams on Fri Apr 4 13:48:53 2025
    Thiago Adams <thiago.adams@gmail.com> writes:

    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }

    I think it doesn't belong in comp.lang.c.

    I also think you have been participating in comp.lang.c
    long enough to know better. Kindly take your language
    fantasies somewhere else.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Thiago Adams on Fri Apr 4 21:01:22 2025
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    Em 4/4/2025 5:34 PM, Kaz Kylheku escreveu:
    The else part might need access to some local variables
    in the main part.

    do {
    char *name = calculate_path(PATH_PREFIX "/", name, ".txt");
    FILE *f = fopen(...)

    if (!f)
    quit;
    ...
    }
    else
    {
    printf("unable to open %s\n", name);
    ...
    }

    In this case we move the scope of the variable we need.

    Your name isn't Bjarne Stroustrup, so you're not allowed to
    create scope wormholes between disjoint curly braces.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Kaz Kylheku on Sat Apr 5 14:54:18 2025
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }


    The else part might need access to some local variables
    in the main part.

    And some metadata, as well. Consider that the message should
    also say _why_ the file couldn't be opened. That requires
    errno to be preserved as well.

    printf("%s: Unable to open '%s': %s\n",
    argv[0], filename, strerror(errno));

    Best to produce the error message -immediately- after the
    failure was detected.

    The idea is fatally flawed - if only because there is no chance
    it could ever be added to the C language.

    I don't believe C++ exceptions are useful in this case, either,
    and I avoid using them for general purpose error handling.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Scott Lurndal on Sat Apr 5 17:54:30 2025
    On 05.04.2025 16:54, Scott Lurndal wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?
    [...]

    I don't believe C++ exceptions are useful in this case, either,
    and I avoid using them for general purpose error handling.

    I'd have wished that they were available back then when we
    started using C++ regularly in the early 1990's.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Janis Papanagnou on Sat Apr 5 16:10:36 2025
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 05.04.2025 16:54, Scott Lurndal wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?
    [...]

    I don't believe C++ exceptions are useful in this case, either,
    and I avoid using them for general purpose error handling.

    I'd have wished that they were available back then when we
    started using C++ regularly in the early 1990's.

    I was using C++ (cfront 2.1) for operating system code in 1990.

    We couldn't have used exceptions even when they were introduced
    in cfront 3 for that project.

    I strongly believe errors must be handled immediately when
    detected, rather than deferring to some nebulous code a long
    way in both space and time from the actual error.

    The only use I see for C++ exceptions is a cleaner
    sigsetjmp/siglongjmp, and even then I've used
    the later when the former is available. As an
    experiment, I once replaced the sigsetjmp/siglongjmp
    calls with C++ exceptions and found that using exceptions
    reduced application performance by a double-digit percentage
    for that particular applications (processor simulator).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Scott Lurndal on Sat Apr 5 23:37:42 2025
    On 05.04.2025 18:10, Scott Lurndal wrote:
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 05.04.2025 16:54, Scott Lurndal wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?
    [...]

    I don't believe C++ exceptions are useful in this case, either,
    and I avoid using them for general purpose error handling.

    I'd have wished that they were available back then when we
    started using C++ regularly in the early 1990's.

    I was using C++ (cfront 2.1) for operating system code in 1990.

    We couldn't have used exceptions even when they were introduced
    in cfront 3 for that project.

    I strongly believe errors must be handled immediately when
    detected, rather than deferring to some nebulous code a long
    way in both space and time from the actual error.

    There's nothing deferred with exceptions. Unless you defer it.


    The only use I see for C++ exceptions is a cleaner
    sigsetjmp/siglongjmp, and even then I've used
    the later when the former is available. As an
    experiment, I once replaced the sigsetjmp/siglongjmp
    calls with C++ exceptions and found that using exceptions
    reduced application performance by a double-digit percentage
    for that particular applications (processor simulator).

    I think one fundamental problem here is that you started with a
    primitive low level "exit-concept"; refactoring such structures
    is likely doomed to fail.

    YMMV.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Thiago Adams on Sun Apr 6 02:58:39 2025
    On Fri, 4 Apr 2025 16:23:30 -0300, Thiago Adams wrote:

    What do you think of this control block?

    Stick to standard C:

    1: Initialize a pointer variable to `NULL`
    2: Allocate memory for the pointer (this might fail)
    3: Correctly free the pointer memory, regardless of allocation
    success/failure

    Specifically:

    PyObject * obj = NULL; /* step 1 */
    do /*once*/
    {
    ... possible other stuff ...
    allocate obj; /* step 2 */
    if (PyErr_Occurred())
    break;
    ... possible other stuff using obj ...
    /* all done */
    result = tempresult;
    tempresult = NULL; /* so I don’t dispose of it yet */
    }
    while (false);
    Py_XDECREF(obj); /* step 3 */

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Scott Lurndal on Sun Apr 6 10:52:16 2025
    On Sat, 05 Apr 2025 16:10:36 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 05.04.2025 16:54, Scott Lurndal wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?
    [...]

    I don't believe C++ exceptions are useful in this case, either,
    and I avoid using them for general purpose error handling.

    I'd have wished that they were available back then when we
    started using C++ regularly in the early 1990's.

    I was using C++ (cfront 2.1) for operating system code in 1990.

    We couldn't have used exceptions even when they were introduced
    in cfront 3 for that project.

    I strongly believe errors must be handled immediately when
    detected, rather than deferring to some nebulous code a long
    way in both space and time from the actual error.

    The only use I see for C++ exceptions is a cleaner
    sigsetjmp/siglongjmp, and even then I've used
    the later when the former is available. As an
    experiment, I once replaced the sigsetjmp/siglongjmp
    calls with C++ exceptions and found that using exceptions
    reduced application performance by a double-digit percentage
    for that particular applications (processor simulator).

    If you believe in non-trivial constructors (i.e. constructors that can
    fail) then you have to believe in exceptions as well.
    Personally, I don't believe in either.
    But then, I don't believe that C++ is suitable for for operating system
    code...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Thiago Adams on Sun Apr 6 12:05:40 2025
    On 04/04/2025 21:23, Thiago Adams wrote:
      What do you think of this control block?

      do
      {
         FILE f = fopen("file.txt", "r");

         if (f == NULL) quit; /*goes to else part*/

         /*success here*/
         for (int i =0; i < 10; i++){
             ...
             if (error) quit;
         }

      }
      else
      {
         /*some error*/
      }


    This does not strike me as worth the effort as a control block. There
    are always vast numbers of ways to make different kinds of control
    blocks in a language - the trick is to pick enough to be able to write
    code conveniently, and not so many that it is hard to learn the language
    and understand the code.

    Modern languages often have some kind of try/except structure, which is
    what this looks like. But I don't think that is a good idea to try to
    bolt onto a C compiler as an extension - it would give little benefit
    and a lot of incompatibility. It is best done as a more fundamental
    part of a language design. Without integration in the library, all you
    have is syntactic sugar for a "goto" without even saving much typing.


    Now, if you were to invent a do / undo control block, where the "undo" statement not merely exits the control block but undoes the effect of everything done so far inside the block, /then/ you would have something
    new and exciting!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Thiago Adams on Sun Apr 6 05:47:47 2025
    Thiago Adams <thiago.adams@gmail.com> writes:

    Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:

    Thiago Adams <thiago.adams@gmail.com> writes:

    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }

    I think it doesn't belong in comp.lang.c.

    I also think you have been participating in comp.lang.c
    long enough to know better. Kindly take your language
    fantasies somewhere else.

    I think the only reason you're saying that is because it's not
    implemented in GCC, Clang, or maybe even MSVC.

    You are wrong. I responded because there is nothing in
    your posting that is suitable for comp.lang.c.

    I've never seen you complain about any GCC extensions here.

    I don't remember seeing any posting in comp.lang.c that
    discusses a gcc extension and nothing else. There are
    plenty of postings that mention gcc extensions in passing,
    along with other material that talks about C, but never
    one that discusses gcc extensions exclusively.

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Sun Apr 6 16:13:23 2025
    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Thiago Adams <thiago.adams@gmail.com> writes:

    Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:

    Thiago Adams <thiago.adams@gmail.com> writes:

    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }

    I think it doesn't belong in comp.lang.c.

    I also think you have been participating in comp.lang.c
    long enough to know better. Kindly take your language
    fantasies somewhere else.

    I think the only reason you're saying that is because it's not
    implemented in GCC, Clang, or maybe even MSVC.

    You are wrong. I responded because there is nothing in
    your posting that is suitable for comp.lang.c.

    I've never seen you complain about any GCC extensions here.

    I don't remember seeing any posting in comp.lang.c that
    discusses a gcc extension and nothing else. There are
    plenty of postings that mention gcc extensions in passing,
    along with other material that talks about C, but never
    one that discusses gcc extensions exclusively.

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    Could you recommend a more appropriate place for Thiago and others where
    they can discuss C-like fantasy languages?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Sun Apr 6 16:02:03 2025
    On 06/04/2025 15:26, Michael S wrote:

    More interesting question than the one above is: why post of Alexis
    from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
    How exactly can we draw a line between two cases?


    One possible distinction is if the post starts off making it clear that
    the discussion is about a potential extension or enhancement to C.
    Alexis discussed a blog article from a C standards committee member
    about a possible future C standard feature - that's entirely topical.

    If Thiago had started off by saying he is prototyping this feature as an extension in his experimental C compiler, with a view to seeing how it
    helps real C code and then proposing it for an enhancement in future C standards, it could reasonably be considered topical (more so than many
    threads we have had). Without context, however, it can reasonably be
    seen as unconnected to C and therefore entirely non-topical.

    Since there is no explicit C context, but an implication that this might
    be an extension in his C compiler, it's a more of a grey area. A number
    of regulars here have responded (with posts other than "this is
    off-topic"), so that suggests there is at least some interest in the group.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Sun Apr 6 16:26:07 2025
    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Thiago Adams <thiago.adams@gmail.com> writes:

    Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:

    Thiago Adams <thiago.adams@gmail.com> writes:

    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }

    I think it doesn't belong in comp.lang.c.

    I also think you have been participating in comp.lang.c
    long enough to know better. Kindly take your language
    fantasies somewhere else.

    I think the only reason you're saying that is because it's not
    implemented in GCC, Clang, or maybe even MSVC.

    You are wrong. I responded because there is nothing in
    your posting that is suitable for comp.lang.c.

    I've never seen you complain about any GCC extensions here.

    I don't remember seeing any posting in comp.lang.c that
    discusses a gcc extension and nothing else. There are
    plenty of postings that mention gcc extensions in passing,
    along with other material that talks about C, but never
    one that discusses gcc extensions exclusively.

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    More interesting question than the one above is: why post of Alexis
    from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
    How exactly can we draw a line between two cases?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Sun Apr 6 07:32:16 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Thiago Adams <thiago.adams@gmail.com> writes:

    Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:

    Thiago Adams <thiago.adams@gmail.com> writes:

    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }

    I think it doesn't belong in comp.lang.c.

    I also think you have been participating in comp.lang.c
    long enough to know better. Kindly take your language
    fantasies somewhere else.

    I think the only reason you're saying that is because it's not
    implemented in GCC, Clang, or maybe even MSVC.

    You are wrong. I responded because there is nothing in
    your posting that is suitable for comp.lang.c.

    I've never seen you complain about any GCC extensions here.

    I don't remember seeing any posting in comp.lang.c that
    discusses a gcc extension and nothing else. There are
    plenty of postings that mention gcc extensions in passing,
    along with other material that talks about C, but never
    one that discusses gcc extensions exclusively.

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    Could you recommend a more appropriate place for Thiago and others
    where they can discuss C-like fantasy languages?

    The newsgroup comp.lang.misc seems like a natural candidate.
    I don't know if comp.lang.misc has an official charter, but at
    least to me new features of any widely used programming language
    would appear to fall under the umbrella of comp.lang.misc.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Michael S on Sun Apr 6 14:45:07 2025
    Michael S <already5chosen@yahoo.com> writes:
    On Sat, 05 Apr 2025 16:10:36 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:



    If you believe in non-trivial constructors (i.e. constructors that can
    fail) then you have to believe in exceptions as well.

    Generally, I don't. And there are other ways to signal constructor
    failures without using exception (i.e. an error flag in the object that
    can be interrogated subsequent to the constructor).

    Personally, I don't believe in either.
    But then, I don't believe that C++ is suitable for for operating system >code...

    Having written two production operating systems, and one production
    and one experimental hypervisor in C++[*], I'll vociferiously disagree.

    [*] C with classes, mostly. No RTTI, no exceptions, no std C++ library.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kenny McCormack@21:1/5 to already5chosen@yahoo.com on Sun Apr 6 14:18:31 2025
    In article <20250406162607.0000657a@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    ...
    More interesting question than the one above is: why post of Alexis
    from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
    How exactly can we draw a line between two cases?

    Tim Wrench is clearly a lunatic. And he's in my killfile.

    The language he uses in this thread is just beyond the pale (*) in terms of rudeness and non-civility. If his target was anyone else (and especially
    if it was an old regular), we'd probably have 20 posts already condemning
    his language.

    (*) I think that's the right spelling - for a phrase I've only heard and
    have never seen written down. Or is it "pail" ?

    --
    The randomly chosen signature file that would have appeared here is more than 4 lines long. As such, it violates one or more Usenet RFCs. In order to remain in compliance with said RFCs, the actual sig can be found at the following URL:
    http://user.xmission.com/~gazelle/Sigs/WeekendAwayFromHome

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Janis Papanagnou on Sun Apr 6 14:41:58 2025
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 05.04.2025 18:10, Scott Lurndal wrote:
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 05.04.2025 16:54, Scott Lurndal wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?
    [...]

    I don't believe C++ exceptions are useful in this case, either,
    and I avoid using them for general purpose error handling.

    I'd have wished that they were available back then when we
    started using C++ regularly in the early 1990's.

    I was using C++ (cfront 2.1) for operating system code in 1990.

    We couldn't have used exceptions even when they were introduced
    in cfront 3 for that project.

    I strongly believe errors must be handled immediately when
    detected, rather than deferring to some nebulous code a long
    way in both space and time from the actual error.

    There's nothing deferred with exceptions. Unless you defer it.

    By deferring, I meant deferring some other "catch" handler
    somewhere in the application. The most knowledge about
    the issue is at the point of detection. By the time the
    typical "catch" handler sees the exception, it may have
    little to no information related to the failure sufficient
    to either repair the issue or report it accurately.



    The only use I see for C++ exceptions is a cleaner
    sigsetjmp/siglongjmp, and even then I've used
    the later when the former is available. As an
    experiment, I once replaced the sigsetjmp/siglongjmp
    calls with C++ exceptions and found that using exceptions
    reduced application performance by a double-digit percentage
    for that particular applications (processor simulator).

    I think one fundamental problem here is that you started with a
    primitive low level "exit-concept"; refactoring such structures
    is likely doomed to fail.

    I don't understand this. The case I mentioned was a
    processor simulation, and it is most natural to use
    longjmp (or C++ exceptions) to handle an exception in
    the middle of the simulation of an ADD instruction
    when one of the operands gets a TLB miss.

    Since such an application is performance sensitive, there
    is no dynamic allocation in the simulation path and thus
    there is no need for the standard C++ exception RAII
    rollback[*]. A long jump back to the main instruction
    fetch/execute loop naturally models the actual hardware.

    [*] Which should never, IMHO, be used to automatically
    unlock a mutex, even when using exceptions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Kenny McCormack on Sun Apr 6 17:08:35 2025
    On 06/04/2025 16:18, Kenny McCormack wrote:
    In article <20250406162607.0000657a@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    ...
    More interesting question than the one above is: why post of Alexis
    from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
    How exactly can we draw a line between two cases?

    Tim Wrench is clearly a lunatic. And he's in my killfile.

    The language he uses in this thread is just beyond the pale (*) in terms of rudeness and non-civility. If his target was anyone else (and especially
    if it was an old regular), we'd probably have 20 posts already condemning
    his language.

    (*) I think that's the right spelling - for a phrase I've only heard and
    have never seen written down. Or is it "pail" ?


    It's even more off-topic, but I like to answer questions when asked -
    yes, you are correct that it is "pale", from an old word for post or
    fence (with similar etymology to "post", as in "wooden post"). Thus
    "beyond the pale" is outside the borders or boundaries of your little
    bit of civilisation.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Sun Apr 6 08:14:19 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Thiago Adams <thiago.adams@gmail.com> writes:

    Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:

    Thiago Adams <thiago.adams@gmail.com> writes:

    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }

    I think it doesn't belong in comp.lang.c.

    I also think you have been participating in comp.lang.c
    long enough to know better. Kindly take your language
    fantasies somewhere else.

    I think the only reason you're saying that is because it's not
    implemented in GCC, Clang, or maybe even MSVC.

    You are wrong. I responded because there is nothing in
    your posting that is suitable for comp.lang.c.

    I've never seen you complain about any GCC extensions here.

    I don't remember seeing any posting in comp.lang.c that
    discusses a gcc extension and nothing else. There are
    plenty of postings that mention gcc extensions in passing,
    along with other material that talks about C, but never
    one that discusses gcc extensions exclusively.

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    More interesting question than the one above is: why post of
    Alexis from 3 months ago named "Opinion on defer" is on topic in
    c.l.c ?

    My impression was that "defer", or something very much like it, is
    being considered for inclusion in a future C standard. Isn't it the
    case that Jens Gustedt is now the head of the C standard committee?
    Of course I might be wrong about that, but that's what I thought
    (and probably will still think unless and until I hear otherwise).
    Surely any language feature being considered by the C committee for
    inclusion in a future C standard, especially if it has been proposed
    by the head of the committee, is a suitable topic for discussion in comp.lang.c. Does any reader feel differently?

    How exactly can we draw a line between two cases?

    A subjective line can be drawn by asking what fraction of the C
    community at large has an interest in the feature or discussing the
    feature (in both cases as a potential addition to the C standard).
    If the fraction is 50% or higher then surely it is topical; if the
    fraction is 10% or lower then a different venue seems indicated. In
    between those two lines there are many different shades of gray.

    Alternatively, a bright line can be drawn by asking whether there is
    a proposal submitted to the C committee for the feature in question.
    If a proposal has been submitted, then without question the matter
    is suitable for comp.lang.c. If a proposal has not been submitted,
    then it seems reasonable to ask the question Why should this topic
    be considered suitable for comp.lang.c, and in the absence of any
    clear answer suggest that it is better taken elsewhere.

    Do these guidelines seem satisfactory? If not then what would you
    say is missing?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Sun Apr 6 19:03:21 2025
    On Sun, 06 Apr 2025 07:32:16 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:


    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    Could you recommend a more appropriate place for Thiago and others
    where they can discuss C-like fantasy languages?

    The newsgroup comp.lang.misc seems like a natural candidate.
    I don't know if comp.lang.misc has an official charter, but at
    least to me new features of any widely used programming language
    would appear to fall under the umbrella of comp.lang.misc.

    My question was not completely abstract.
    I did consider starting a discussion about possibility of inclusion of stackless co-routines into one of the future editions of C.
    Naturally, my ideas at this state are extremely in-concrete, much more
    so then the post of Thiago Adams that started this thread.
    So, if I ever come to it, which by itself is not very likely, do you
    think that comp.lang.misc would be better place than comp.lang.c ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Sun Apr 6 23:48:25 2025
    On Sun, 06 Apr 2025 08:14:19 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:


    My impression was that "defer", or something very much like it, is
    being considered for inclusion in a future C standard. Isn't it the
    case that Jens Gustedt is now the head of the C standard committee?
    Of course I might be wrong about that, but that's what I thought
    (and probably will still think unless and until I hear otherwise).

    It seems, The WG14 Committee has no head. They have Convener (Robert
    Seacord) but that is probably not the same.
    Jens Gustedt appears to be one of the most active members.

    https://www.open-std.org/jtc1/sc22/wg14/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From yeti@21:1/5 to David Brown on Mon Apr 7 03:56:46 2025
    David Brown <david.brown@hesbynett.no> wrote:

    A number of regulars here have responded (with posts other than "this
    is off-topic"), so that suggests there is at least some interest in
    the group.

    I like to see such things discussed here. If it looks like there is a
    need for new constructs, the thread(s) may end with acceptable
    alternatives using only current C's capabilities.

    Other times a pre-compiler might add some icing on the C cake. I'd
    prefer that way over touching the standard.

    With changes to C directly, I'd be very conservative. Far too often I
    already stumble over stuff that isn't buildable with current compilers
    any more. Try even to build some older GCC with the current ones.

    Imo we do not do us a favour if the incompatibilities pile up to a level
    that ends with C != C, but it already seems too late to stop this.

    --
    2. Hitchiker 6: (21) "Listen, three eyes," he said, "don't you try to
    outweird me. I get stranger things than you free with my breakfast
    cereal."

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Mon Apr 7 09:21:53 2025
    On 06/04/2025 22:48, Michael S wrote:
    On Sun, 06 Apr 2025 08:14:19 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:


    My impression was that "defer", or something very much like it, is
    being considered for inclusion in a future C standard. Isn't it the
    case that Jens Gustedt is now the head of the C standard committee?
    Of course I might be wrong about that, but that's what I thought
    (and probably will still think unless and until I hear otherwise).

    It seems, The WG14 Committee has no head. They have Convener (Robert
    Seacord) but that is probably not the same.
    Jens Gustedt appears to be one of the most active members.

    https://www.open-std.org/jtc1/sc22/wg14/


    He is certainly one of the more visible and energetic members - he wants
    to drive C forward with new ideas and new ways of coding, and is behind
    a fair number of the more interesting proposals (as distinct from the
    useful, but unexciting bug-fixes to the standard). He also discusses
    the ideas and the new C features regularly on his blog.

    Of course major changes to C, such as a "defer" mechanism, are highly controversial.

    The C standards committee doesn't have a leader. Jens Gustedt is the
    leader they don't have. (Paraphrased from Terry Pratchet.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to yeti on Mon Apr 7 09:16:15 2025
    On 07/04/2025 05:14, yeti wrote:
    David Brown <david.brown@hesbynett.no> wrote:

    A number of regulars here have responded (with posts other than "this
    is off-topic"), so that suggests there is at least some interest in
    the group.

    I like to see such things discussed here. If it looks like there is a
    need for new constructs, the thread(s) may end with acceptable
    alternatives using only current C's capabilities.


    I personally have no problems with this thread in this group, though I understand that others may feel differently. I think it would have been clearer that it is topical if Thiago had given a bit more explanation in
    the original post.

    Other times a pre-compiler might add some icing on the C cake. I'd
    prefer that way over touching the standard.

    With changes to C directly, I'd be very conservative. Far too often I already stumble over stuff that isn't buildable with current compilers
    any more. Try even to build some older GCC with the current ones.


    Usually all that is needed to build older code is to make sure that you
    specify the C standard explicitly, as gcc gradually updates their
    "default" C standard. I think perhaps it would be better if the
    standard had to be given explicitly with no default. Alternatively, it
    could be the current standard - C23 - along with all the compatibility
    warning flags, thus requiring the code to be in the intersection of all
    C standards.

    Occasionally there are also issues with builds using "-Wall -Werror" and
    newer gcc versions adding extra flags to -Wall, or older buggy code
    failing in the face of newer optimisations.

    Imo we do not do us a favour if the incompatibilities pile up to a level
    that ends with C != C, but it already seems too late to stop this.


    It is certainly easier when a new feature can, to at least some extent,
    be implemented as macros for older compilers. For example, it is
    possible to implement C11's "_Static_assert" using macros in C99. The
    result is uglier and gives less clear error messages, but it does the
    job. And Thiago has implements his do/quit or try/catch system in a
    limited form as macros - though a language extension would be more
    powerful (such as allowing for multiple uses within one function).

    I am sceptical to macros like these even though they are implemented in standard C - they have a tendency to make the code very hard to follow
    for anyone not used to the macros. I think they need to have very
    significant benefit to the code before they are worth that confusion,
    and I can't see that for Thiago's constructs here. But if he is
    intending to propose the constructs as a new feature for standard C,
    then it is good to prototype it with macros, and I am sure he can argue
    for the use-cases in his proposal.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Mon Apr 7 04:50:35 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 08:14:19 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    My impression was that "defer", or something very much like it, is
    being considered for inclusion in a future C standard. Isn't it the
    case that Jens Gustedt is now the head of the C standard committee?
    Of course I might be wrong about that, but that's what I thought
    (and probably will still think unless and until I hear otherwise).

    It seems, The WG14 Committee has no head. They have Convener (Robert Seacord) but that is probably not the same.
    Jens Gustedt appears to be one of the most active members.

    https://www.open-std.org/jtc1/sc22/wg14/

    Okay, good to know. Thank you for running this down.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Mon Apr 7 05:45:19 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 07:32:16 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    Could you recommend a more appropriate place for Thiago and others
    where they can discuss C-like fantasy languages?

    The newsgroup comp.lang.misc seems like a natural candidate.
    I don't know if comp.lang.misc has an official charter, but at
    least to me new features of any widely used programming language
    would appear to fall under the umbrella of comp.lang.misc.

    My question was not completely abstract.
    I did consider starting a discussion about possibility of inclusion of stackless co-routines into one of the future editions of C.
    Naturally, my ideas at this state are extremely in-concrete, much more
    so then the post of Thiago Adams that started this thread.
    So, if I ever come to it, which by itself is not very likely, do you
    think that comp.lang.misc would be better place than comp.lang.c ?

    Before giving an answer I would like to ask some questions.

    * How much does the (still fuzzy) idea depend on running in a C
    environment? Is it very specific to C, or might it be applicable
    to other procedural/imperative languages (for example, Pascal)?

    * How much does the current C language impact what you expect to
    propose? Which aspects of C need to be taken into consideration
    in forming the proposal, and how strongly do those considerations
    affect the specifics of what would be proposed?

    * Assuming a proposed extension has been fully worked out, how
    broad or how narrow do you think the interest would be in the
    general C community for a future C standard to incorporate the
    proposed extension?

    * Assuming you get to a point where you are happy with the details
    of a proposed extension, how likely is it that you would write a
    proposal for the C standard committee, and make the effort needed
    to shepherd it through the process of being accepted for a future
    C standard?

    I realize you probably don't have firm answers for some or all of
    these questions. As part of figuring everything out, you might want
    to start a discussion both of the general idea and also about what
    the answers to these questions might be. I think comp.lang.misc is
    a good place to have such a discussion, even if your ideas are still
    in the process of being formed; the discussion could then serve the
    dual purpose of getting the idea fleshed out and of determining how
    strongly the idea should be considered as part of a future C
    standard.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Kenny McCormack on Mon Apr 7 08:06:36 2025
    gazelle@shell.xmission.com (Kenny McCormack) writes:

    In article <20250406162607.0000657a@yahoo.com>,
    Michael S <already5chosen@yahoo.com> wrote:
    ...

    More interesting question than the one above is: why post of Alexis
    from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
    How exactly can we draw a line between two cases?

    Tim Wrench is clearly a lunatic. And he's in my killfile.

    The language he uses in this thread is just beyond the pale (*) in
    terms of rudeness and non-civility. If his target was anyone else
    (and especially if it was an old regular), we'd probably have 20
    posts already condemning his language.

    I usually read postings from Kenny. Before now I didn't know
    he had put me in his killfile, or that he had this reaction to my
    comments.

    In posting a followup to a message, I make an effort to respond
    to the content and not the person. I don't feel obliged to
    follow this rule in cases where there seems to be a regular
    pattern of rude or anti-social behavior.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Mon Apr 7 21:02:48 2025
    On Mon, 07 Apr 2025 05:45:19 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 07:32:16 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    Could you recommend a more appropriate place for Thiago and others
    where they can discuss C-like fantasy languages?

    The newsgroup comp.lang.misc seems like a natural candidate.
    I don't know if comp.lang.misc has an official charter, but at
    least to me new features of any widely used programming language
    would appear to fall under the umbrella of comp.lang.misc.

    My question was not completely abstract.
    I did consider starting a discussion about possibility of inclusion
    of stackless co-routines into one of the future editions of C.
    Naturally, my ideas at this state are extremely in-concrete, much
    more so then the post of Thiago Adams that started this thread.
    So, if I ever come to it, which by itself is not very likely, do you
    think that comp.lang.misc would be better place than comp.lang.c ?

    Before giving an answer I would like to ask some questions.

    * How much does the (still fuzzy) idea depend on running in a C
    environment? Is it very specific to C, or might it be applicable
    to other procedural/imperative languages (for example, Pascal)?

    * How much does the current C language impact what you expect to
    propose? Which aspects of C need to be taken into consideration
    in forming the proposal, and how strongly do those considerations
    affect the specifics of what would be proposed?


    Of course, proposals for similar feature in other procedural/imperative language would not be totally different. Pascal is more similar to C
    than many other procedural languages, so solution for Pascal would
    likely be more similar to C than for example, stackless co-routines
    that already exist in such languages like C# (that started current wave
    of popularity of the feature) or Python.
    However Pascal and C have enough not in common for significant
    difference in proposed syntax and implementation. Specifically, in
    Pascal:
    - heap management is built-n in the language
    - non-local goto is built-n in the language
    - nested procedures
    - everything related to separated compilation of the translation units
    is handwaved in the docs rather than strictly specified. May be it's
    not so in Extended Pascal standard, I never read it.

    Most importantly, Pascal in its hay days had different (from C)
    attitude with regard to standardization. Implementors, especially
    bigger ones, freely made very significant mutually incompatible
    extensions and nobody in community was upset about it. C way is more centralized.

    * Assuming a proposed extension has been fully worked out, how
    broad or how narrow do you think the interest would be in the
    general C community for a future C standard to incorporate the
    proposed extension?



    My own interest is for microcontrollers, primarily 32-bit
    microcontrollers. Environments of interest are either without
    multitasking library at all (my favorite) or with relatively simple multitasking known as Real-time executives. In recent time the one
    which is pushed by MCU vendors, which helps popularity rather immensely,
    is called FreeRTOS.
    These environments are characterized by not especially tight code
    footprint but rather tight (writable) RAM footprint.

    I don't believe that the feature is interesting for application
    programming on "big" computers/OSes. IMHO, on "big" computers the same objectives can be achieved in cleaner way through full (==stackfull)
    coroutines or even by threads. Stackfull coroutines do not require
    integration into programming language, esp. into relatively low-level
    language, like C. They tend to be widely available for several decades
    on majority of widely used OSes. And they tend to be ignored by C
    programmers. Which, to me, suggests that the same would happen to more
    limited stackless variant.
    Anyway, application programming in C on "big" computers/OSes is a dying
    field, and probably deservingly so. WG14 Committee should acknowledge
    the fact by putting their needs at lowest priority. Unlike that
    programming MCUs in C is as healthy as ever. So should be prioritized
    higher.

    The 3rd field is kernel programming. I wrote my fare share of kernel
    drivers for Windows and a couple for Linux, but it never was my passion.
    Kernel programming always felt to me as unpleasant programming
    experience. I know that other people feel very differently about it.
    So, despite 1st hand experience, I don't consider myself qualified to
    judge if stackless coroutines can fit here or not. Although my
    unqualified opinion is "not".

    * Assuming you get to a point where you are happy with the details
    of a proposed extension, how likely is it that you would write a
    proposal for the C standard committee, and make the effort needed
    to shepherd it through the process of being accepted for a future
    C standard?


    Not likely. I would have to somehow convince somebody else to do it.

    I realize you probably don't have firm answers for some or all of
    these questions. As part of figuring everything out, you might want
    to start a discussion both of the general idea and also about what
    the answers to these questions might be. I think comp.lang.misc is
    a good place to have such a discussion, even if your ideas are still
    in the process of being formed; the discussion could then serve the
    dual purpose of getting the idea fleshed out and of determining how
    strongly the idea should be considered as part of a future C
    standard.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Michael S on Mon Apr 7 19:31:23 2025
    On 07/04/2025 19:02, Michael S wrote:
    On Mon, 07 Apr 2025 05:45:19 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 07:32:16 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    Could you recommend a more appropriate place for Thiago and others
    where they can discuss C-like fantasy languages?

    The newsgroup comp.lang.misc seems like a natural candidate.
    I don't know if comp.lang.misc has an official charter, but at
    least to me new features of any widely used programming language
    would appear to fall under the umbrella of comp.lang.misc.

    My question was not completely abstract.
    I did consider starting a discussion about possibility of inclusion
    of stackless co-routines into one of the future editions of C.
    Naturally, my ideas at this state are extremely in-concrete, much
    more so then the post of Thiago Adams that started this thread.
    So, if I ever come to it, which by itself is not very likely, do you
    think that comp.lang.misc would be better place than comp.lang.c ?

    Before giving an answer I would like to ask some questions.

    * How much does the (still fuzzy) idea depend on running in a C
    environment? Is it very specific to C, or might it be applicable
    to other procedural/imperative languages (for example, Pascal)?

    * How much does the current C language impact what you expect to
    propose? Which aspects of C need to be taken into consideration
    in forming the proposal, and how strongly do those considerations
    affect the specifics of what would be proposed?


    Of course, proposals for similar feature in other procedural/imperative language would not be totally different. Pascal is more similar to C
    than many other procedural languages, so solution for Pascal would
    likely be more similar to C than for example, stackless co-routines
    that already exist in such languages like C# (that started current wave
    of popularity of the feature) or Python.
    However Pascal and C have enough not in common for significant
    difference in proposed syntax and implementation. Specifically, in
    Pascal:
    - heap management is built-n in the language
    - non-local goto is built-n in the language

    That's news to me. But then I only used an educational version.

    - nested procedures
    - everything related to separated compilation of the translation units
    is handwaved in the docs rather than strictly specified.

    I don't think it's that strictly specified in C. Isn't it vaguely left
    to the implementation?

    Much of how different units share macros, types, structs and enums isn't
    part of the language at all AFAICS: it's just a by-product of different
    modules happening to include the same header files.

    But it could also be done by repeating declarations in each module; it's
    rather ad hoc.

    The Pascal I used only worked with one module; more recent versions do
    seem to have formal interfaces which are part of the language. So it is
    more rigorous than C.


    May be it's
    not so in Extended Pascal standard, I never read it.

    Most importantly, Pascal in its hay days had different (from C)
    attitude with regard to standardization. Implementors, especially
    bigger ones, freely made very significant mutually incompatible
    extensions and nobody in community was upset about it. C way is more centralized.

    I have a feeling that there were WAY more variations of C than Pascal,
    largely because C was more popular and more widespread.

    You still see this know when you delve into systems and applications
    headers which are often a mess of '#ifdef' blocks which special-case
    specific compiler versions which all have different characteristics.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Tue Apr 8 10:12:22 2025
    On 07/04/2025 20:31, bart wrote:
    On 07/04/2025 19:02, Michael S wrote:
    On Mon, 07 Apr 2025 05:45:19 -0700

    Of course, proposals for similar feature in other procedural/imperative
    language would not be totally different. Pascal is more similar to C
    than many other procedural languages, so solution for Pascal would
    likely be more similar to C than for example, stackless co-routines
    that already exist in such languages like C# (that started current wave
    of popularity of the feature) or Python.
    However Pascal and C have enough not in common for significant
    difference in proposed syntax and implementation. Specifically, in
    Pascal:
    - heap management is built-n in the language
    - non-local goto is built-n in the language

    That's news to me. But then I only used an educational version.

    - nested procedures
    - everything related to separated compilation of the translation units
    is handwaved in the docs rather than strictly specified.

    I don't think it's that strictly specified in C. Isn't it vaguely left
    to the implementation?


    No.

    Much of how different units share macros, types, structs and enums isn't
    part of the language at all AFAICS: it's just a by-product of different modules happening to include the same header files.


    Linkage is explained in 6.2.2 - only identifiers with external linkage
    are shared amongst translation units. Macros, types, enums are all have
    no linkage and are therefore never shared.

    The only way to make new non-standard types in C is with "struct",
    "union" or "enum". Section 6.2.7 of the standard sets out simply and
    clearly what is required for two types in different translation units to
    be compatible. (It doesn't make sense to say they are the "same type"
    in C lingo, since types have no linkage, but compatibility is the
    important point.)

    Sharing a definition in a header file is normally the easiest way to
    ensure that the types used in different translation files are
    compatible, but it is not required.

    But it could also be done by repeating declarations in each module; it's rather ad hoc.

    It is not remotely "ad hoc" - as far as the language is concerned,
    including a header file /is/ repeating the declaration in the different translation units. The way C handles this kind of thing is arguably
    weaker than in languages that have proper modules (like Ada, or Modula
    2), and much more open to mistakes. On the other hand, it is very
    flexible and simple to understand, and does not need additional
    specialised object files or "interface" files. It is possible to write
    C code in an "ad hoc" manner (such as declaring an "extern" identifier
    within a C file rather than a header file), but the language definition
    is not "ad hoc".


    The Pascal I used only worked with one module; more recent versions do
    seem to have formal interfaces which are part of the language. So it is
    more rigorous than C.


    Yes, most Pascal versions suitable for real development (rather than the
    older teaching versions) have more formal interfaces. Personally, I
    prefer more formal interfaces - more formality and stronger typing
    reduce flexibility but also reduce the risk of some kinds of errors, and
    can make a language more amenable to analysis.


    May be it's
    not so in Extended Pascal standard, I never read it.

    Most importantly, Pascal in its hay days had different (from C)
    attitude with regard to standardization. Implementors, especially
    bigger ones, freely made very significant mutually incompatible
    extensions and nobody in community was upset about it. C way is more
    centralized.

    I have a feeling that there were WAY more variations of C than Pascal, largely because C was more popular and more widespread.


    I suspect you are wrong here. There are certainly far more C compilers
    than Pascal compilers, and there are minor variations between the C
    compilers, but even prior to K&R's book the differences between C
    compilers was smaller than between the different Pascal versions.
    Pascal was standardised, but standard Pascal was too limited for most commercial use and different vendors build on it - with Borland's line
    being the most relevant. Comparing modern Delphi and standard Pascal is
    a bit like comparing C# with K&R C.

    You still see this know when you delve into systems and applications
    headers which are often a mess of '#ifdef' blocks which special-case
    specific compiler versions which all have different characteristics.


    Certainly there are variations in the details - in particular, there are
    lots of things in C (and Pascal) that are "implementation defined".

    It is the similarity between C compilers that means that often all you
    need is some #ifdef's for low-level or library code shared between C
    compilers on significantly different systems or targets. If you want to
    write a low-level library for Free Pascal, Delphi, GNU Pascal, and
    Pascal-P, you write four versions of it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Tue Apr 8 12:35:34 2025
    On 08/04/2025 09:12, David Brown wrote:
    On 07/04/2025 20:31, bart wrote:
    On 07/04/2025 19:02, Michael S wrote:
    On Mon, 07 Apr 2025 05:45:19 -0700

    Of course, proposals for similar feature in other procedural/imperative
    language would not be totally different. Pascal is more similar to C
    than many other procedural languages, so solution for Pascal would
    likely be more similar to C than for example, stackless co-routines
    that already exist in such languages like C# (that started current wave
    of popularity of the feature) or Python.
    However Pascal and C have enough not in common for significant
    difference in proposed syntax and implementation. Specifically, in
    Pascal:
    - heap management is built-n in the language
    - non-local goto is built-n in the language

    That's news to me. But then I only used an educational version.

    - nested procedures
    - everything related to separated compilation of the translation units
    is handwaved in the docs rather than strictly specified.

    I don't think it's that strictly specified in C. Isn't it vaguely left
    to the implementation?


    No.

    C simply has the requirement for separate compilation of modules. Where
    does it specify how the implementation does that?

    Much of how different units share macros, types, structs and enums
    isn't part of the language at all AFAICS: it's just a by-product of
    different modules happening to include the same header files.


    Linkage is explained in 6.2.2 - only identifiers with external linkage
    are shared amongst translation units.  Macros, types, enums are all have
    no linkage and are therefore never shared.

    From the programmer point of view, they are shared. But the language
    provides no specific mechanism for that.



    The only way to make new non-standard types in C is with "struct",
    "union" or "enum".  Section 6.2.7 of the standard sets out simply and clearly what is required for two types in different translation units to
    be compatible.  (It doesn't make sense to say they are the "same type"
    in C lingo, since types have no linkage, but compatibility is the
    important point.)

    Sharing a definition in a header file is normally the easiest way to
    ensure that the types used in different translation files are
    compatible, but it is not required.

    But it could also be done by repeating declarations in each module;
    it's rather ad hoc.

    It is not remotely "ad hoc" - as far as the language is concerned,
    including a header file /is/ repeating the declaration in the different translation units.

    The programmer can achieve the objective in multiple ways; that's what's
    ad hoc. The implementation itself works by crossing its fingers and
    hoping that the multiple declarations of the common entity X that are
    seen by the different translation unit are fully compatible.

    But this need not be the case. For example this is module A:

    --------------------------
    #include <stdio.h>

    typedef struct point {float a; float b;} Point;

    float dist(Point);

    int main(void) {
    Point p = {3, 4};
    printf("%f\n", dist(p));
    }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
    #include <math.h>

    typedef float length;
    typedef struct _tag {length x, y;} vector;

    length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);} --------------------------

    The types involved are somewhat different, but are compatible enough for
    it to work.

    However, they could also be different enough (in a more elaborate
    example) for things to superficially work.

    This is what I mean by 'ad hoc'.


    This is how it looks when there is language support; first module A:

    --------------------------
    module b # (imports b)

    proc main=
    point p := (3, 4)

    println dist(p)
    end

    --------------------------

    Module B:
    --------------------------
    global record point = (real32 x, y)

    global fun dist(point p)real32 = sqrt(sqr(p.x) + sqr(p.y)) --------------------------

    (Example from one of mine, which uses whole-program compilation) Here,
    unlike C, you need to decide which module owns and exports the type.
    Then, there is only that one version which is shared.

    However similar problems to C can occur when sharing across /programs/,
    which could be written in different languages (eg. libraries).

    I don't know if or how the C standard addresses that, since it can only
    talk about the C language. For that matter, a single program with
    independently compiled modules might have only some of those in C.

    So there is even more scope for ad hoc-ness.

    The way C handles this kind of thing is arguably
    weaker than in languages that have proper modules (like Ada, or Modula
    2), and much more open to mistakes.  On the other hand, it is very
    flexible and simple to understand,


    The preprocessor mechanisms available to work with source code are
    fairly easy to grasp (but may be complex in practice with multiple
    nested headers spread over a file system).

    But I had, and do still have, difficulty with how exactly you import and
    export entities, even ones with linkage.

    How compilers deal with it have changed. But right now, if I put this in
    a header shared by A and B modules:

    int abc;

    I get 'multiple definition' of abc (from some compilers; others have no problem).

    If I stick 'extern' in front, I get 'undefined reference' of abc. To
    make it work, 'extern int abc' is shared, and one module must see 'int abc'.

    However if I need to initialise the variable:

    extern int table[]; // shared
    int table[] = (10, 20, 30)

    then other modules can't pick up length of the array.


    and does not need additional
    specialised object files or "interface" files.  It is possible to write
    C code in an "ad hoc" manner (such as declaring an "extern" identifier
    within a C file rather than a header file), but the language definition
    is not "ad hoc".

    So, what are the rules again for mixing 'extern' and 'static'
    declarations? Since this passes gcc:

    static int def;
    static int def;
    extern int def;
    static int def;

    but this doesn't:

    extern int def;
    static int def;
    static int def;
    static int def;

    Are you sure they aren't ad hoc? Simply saying that the C standard
    enumerates the legal combinations doesn't make them not so!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Tue Apr 8 16:50:56 2025
    On 08/04/2025 13:35, bart wrote:
    On 08/04/2025 09:12, David Brown wrote:
    On 07/04/2025 20:31, bart wrote:
    On 07/04/2025 19:02, Michael S wrote:
    On Mon, 07 Apr 2025 05:45:19 -0700

    Of course, proposals for similar feature in other procedural/imperative >>>> language would not be totally different. Pascal is more similar to C
    than many other procedural languages, so solution for Pascal would
    likely be more similar to C than for example, stackless co-routines
    that already exist in such languages like C# (that started current wave >>>> of popularity of the feature) or Python.
    However Pascal and C have enough not in common for significant
    difference in proposed syntax and implementation. Specifically, in
    Pascal:
    - heap management is built-n in the language
    - non-local goto is built-n in the language

    That's news to me. But then I only used an educational version.

    - nested procedures
    - everything related to separated compilation of the translation units >>>> is handwaved in the docs rather than strictly specified.

    I don't think it's that strictly specified in C. Isn't it vaguely
    left to the implementation?


    No.

    C simply has the requirement for separate compilation of modules. Where
    does it specify how the implementation does that?

    The details of how a compiler (and linker) run are not part of a
    language specification. But how separately compiled units interact is
    in the standard.


    Much of how different units share macros, types, structs and enums
    isn't part of the language at all AFAICS: it's just a by-product of
    different modules happening to include the same header files.


    Linkage is explained in 6.2.2 - only identifiers with external linkage
    are shared amongst translation units.  Macros, types, enums are all
    have no linkage and are therefore never shared.

    From the programmer point of view, they are shared. But the language provides no specific mechanism for that.


    No, of course not. A language specification says what the language
    /means/, not how tools make that happen. That is a good thing - if the
    C standards had specified that translation units get compiled to object
    files and then a linker is used, you couldn't have link-time
    optimisation or whole-program compilation.



    The only way to make new non-standard types in C is with "struct",
    "union" or "enum".  Section 6.2.7 of the standard sets out simply and
    clearly what is required for two types in different translation units
    to be compatible.  (It doesn't make sense to say they are the "same
    type" in C lingo, since types have no linkage, but compatibility is
    the important point.)

    Sharing a definition in a header file is normally the easiest way to
    ensure that the types used in different translation files are
    compatible, but it is not required.

    But it could also be done by repeating declarations in each module;
    it's rather ad hoc.

    It is not remotely "ad hoc" - as far as the language is concerned,
    including a header file /is/ repeating the declaration in the
    different translation units.

    The programmer can achieve the objective in multiple ways; that's what's
    ad hoc.

    As I said - the C standards and the language are not ad hoc. But it is possible to write ad hoc code.

    The implementation itself works by crossing its fingers and
    hoping that the multiple declarations of the common entity X that are
    seen by the different translation unit are fully compatible.


    Nope. You are just making stuff up in your never-ending quest to
    misunderstand C and pretend everything about it is terrible.

    But it is certainly true that the inter-unit interaction in C is less
    rigid and controlled than in some other languages. That keeps the
    language and its definition simpler, allows simpler implementations, and
    gives more programmer flexibility (especially if they are happy with non-portable code). The flip side is that it also allows more abuse or accidental mistakes, and requires more advanced tools to diagnose
    problems (such as using link-time optimising compilers or whole-program analysis tools).

    But this need not be the case. For example this is module A:

    --------------------------
      #include <stdio.h>

      typedef struct point {float a; float b;} Point;

      float dist(Point);

      int main(void) {
          Point p = {3, 4};
          printf("%f\n", dist(p));
      }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
      #include <math.h>

      typedef float length;
      typedef struct _tag {length x, y;} vector;

      length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);} --------------------------

    The types involved are somewhat different, but are compatible enough for
    it to work.

    The two types are entirely compatible. "typedef" does not introduce a
    new type, and struct types in different modules are compatible if they
    are build from the same compatible field types in the same order.


    However, they could also be different enough (in a more elaborate
    example) for things to superficially work.

    Not in C.


    This is what I mean by 'ad hoc'.

    If that's what you meant by "ad hoc", you were wrong about C being "ad hoc".


    The way C handles this kind of thing is arguably weaker than in
    languages that have proper modules (like Ada, or Modula 2), and much
    more open to mistakes.  On the other hand, it is very flexible and
    simple to understand,


    The preprocessor mechanisms available to work with source code are
    fairly easy to grasp (but may be complex in practice with multiple
    nested headers spread over a file system).

    That's like complaining that integer addition is complex because someone
    might want to add 26 digit numbers. Stop being silly.


    But I had, and do still have, difficulty with how exactly you import and export entities, even ones with linkage.

    That sounds very much like a "Bart" problem. If you /genuinely/ want to
    know, and you can't figure it out with a quick google search, reading
    the page in the standards, or looking at an introduction to C book, then
    please ask. If you are just trying to claim opportunities to say it's
    all so difficult and confusing, then don't bother.


    How compilers deal with it have changed.

    As a general rule, they have not.

    But it is true that some compilers have by default supported an
    extension that was designed to make interoperability with Fortran
    programs easier - and that extension allows C programmers to make
    mistakes if they don't understand the very simple rule of defining
    objects only once in a C program. (I pushed for this extension to be
    disabled by default in gcc.)

    But right now, if I put this in
    a header shared by A and B modules:

      int abc;

    I get 'multiple definition' of abc (from some compilers; others have no problem).

    It is an error to link these translation units in C - but some compilers accepted it.

    You know how linkers work with assembly, so it is easiest to explain it
    in terms of a typical implementation (though the C standard does not
    require any of this). When you write "int abc;" at file scope, without "static", the compiler will put the symbol in ".bss" if it is
    zero-initialised, and in ".data" if it is explicitly initialised. At
    link time, if the linker sees the same symbol defined more than once, it complains.

    The exception is that if the linker sees identically named symbols in a
    section called ".common", they are merged without complaint - that is
    the way Fortran handles linkage. So some compilers put uninitialised
    data in a ".common" section rather than ".bss", allowing them to be linked.

    This is, of course, a terrible idea, and a flaw in those compilers.


    If I stick 'extern' in front, I get 'undefined reference' of abc. To
    make it work, 'extern int abc' is shared, and one module must see 'int
    abc'.

    Yes. One definition in the program as a whole, and as many declarations
    as you like. Simple.


    However if I need to initialise the variable:

       extern int table[];          // shared
       int table[] = (10, 20, 30)

    then other modules can't pick up length of the array.


    Correct.


     and does not need additional
    specialised object files or "interface" files.  It is possible to
    write C code in an "ad hoc" manner (such as declaring an "extern"
    identifier within a C file rather than a header file), but the
    language definition is not "ad hoc".

    So, what are the rules again for mixing 'extern' and 'static'
    declarations? Since this passes gcc:

      static int def;
      static int def;
      extern int def;
      static int def;

    but this doesn't:

      extern int def;
      static int def;
      static int def;
      static int def;

    The rules are given in 6.2.2 of the standard under "Linkages of
    identifiers", as I mentioned earlier. Of course people don't mix
    storage class specifiers like this - while the language rules make it
    clear what happens as far as the semantics of C are concerned, such duplications would be confusing or at best redundant.


    Are you sure they aren't ad hoc? Simply saying that the C standard
    enumerates the legal combinations doesn't make them not so!


    The C standard gives clear rules here that make sense. That does not
    mean they are the /only/ set of rules a language could have that makes
    sense, but they are not "ad hoc". That would imply that combinations
    like this could have unpredictable meanings.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Tue Apr 8 17:28:01 2025
    On 08/04/2025 15:50, David Brown wrote:
    On 08/04/2025 13:35, bart wrote:

    But this need not be the case. For example this is module A:

    --------------------------
       #include <stdio.h>

       typedef struct point {float a; float b;} Point;

       float dist(Point);

       int main(void) {
           Point p = {3, 4};
           printf("%f\n", dist(p));
       }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
       #include <math.h>

       typedef float length;
       typedef struct _tag {length x, y;} vector;

       length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible enough
    for it to work.

    The two types are entirely compatible.


    Are they? So why does gcc report an error here (the two types are from
    my example):

    typedef struct point {float a; float b;} Point;

    typedef float length;
    typedef struct _tag {length x, y;} vector;

    Point p;
    vector v;

    p=v;

    c.c:14:5: error: incompatible types when assigning to type 'Point' {aka
    'struct point'} from type
    ector' {aka 'struct _tag'}
    14 | p=v;
    | ^


    "typedef" does not introduce a
    new type, and struct types in different modules are compatible if they
    are build from the same compatible field types in the same order.


    However, they could also be different enough (in a more elaborate
    example) for things to superficially work.

    Not in C.

    Really? I could have added a dozen extra fields to one (or a pile of incompatible fields to both), and it can still work (especially if I
    pass the struct by reference).

    The preprocessor mechanisms available to work with source code are
    fairly easy to grasp (but may be complex in practice with multiple
    nested headers spread over a file system).

    That's like complaining that integer addition is complex because someone might want to add 26 digit numbers.  Stop being silly.

    You're missing the point: the concept may be simple, but as typically
    used in C, it is can be much more complex than necessary. Doing:

    #include "lib.h"

    is not enough; there may be a dozen different header locations (from
    nested includes) that need to be made known to the compiler, so you need
    to figure them out first!

    A program may comprise 100 .c files, but use 37 different headers in
    mixed, possible nested combinations across those 100 modules. You can't
    in general tie one .c file to a specific .h file; /that/ would be simpler.

    So the usual thing applies in C: the language lays down some vague
    rules, beyond that it's a free-for-all.

    You choose to call that 'being flexible'; I might call it something else.



    But I had, and do still have, difficulty with how exactly you import
    and export entities, even ones with linkage.

    That sounds very much like a "Bart" problem.

    You really think that I wouldn't know how to do this if the language
    provided genuinely simple and well-thought-out and consistent rules?

    Here are some rules from another of my languages; this time it's an
    assembler:

    L1: # local label
    L2:: # exported label
    call puts* # imported symbol
    call fred # name defined in this file (which may be
    # local or exported depending on : or ::)

    There are no explicit sets of declarations (eg. 'extern puts' as in
    other products); no forward declarations are needed.

    Simple, yes?


      If you /genuinely/ want to
    know, and you can't figure it out with a quick google search, reading
    the page in the standards, or looking at an introduction to C book, then please ask.  If you are just trying to claim opportunities to say it's
    all so difficult and confusing, then don't bother.

    Ah yes, the Microsoft approach: provide huge amounts of resources,
    manuals, training courses etc, rather than making something actually simple!


    How compilers deal with it have changed.

    As a general rule, they have not.

    But it is true that some compilers have by default supported an
    extension that was designed to make interoperability with Fortran
    programs easier

    Which means a pile of badly written programs.

    However if I need to initialise the variable:

        extern int table[];          // shared
        int table[] = (10, 20, 30)

    then other modules can't pick up length of the array.


    Correct.

    And the workaround is...?

    (Maybe you can appreciate one of many reasons why I normally generate C
    code for a project as one source file.)

    The C standard gives clear rules here that make sense.

    What's the rational for allowing both static and extern versions of the
    same entity in the same file? And if that is allowed, why does the order matter?

    (In my compiler I gave up trying to make sense of it, and just ended up
    allow any combination unless it was clearly wrong.)

      That does not
    mean they are the /only/ set of rules a language could have that makes
    sense, but they are not "ad hoc".  That would imply that combinations
    like this could have unpredictable meanings.

    I don't mean 'ad hoc' to be 'indeterminate'. More like, 'mess', or 'free-for-all'.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Tue Apr 8 10:32:23 2025
    bart <bc@freeuk.com> writes:

    On 08/04/2025 15:50, David Brown wrote:

    On 08/04/2025 13:35, bart wrote:

    But this need not be the case. For example this is module A:

    --------------------------
    #include <stdio.h>

    typedef struct point {float a; float b;} Point;

    float dist(Point);

    int main(void) {
    Point p = {3, 4};
    printf("%f\n", dist(p));
    }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
    #include <math.h>

    typedef float length;
    typedef struct _tag {length x, y;} vector;

    length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible
    enough for it to work.

    The two types are entirely compatible.

    Are they?

    No, they are not. The type names 'Point' and 'vector' name two
    distinct types, and those types are not compatible, because
    the two struct tags are different.

    Because the two types are not compatible, even just calling the
    function dist() is undefined behavior.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Tue Apr 8 10:47:33 2025
    bart <bc@freeuk.com> writes:

    On 08/04/2025 09:12, David Brown wrote:

    On 07/04/2025 20:31, bart wrote:

    On 07/04/2025 19:02, Michael S wrote:

    On Mon, 07 Apr 2025 05:45:19 -0700

    [discussing Pascal]
    - nested procedures
    - everything related to separated compilation of the translation
    units is handwaved in the docs rather than strictly specified.

    I don't think it's that strictly specified in C. Isn't it vaguely
    left to the implementation?

    No.

    C simply has the requirement for separate compilation of
    modules. Where does it specify how the implementation does that?

    In C the term is translation units, not modules.

    The C standard requires implementations be able to combine
    separately compiled translation units into a single unified
    program image that contains all the information needed for
    program execution. The standard doesn't say how this step
    is to be done, only that implementations must be able to
    do it. Also, the standard doesn't say how to cause a
    produced program image to be executed; rather, there is an
    explicit statement that says how to do that is outside the
    scope of the standard.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Tue Apr 8 10:59:50 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Mon, 07 Apr 2025 05:45:19 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 07:32:16 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    Could you recommend a more appropriate place for Thiago and others
    where they can discuss C-like fantasy languages?

    The newsgroup comp.lang.misc seems like a natural candidate.
    I don't know if comp.lang.misc has an official charter, but at
    least to me new features of any widely used programming language
    would appear to fall under the umbrella of comp.lang.misc.

    My question was not completely abstract.
    I did consider starting a discussion about possibility of inclusion
    of stackless co-routines into one of the future editions of C.
    Naturally, my ideas at this state are extremely in-concrete, much
    more so then the post of Thiago Adams that started this thread.
    So, if I ever come to it, which by itself is not very likely, do you
    think that comp.lang.misc would be better place than comp.lang.c ?

    Before giving an answer I would like to ask some questions.

    * How much does the (still fuzzy) idea depend on running in a C
    environment? Is it very specific to C, or might it be applicable
    to other procedural/imperative languages (for example, Pascal)?

    * How much does the current C language impact what you expect to
    propose? Which aspects of C need to be taken into consideration
    in forming the proposal, and how strongly do those considerations
    affect the specifics of what would be proposed?

    [...]

    My apologies; I gave the wrong impression. I didn't mean I wanted
    to see the answers myself. What I did mean is that the questions
    are good for you (or someone else) to ask of themselves to decide
    whether comp.lang.c or comp.lang.misc (or possibly some other group)
    is a better place for a posting.

    Given that the details seem to be still a bit fuzzy, I tend to think comp.lang.misc is a better place to start. But after thinking about
    the questions you might decide otherwise.

    * Assuming you get to a point where you are happy with the details
    of a proposed extension, how likely is it that you would write a
    proposal for the C standard committee, and make the effort needed
    to shepherd it through the process of being accepted for a future
    C standard?

    Not likely. I would have to somehow convince somebody else to do it.

    I see. Well, good luck with that. :)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Tim Rentsch on Tue Apr 8 19:04:10 2025
    On 08/04/2025 18:32, Tim Rentsch wrote:
    bart <bc@freeuk.com> writes:

    On 08/04/2025 15:50, David Brown wrote:

    On 08/04/2025 13:35, bart wrote:

    But this need not be the case. For example this is module A:

    --------------------------
    #include <stdio.h>

    typedef struct point {float a; float b;} Point;

    float dist(Point);

    int main(void) {
    Point p = {3, 4};
    printf("%f\n", dist(p));
    }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
    #include <math.h>

    typedef float length;
    typedef struct _tag {length x, y;} vector;

    length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible
    enough for it to work.

    The two types are entirely compatible.

    Are they?

    No, they are not. The type names 'Point' and 'vector' name two
    distinct types, and those types are not compatible, because
    the two struct tags are different.

    Because the two types are not compatible, even just calling the
    function dist() is undefined behavior.

    I get an incompatible error (from the example you snipped) even when I
    remove both struct tags.

    I can't use the same struct tag in the same scope as one will clash with
    the other. But if I have the second in an inner scope, then I again get
    the error.

    It doesn't seem to be anything to do with struct tags.

    Two typedefs for same struct layout appear to create distinct types;
    this fails:

    typedef struct {float x, y;} Point;
    typedef struct {float x, y;} vector;

    Point p;
    vector v;

    p=v;


    But this works:

    typedef struct {float x, y;} Point, vector;

    Point p;
    vector v;

    p=v;

    So it seems to depend on whether Point and vector share the same
    internal descriptor for the struct.

    In my original example, the structs were defined in separate translation
    unit, so the compiler has to take things on trust.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From candycanearter07@21:1/5 to Kaz Kylheku on Tue Apr 8 19:00:04 2025
    Kaz Kylheku <643-408-1753@kylheku.com> wrote at 20:39 this Friday (GMT):
    On 2025-04-04, Kaz Kylheku <643-408-1753@kylheku.com> wrote:
    On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }


    The else part might need access to some local variables
    in the main part.

    do {
    char *name = calculate_path(PATH_PREFIX "/", name, ".txt");
    FILE *f = fopen(...)

    if (!f)
    quit;
    ...
    }
    else
    {
    printf("unable to open %s\n", name);
    ...
    }

    If you make that work, you're creating scope wormholes between
    disjoint curly braces, which is not allowed if youre name isn't
    Bjarne Stroustrup.

    How about: do/else if/else if/else with argument passing to first
    clause whose signature can take the argument list:

    do {
    ...
    quit("rage"); // goes to (char *arg)
    ...
    quit(42); // goes to (int arg)
    ...
    }
    else if (char *arg) // or just else? multiple elses on do, why not.
    {
    }
    else (int arg)
    {
    }

    Friday `f`noons, eh?


    I believe that's how python try/except works, with different error
    types.
    --
    user <candycane> is generated from /dev/urandom

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Tue Apr 8 14:18:30 2025
    bart <bc@freeuk.com> writes:

    On 08/04/2025 18:32, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    On 08/04/2025 15:50, David Brown wrote:

    On 08/04/2025 13:35, bart wrote:

    But this need not be the case. For example this is module A:

    --------------------------
    #include <stdio.h>

    typedef struct point {float a; float b;} Point;

    float dist(Point);

    int main(void) {
    Point p = {3, 4};
    printf("%f\n", dist(p));
    }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
    #include <math.h>

    typedef float length;
    typedef struct _tag {length x, y;} vector;

    length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible
    enough for it to work.

    The two types are entirely compatible.

    Are they?

    No, they are not. The type names 'Point' and 'vector' name two
    distinct types, and those types are not compatible, because
    the two struct tags are different.

    Because the two types are not compatible, even just calling the
    function dist() is undefined behavior.

    I get an incompatible error (from the example you snipped) even when I
    remove both struct tags.

    I can't use the same struct tag in the same scope as one will clash
    with the other. But if I have the second in an inner scope, then I
    again get the error.

    If you want to make a point or ask a question about C code,
    SHOW THE CODE. And show all of it. Don't make people guess
    by showing only some of the code or by giving just a description.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Tim Rentsch on Tue Apr 8 23:38:18 2025
    On 08/04/2025 22:18, Tim Rentsch wrote:
    bart <bc@freeuk.com> writes:

    On 08/04/2025 18:32, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    On 08/04/2025 15:50, David Brown wrote:

    On 08/04/2025 13:35, bart wrote:

    But this need not be the case. For example this is module A:

    --------------------------
    #include <stdio.h>

    typedef struct point {float a; float b;} Point;

    float dist(Point);

    int main(void) {
    Point p = {3, 4};
    printf("%f\n", dist(p));
    }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
    #include <math.h>

    typedef float length;
    typedef struct _tag {length x, y;} vector;

    length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible
    enough for it to work.

    The two types are entirely compatible.

    Are they?

    No, they are not. The type names 'Point' and 'vector' name two
    distinct types, and those types are not compatible, because
    the two struct tags are different.

    Because the two types are not compatible, even just calling the
    function dist() is undefined behavior.

    I get an incompatible error (from the example you snipped) even when I
    remove both struct tags.

    I can't use the same struct tag in the same scope as one will clash
    with the other. But if I have the second in an inner scope, then I
    again get the error.

    If you want to make a point or ask a question about C code,
    SHOW THE CODE. And show all of it. Don't make people guess
    by showing only some of the code or by giving just a description.

    I'm showing the code but you keep snipping it! If you want testable
    code, just wrap it with 'int main() { ... }'. (I assumed you could
    figure that out.)

    Here I was responding to your remark that the types are incompatible
    because the struct tags are different. If by that you mean 'struct X' vs 'struct Y', then I said that isn't the case, as my example without such
    tags showed.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Tue Apr 8 16:27:23 2025
    bart <bc@freeuk.com> writes:

    On 08/04/2025 22:18, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    On 08/04/2025 18:32, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    On 08/04/2025 15:50, David Brown wrote:

    On 08/04/2025 13:35, bart wrote:

    But this need not be the case. For example this is module A:

    --------------------------
    #include <stdio.h>

    typedef struct point {float a; float b;} Point;

    float dist(Point);

    int main(void) {
    Point p = {3, 4};
    printf("%f\n", dist(p));
    }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
    #include <math.h>

    typedef float length;
    typedef struct _tag {length x, y;} vector;

    length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible
    enough for it to work.

    The two types are entirely compatible.

    Are they?

    No, they are not. The type names 'Point' and 'vector' name two
    distinct types, and those types are not compatible, because
    the two struct tags are different.

    Because the two types are not compatible, even just calling the
    function dist() is undefined behavior.

    I get an incompatible error (from the example you snipped) even when I
    remove both struct tags.

    I can't use the same struct tag in the same scope as one will clash
    with the other. But if I have the second in an inner scope, then I
    again get the error.

    If you want to make a point or ask a question about C code,
    SHOW THE CODE. And show all of it. Don't make people guess
    by showing only some of the code or by giving just a description.

    I'm showing the code but you keep snipping it! [...]

    No, I don't. Don't be so obtuse. I included the code I was
    originally commenting on, in my first followup. My comment about
    showing code was about your second posting. Let me repeat the two
    important paragraphs (quoted above) taken from that posting:

    I get an incompatible error (from the example you snipped) even when I
    remove both struct tags.

    The phrase "even when I remove both struct tags" describes code, it
    doesn't show the code.

    I can't use the same struct tag in the same scope as one will clash
    with the other. But if I have the second in an inner scope, then I
    again get the error.

    The phrase "if I have the second in an inner scope" describes code,
    it doesn't show the code.

    And don't accuse me of something I haven't done.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Tim Rentsch on Wed Apr 9 01:02:29 2025
    On 09/04/2025 00:27, Tim Rentsch wrote:
    bart <bc@freeuk.com> writes:

    If you want to make a point or ask a question about C code,
    SHOW THE CODE. And show all of it. Don't make people guess
    by showing only some of the code or by giving just a description.

    I'm showing the code but you keep snipping it! [...]

    No, I don't. Don't be so obtuse. I included the code I was
    originally commenting on, in my first followup. My comment about
    showing code was about your second posting. Let me repeat the two
    important paragraphs (quoted above) taken from that posting:

    I get an incompatible error (from the example you snipped) even when I >>>> remove both struct tags.

    The phrase "even when I remove both struct tags" describes code, it
    doesn't show the code.

    I showed this example a few lines later which has both struct tags omitted:

    BC:
    Two typedefs for same struct layout appear to create distinct types;
    this fails:

    typedef struct {float x, y;} Point;
    typedef struct {float x, y;} vector;

    Point p;
    vector v;

    p=v;


    But before I get there, I say:

    I can't use the same struct tag in the same scope as one will clash with
    the other.

    That would be something like this:

    typedef struct tag {float x, y;} Point;
    typedef struct tag {float x, y;} vector;

    I suggested:


    But if I have the second in an inner scope, then I again get
    the error.

    That would be something like this where both 'struct tag' can co-exist:

    typedef struct tag {float x, y;} Point;
    {
    typedef struct tag {float x, y;} vector;
    ... rest of example that assigns v to p
    }



    You asserted that the incompabilities are due to the struct tags. I
    tried various tests but couldn't find any evidence for that. The structs
    are incompatible, even though they have identical layout, member names
    and structs, because they distinct, as demonstrated by the first example
    in this post. (That needs to be inside any function to see that error.)

    That makes sense to me, since different structs even with the same
    members could be intended for any number of unrelated purposes:

    typedef struct (float a, b, c;} rgbfloat;
    typedef struct (float a, b, c;} point;
    typedef struct (float a, b, c;} vector;
    typedef struct (float a, b, c;} circle;
    typedef struct (float a, b, c;} poly;

    You wouldn't want instances to these to be assigned to each other
    willy-nilly, or passed to functions expectong one of the other functions.

    Yes, you'd probably use better names, but AFAIK your choice of member
    names shouldn't play a part in determining compatibility.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Wed Apr 9 11:51:48 2025
    On Tue, 08 Apr 2025 10:59:50 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Mon, 07 Apr 2025 05:45:19 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 07:32:16 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 06 Apr 2025 05:47:47 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Furthermore, even if there had been a posting that concerns
    only a gcc extension and nothing else, and is one I didn't
    respond to, that doesn't excuse your action. It isn't like
    this is the first time you have posted something here that
    is not about C but only about your fantasy language, and
    also not the first time the unsuitability of such postings
    has been pointed out. You're a repeat offender. So stop
    pretending you are being picked on for no reason.

    Could you recommend a more appropriate place for Thiago and
    others where they can discuss C-like fantasy languages?

    The newsgroup comp.lang.misc seems like a natural candidate.
    I don't know if comp.lang.misc has an official charter, but at
    least to me new features of any widely used programming language
    would appear to fall under the umbrella of comp.lang.misc.

    My question was not completely abstract.
    I did consider starting a discussion about possibility of
    inclusion of stackless co-routines into one of the future
    editions of C. Naturally, my ideas at this state are extremely
    in-concrete, much more so then the post of Thiago Adams that
    started this thread. So, if I ever come to it, which by itself is
    not very likely, do you think that comp.lang.misc would be better
    place than comp.lang.c ?

    Before giving an answer I would like to ask some questions.

    * How much does the (still fuzzy) idea depend on running in a C
    environment? Is it very specific to C, or might it be applicable
    to other procedural/imperative languages (for example, Pascal)?

    * How much does the current C language impact what you expect to
    propose? Which aspects of C need to be taken into consideration
    in forming the proposal, and how strongly do those considerations
    affect the specifics of what would be proposed?

    [...]

    My apologies; I gave the wrong impression. I didn't mean I wanted
    to see the answers myself. What I did mean is that the questions
    are good for you (or someone else) to ask of themselves

    Even more interesting question to ask myself is why I want stackless
    coroutines in C to be different from how they were recently added to
    C++ and Rust - two languages that are relatively similar to C in their
    assumed execution models. Relatively, that is.

    to decide
    whether comp.lang.c or comp.lang.misc (or possibly some other group)
    is a better place for a posting.


    I took a look at comp.lang.misc.
    It does not appear to have much of the life of its own. Nearly all
    threads that lasted for more that 5 messages did so due to crossposts
    from other groups.

    Given that the details seem to be still a bit fuzzy, I tend to think comp.lang.misc is a better place to start. But after thinking about
    the questions you might decide otherwise.

    * Assuming you get to a point where you are happy with the details
    of a proposed extension, how likely is it that you would write a
    proposal for the C standard committee, and make the effort needed
    to shepherd it through the process of being accepted for a future
    C standard?

    Not likely. I would have to somehow convince somebody else to do
    it.

    I see. Well, good luck with that. :)

    I know that I would need it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ike Naar@21:1/5 to bart on Wed Apr 9 09:00:27 2025
    On 2025-04-08, bart <bc@freeuk.com> wrote:
    However if I need to initialise the variable:

    extern int table[]; // shared
    int table[] = (10, 20, 30)

    then other modules can't pick up length of the array.

    extern int table[3];

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Wed Apr 9 13:04:49 2025
    On Wed, 9 Apr 2025 11:42:36 +0200
    David Brown <david.brown@hesbynett.no> wrote:


    In C, if you declare two structs in the same translation unit with
    the same field types and the same field names, they are still
    different types.

    That is clear for structs with tags. Less clear for tagless structs
    that have exactly the same fields.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Wed Apr 9 13:11:24 2025
    On Wed, 9 Apr 2025 11:42:36 +0200
    David Brown <david.brown@hesbynett.no> wrote:


    This applies to all languages. For example, in Python you do not
    have separate "interface" and "implementation" files - everything is
    in one ".py" file. If I have a Python module that says "import
    my_py_lib", how does Python know where to find "my_py_lib.py" ? How
    does it know which copy of "my_py_lib.py" to use from the dozen that
    I have on my computer? The answer is it uses some default rules for
    the language, some default rules for the implementation, some
    configuration settings, some flags, some run-time information
    (equivalent to compile-time information in compiled languages). The
    exact details are different, but the principle is the same for C and
    for any other language that can handle more than one file.


    It is not quite the same for all languages. The degree in which it is standardizes vs left to implementation differs. In some languages it is
    fully standardized.
    I think, in case of Ada it was standardized in APSE. But then, real
    world mostly accepted a language part of Ada standard and mostly
    ignored APSE part.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Wed Apr 9 11:42:36 2025
    On 08/04/2025 18:28, bart wrote:
    On 08/04/2025 15:50, David Brown wrote:
    On 08/04/2025 13:35, bart wrote:

    But this need not be the case. For example this is module A:

    --------------------------
       #include <stdio.h>

       typedef struct point {float a; float b;} Point;

       float dist(Point);

       int main(void) {
           Point p = {3, 4};
           printf("%f\n", dist(p));
       }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
       #include <math.h>

       typedef float length;
       typedef struct _tag {length x, y;} vector;

       length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible enough
    for it to work.

    The two types are entirely compatible.


    Are they?

    Yes.

    So why does gcc report an error here (the two types are from
    my example):

      typedef struct point {float a; float b;} Point;

      typedef float length;
      typedef struct _tag {length x, y;} vector;

      Point p;
      vector v;

      p=v;

    c.c:14:5: error: incompatible types when assigning to type 'Point' {aka 'struct point'} from type
    ector' {aka 'struct _tag'}
       14 |   p=v;
          |     ^


    That is a different situation. In the first case, the types were
    defined in different translation units - and are compatible. In the
    second case, they are within the same translation unit, and are not
    compatible.

    In C, if you declare two structs in the same translation unit with the
    same field types and the same field names, they are still different
    types. That is important for making new types - it is how you get
    strong typing in C (albeit with less user convenience than in some other languages). It means that you can't mix up two types just because of coincidences in the fields.

    This means that when you have a struct declaration in two translation
    units (locally in the C file, or via a header file - there is no
    distinction), they form two different types as they are separate
    declarations. If C did not specify that these were compatible, it would
    be impossible (without UB) to use struct or union types across
    translation units.

    This is a situation where C's system is weaker than a solid module
    solution, but it works extremely well in practice - especially if
    developers follow the simple and common habit of putting shared type declarations in shared header files.


    "typedef" does not introduce a new type, and struct types in different
    modules are compatible if they are build from the same compatible
    field types in the same order.


    However, they could also be different enough (in a more elaborate
    example) for things to superficially work.

    Not in C.

    Really? I could have added a dozen extra fields to one (or a pile of incompatible fields to both), and it can still work (especially if I
    pass the struct by reference).

    The fact that something happens to work does not mean that it is defined behaviour in C.

    Of course it can be appropriate to write non-portable code that "just
    works". Making a pointer to one struct type, then using it as though it
    is a pointer to a different struct type like this is very likely to
    "just work" as long as you stay within the common part of the struct
    types. But there also may be circumstances in which it does /not/ "just
    work", or it might not work with other compilers or other options.


    The preprocessor mechanisms available to work with source code are
    fairly easy to grasp (but may be complex in practice with multiple
    nested headers spread over a file system).

    That's like complaining that integer addition is complex because
    someone might want to add 26 digit numbers.  Stop being silly.

    You're missing the point: the concept may be simple, but as typically
    used in C, it is can be much more complex than necessary.

    The C language is defined as explained in the standards. If someone
    writes C code that you think is more complex than necessary, talk to the
    person writing that code.

    Doing:

      #include "lib.h"

    is not enough; there may be a dozen different header locations (from
    nested includes) that need to be made known to the compiler, so you need
    to figure them out first!

    That is a question of build environment and build instructions. It
    applies to every programming language. Any time one file refers to
    another, you need some way to be sure you get exactly the file you intended.


    A program may comprise 100 .c files, but use 37 different headers in
    mixed, possible nested combinations across those 100 modules. You can't
    in general tie one .c file to a specific .h file; /that/ would be simpler.


    This applies to all languages. For example, in Python you do not have
    separate "interface" and "implementation" files - everything is in one
    ".py" file. If I have a Python module that says "import my_py_lib", how
    does Python know where to find "my_py_lib.py" ? How does it know which
    copy of "my_py_lib.py" to use from the dozen that I have on my computer?
    The answer is it uses some default rules for the language, some
    default rules for the implementation, some configuration settings, some
    flags, some run-time information (equivalent to compile-time information
    in compiled languages). The exact details are different, but the
    principle is the same for C and for any other language that can handle
    more than one file.

    So the usual thing applies in C: the language lays down some vague
    rules, beyond that it's a free-for-all.

    You choose to call that 'being flexible'; I might call it something else.



    But I had, and do still have, difficulty with how exactly you import
    and export entities, even ones with linkage.

    That sounds very much like a "Bart" problem.

    You really think that I wouldn't know how to do this if the language
    provided genuinely simple and well-thought-out and consistent rules?

    Apparently, that is the case. It does surprise me a little that you
    find this difficult - especially since you claim to have written a C
    compiler but don't seem to have read any of the language standards.



      If you /genuinely/ want to know, and you can't figure it out with a
    quick google search, reading the page in the standards, or looking at
    an introduction to C book, then please ask.  If you are just trying to
    claim opportunities to say it's all so difficult and confusing, then
    don't bother.

    Ah yes, the Microsoft approach: provide huge amounts of resources,
    manuals, training courses etc, rather than making something actually
    simple!

    It is /one/ **beeping** page in the standard! It is in /one/ section -
    section 6.2.2 - titled "Linkages of identifiers". Seven paragraphs,
    none of which are more than 5 lines long.



    How compilers deal with it have changed.

    As a general rule, they have not.

    But it is true that some compilers have by default supported an
    extension that was designed to make interoperability with Fortran
    programs easier

    Which means a pile of badly written programs.

    That is why I said it was a bad idea for gcc to have "-fcommon" as the
    default. It is a real shame that it took so long to change it.

    However, while that default meant that some people wrote C code with a misunderstanding of linkages and the difference between declarations and definitions, most C programmers don't make that mistake. When gcc
    eventually changed the default, it did not lead to wide-spread breakage
    of code.


    However if I need to initialise the variable:

        extern int table[];          // shared
        int table[] = (10, 20, 30)

    then other modules can't pick up length of the array.


    Correct.

    And the workaround is...?

    Learn how arrays work in C, and how you can pass around the length of an
    array between different functions or translation units.


    (Maybe you can appreciate one of many reasons why I normally generate C
    code for a project as one source file.)

    I can appreciate that you are the sort of person who, when finding a
    hole in their sock, would rather chop off their foot than go to the
    effort of buying a new pair.

    No one claims that C is the ideal language for all programming tasks or
    all programmers - if you would rather use a different language, that's
    fine. It's the petty griping and whining about things that are simple
    and clear that is so pathetic. You /know/ that C does not pass on the
    array size in the case you give above. You /know/ you have not shared
    that information with the second unit. You /know/ that no language lets
    one unit or module know information from a different unit or module if
    that information is not shared. And you know perfectly well how you can
    pass around the information in C when you need to.


    The C standard gives clear rules here that make sense.

    What's the rational for allowing both static and extern versions of the
    same entity in the same file? And if that is allowed, why does the order matter?

    I believe the meaning of "extern" in combination with other
    storage-class specifiers was picked to work with existing old code from
    before "extern" was added to the language.

    (You might not think this is a good reason, or prefer the rules to be
    different - that's fine. I would certainly prefer stricter rules, and
    use compiler warnings to enforce those preferences in order to reduce
    the risk of errors in my code.)


    (In my compiler I gave up trying to make sense of it, and just ended up
    allow any combination unless it was clearly wrong.)

    Again, it is /one/ page in the standard. It is not rocket science. The
    idea that a person could be smart enough to make their own compiler and
    not smart enough to understand the rules around linkage in C is utterly laughable. You have are intentionally misunderstanding this so that you
    can claim C is confusing or badly designed. This is deceitful behaviour.

    No one is asking you to /like/ the rules of C. No one is asking you to
    think they are ideal. Certainly no C programmer I know likes all of C's design, though they vary on what they like and dislike. But you are
    clearly wrong about these things being hard to understand.


      That does not
    mean they are the /only/ set of rules a language could have that makes
    sense, but they are not "ad hoc".  That would imply that combinations
    like this could have unpredictable meanings.

    I don't mean 'ad hoc' to be 'indeterminate'. More like, 'mess', or 'free-for-all'.


    You are still wrong.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Wed Apr 9 13:16:33 2025
    On Wed, 9 Apr 2025 11:42:36 +0200
    David Brown <david.brown@hesbynett.no> wrote:

    On 08/04/2025 18:28, bart wrote:
    On 08/04/2025 15:50, David Brown wrote:
    On 08/04/2025 13:35, bart wrote:
    But it is true that some compilers have by default supported an
    extension that was designed to make interoperability with Fortran
    programs easier

    Which means a pile of badly written programs.

    That is why I said it was a bad idea for gcc to have "-fcommon" as
    the default. It is a real shame that it took so long to change it.

    However, while that default meant that some people wrote C code with
    a misunderstanding of linkages and the difference between
    declarations and definitions, most C programmers don't make that
    mistake. When gcc eventually changed the default, it did not lead to wide-spread breakage of code.


    I wouldn't be so sure.
    I have no statistics, but would expect that very significant part of
    Unix-only C programmers, especially grumpy old timers, believes that
    '-fcommon' is the real C and the rest are heresies.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Wed Apr 9 11:51:37 2025
    On 09/04/2025 10:42, David Brown wrote:
    On 08/04/2025 18:28, bart wrote:
    On 08/04/2025 15:50, David Brown wrote:

    The two types are entirely compatible.


    Are they?

    Yes.

    So why does gcc report an error here (the two types are from my example):

       typedef struct point {float a; float b;} Point;

       typedef float length;
       typedef struct _tag {length x, y;} vector;

       Point p;
       vector v;

       p=v;

    c.c:14:5: error: incompatible types when assigning to type
    'Point' {aka 'struct point'} from type
    ector' {aka 'struct _tag'}
        14 |   p=v;
           |     ^


    That is a different situation.  In the first case, the types were
    defined in different translation units - and are compatible.  In the
    second case, they are within the same translation unit, and are not compatible.

    This doesn't make sense at all.

    Turning it around, you're saying that if T an U are incompatible types
    within the same translation unit, they suddenly become compatible if
    split across two translation units?


    In C, if you declare two structs in the same translation unit with the
    same field types and the same field names, they are still different
    types.  That is important for making new types - it is how you get
    strong typing in C (albeit with less user convenience than in some other languages).  It means that you can't mix up two types just because of coincidences in the fields.

    This means that when you have a struct declaration in two translation
    units (locally in the C file, or via a header file - there is no distinction), they form two different types as they are separate declarations.  If C did not specify that these were compatible, it would
    be impossible (without UB) to use struct or union types across
    translation units.

    So, yes, you are saying that. In short, if a programmer says that
    incompatible types T and U are the same (where the compiler can only see
    T in module A and U in module B), then the programmer must be trusted,
    even though they would be wrong.

    Note that I, as the programmer, said this:

    "The types involved are somewhat different, but are compatible enough
    for it to work."

    What you are saying is that even though I was actually telling the
    truth, I was wrong. But I would be right if I lied about it....

    We're either through the Looking-Glass at this point, or somewhere not
    in Kansas!

    I'll have to think about this before replying to any other points.

    You are still wrong.

    Never mind. I've just spotted this at the end. In that case, and given
    what you said above where you arguing that Black is White, discussion is futile.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Ike Naar on Wed Apr 9 11:36:18 2025
    On 09/04/2025 10:00, Ike Naar wrote:
    On 2025-04-08, bart <bc@freeuk.com> wrote:
    However if I need to initialise the variable:

    extern int table[]; // shared
    int table[] = (10, 20, 30)

    then other modules can't pick up length of the array.

    extern int table[3];

    That is not practical to do. If it was, you'd just write:

    int table[3] = (10, 20, 30)

    instead. But now you need to track the size of the data (it could be
    1000s of elements) and keep both bounds updated.

    The data can also include conditional elements that affect the total.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to David Brown on Wed Apr 9 12:58:08 2025
    On 09.04.2025 11:42, David Brown wrote:
    On 08/04/2025 18:28, bart wrote:
    [...]

    I believe the meaning of "extern" in combination with other
    storage-class specifiers was picked to work with existing old code from before "extern" was added to the language.

    Assuming you mean the "C" language I don't quite understand the last
    part of the sentence. Wasn't 'extern' already in "K&R" - so what was
    "the language" before the addition of 'extern'?

    Or did you just mean to say "[...] before _combinations_ of 'extern'
    and other storage-class specifier were added to the language."

    Janis, puzzled

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Janis Papanagnou on Wed Apr 9 14:23:03 2025
    On Wed, 9 Apr 2025 12:58:08 +0200
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    On 09.04.2025 11:42, David Brown wrote:
    On 08/04/2025 18:28, bart wrote:
    [...]

    I believe the meaning of "extern" in combination with other
    storage-class specifiers was picked to work with existing old code
    from before "extern" was added to the language.

    Assuming you mean the "C" language I don't quite understand the last
    part of the sentence. Wasn't 'extern' already in "K&R" - so what was
    "the language" before the addition of 'extern'?

    Or did you just mean to say "[...] before _combinations_ of 'extern'
    and other storage-class specifier were added to the language."

    Janis, puzzled


    K&R was published in 1978, 5 years after C got its first users.
    Back in 1973-74 C language was significantly different from what it
    became few years later.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Damon@21:1/5 to bart on Wed Apr 9 07:15:19 2025
    On 4/8/25 2:04 PM, bart wrote:
    On 08/04/2025 18:32, Tim Rentsch wrote:
    bart <bc@freeuk.com> writes:

    On 08/04/2025 15:50, David Brown wrote:

    On 08/04/2025 13:35, bart wrote:

    But this need not be the case.  For example this is module A:

    --------------------------
      #include <stdio.h>

      typedef struct point {float a; float b;} Point;

      float dist(Point);

      int main(void) {
      Point p = {3, 4};
      printf("%f\n", dist(p));
      }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
      #include <math.h>

      typedef float length;
      typedef struct _tag {length x, y;} vector;

      length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible
    enough for it to work.

    The two types are entirely compatible.

    Are they?

    No, they are not.  The type names 'Point' and 'vector' name two
    distinct types, and those types are not compatible, because
    the two struct tags are different.

    Because the two types are not compatible, even just calling the
    function dist() is undefined behavior.

    I get an incompatible error (from the example you snipped) even when I
    remove both struct tags.

    I can't use the same struct tag in the same scope as one will clash with
    the other. But if I have the second in an inner scope, then I again get
    the error.

    It doesn't seem to be anything to do with struct tags.

    Two typedefs for same struct layout appear to create distinct types;
    this fails:

      typedef struct {float x, y;} Point;
      typedef struct {float x, y;} vector;

      Point p;
      vector v;

      p=v;


    But this works:

      typedef struct {float x, y;} Point, vector;

      Point p;
      vector v;

      p=v;

    So it seems to depend on whether Point and vector share the same
    internal descriptor for the struct.

    In my original example, the structs were defined in separate translation unit, so the compiler has to take things on trust.


    I think the key point is that every time you define a struct with the
    struct keyword, it gets a "tag", if you don't provide it, it gets a
    private unnamable one, that is distinct. Thus you can't define a struct
    twice and get the exact same type, so every occurance of

    struct { float x, y; };

    will create a new type, so you can't use one in the place of another.

    The "Names" of types in C don't cross transition unit boundries, and it
    has a rule that two structs, with the same component by component
    definitions in two different translation units are compatible.

    So, in one C file you could have:

    typedef struct {float x, y; } Point;

    void fun(Point* p) { .... }


    and in another C file you could have:

    typedef struct { float x, y; } Vector;

    extern fun(Vector* v);

    Vector v;

    ...

    fun(&v);

    and have fully defined behavior, as the names of the type don't matter
    in C, just the memory layout.


    WITHIN a translation unit, you can't do that as names of types DO matter
    within a single translation unit,

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Wed Apr 9 14:06:45 2025
    On 09/04/2025 12:04, Michael S wrote:
    On Wed, 9 Apr 2025 11:42:36 +0200
    David Brown <david.brown@hesbynett.no> wrote:


    In C, if you declare two structs in the same translation unit with
    the same field types and the same field names, they are still
    different types.

    That is clear for structs with tags. Less clear for tagless structs
    that have exactly the same fields.


    (Note - I am referencing C11 here for personal convenience, but the
    section numbering and contents is, AFAIR, the same from C99 up to C17.
    C23 changed the numbering a bit.)

    6.7.2.1 "Structure and union specifiers" paragraph 8:

    """
    The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit.
    """


    So two tagless structs with the same fields declared, compatibility is
    the same as always - within a translation unit, they declare distinct incompatible new types, while across translation units they are compatible.




    6.2.7 "Compatible type and composite type" paragraph 1:

    """
    Two types have compatible type if their types are the same. Additional
    rules for determining whether two types are compatible are described in
    6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in 6.7.6
    for declarators. 55) Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and
    members satisfy the following requirements: If one is declared with a
    tag, the other shall be declared with the same tag. If both are
    completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of
    corresponding members are declared with compatible types;
    """

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Wed Apr 9 13:51:55 2025
    On 08/04/2025 20:04, bart wrote:
    On 08/04/2025 18:32, Tim Rentsch wrote:
    bart <bc@freeuk.com> writes:

    On 08/04/2025 15:50, David Brown wrote:

    On 08/04/2025 13:35, bart wrote:

    But this need not be the case.  For example this is module A:

    --------------------------
      #include <stdio.h>

      typedef struct point {float a; float b;} Point;

      float dist(Point);

      int main(void) {
      Point p = {3, 4};
      printf("%f\n", dist(p));
      }
    --------------------------

    And this is module B that defines 'dist':


    --------------------------
      #include <math.h>

      typedef float length;
      typedef struct _tag {length x, y;} vector;

      length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
    --------------------------

    The types involved are somewhat different, but are compatible
    enough for it to work.

    The two types are entirely compatible.

    Are they?

    No, they are not.  The type names 'Point' and 'vector' name two
    distinct types, and those types are not compatible, because
    the two struct tags are different.

    Because the two types are not compatible, even just calling the
    function dist() is undefined behavior.

    I get an incompatible error (from the example you snipped) even when I
    remove both struct tags.

    Of course. They are different types.


    I can't use the same struct tag in the same scope as one will clash with
    the other.

    Yes.

    But if I have the second in an inner scope, then I again get
    the error.

    Yes.


    It doesn't seem to be anything to do with struct tags.

    Correct.

    Every time you declare a struct - when you have "struct {" or "struct X
    {", you declare a /new/ type that is incompatible with any other type
    (except for inter-translation unit compatibility).


    Two typedefs for same struct layout appear to create distinct types;
    this fails:

    "typedef" does not create types - it merely creates an alias for an
    existing type. (Is it a questionable choice of keyword? Yes, it
    certainly is. So you have to learn what it means.) "struct"
    declarations (and "union" declarations) create types.


      typedef struct {float x, y;} Point;

    This creates a new anonymous type, then declares "Point" to be an alias
    for it.

      typedef struct {float x, y;} vector;

    This creates a new anonymous type, then declares "vector" to be an alias
    for it.

    "Point" and "vector" thus refer to different types.


      Point p;
      vector v;

      p=v;


    But this works:

      typedef struct {float x, y;} Point, vector;

    This creates a new anonymous type, then declares "Point" and "vector" to
    be aliases of it. They therefore refer to the same type.


      Point p;
      vector v;

      p=v;

    So it seems to depend on whether Point and vector share the same
    internal descriptor for the struct.


    It depends on whether they are declared as aliases for the same type, or
    for different types.

    In my original example, the structs were defined in separate translation unit, so the compiler has to take things on trust.


    Yes - as explained in 6.2.7p1 of the standard. Having them in separate translation units is critical to the difference.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Wed Apr 9 14:11:19 2025
    On 09/04/2025 12:11, Michael S wrote:
    On Wed, 9 Apr 2025 11:42:36 +0200
    David Brown <david.brown@hesbynett.no> wrote:


    This applies to all languages. For example, in Python you do not
    have separate "interface" and "implementation" files - everything is
    in one ".py" file. If I have a Python module that says "import
    my_py_lib", how does Python know where to find "my_py_lib.py" ? How
    does it know which copy of "my_py_lib.py" to use from the dozen that
    I have on my computer? The answer is it uses some default rules for
    the language, some default rules for the implementation, some
    configuration settings, some flags, some run-time information
    (equivalent to compile-time information in compiled languages). The
    exact details are different, but the principle is the same for C and
    for any other language that can handle more than one file.


    It is not quite the same for all languages. The degree in which it is standardizes vs left to implementation differs. In some languages it is
    fully standardized.
    I think, in case of Ada it was standardized in APSE. But then, real
    world mostly accepted a language part of Ada standard and mostly
    ignored APSE part.



    As I said, details vary, and some languages may specify more details
    than others. There are also differences in the relationship between a
    "module" of some sort that a unit might refer to, and the file or files
    that comprise that module. But the principle is that when one unit
    refers to another, the tools will have some way of figuring out which
    unit you are referring to, distinguishing it from other units or files
    on the same host system even if the filenames are the same. C does not
    differ in principle here from other languages. Bart seems to think C is somehow especially bad or complicated - he is wrong in that.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Wed Apr 9 14:36:15 2025
    On 09/04/2025 12:51, bart wrote:
    On 09/04/2025 10:42, David Brown wrote:
    On 08/04/2025 18:28, bart wrote:
    On 08/04/2025 15:50, David Brown wrote:

    The two types are entirely compatible.


    Are they?

    Yes.

    So why does gcc report an error here (the two types are from my
    example):

       typedef struct point {float a; float b;} Point;

       typedef float length;
       typedef struct _tag {length x, y;} vector;

       Point p;
       vector v;

       p=v;

    c.c:14:5: error: incompatible types when assigning to type 'Point'
    {aka 'struct point'} from type
    ector' {aka 'struct _tag'}
        14 |   p=v;
           |     ^


    That is a different situation.  In the first case, the types were
    defined in different translation units - and are compatible.  In the
    second case, they are within the same translation unit, and are not
    compatible.

    This doesn't make sense at all.

    Turning it around, you're saying that if T an U are incompatible types
    within the same translation unit, they suddenly become compatible if
    split across two translation units?


    In the specific case of structs and unions matching the requirements in
    6.2.7, yes. /Please/ read that section of the standard before making
    any more posts about it.

    There are plenty of differences between compiling two C files
    independently, and pasting them directly together in one file and
    compiling that. This is one of those differences.


    In C, if you declare two structs in the same translation unit with the
    same field types and the same field names, they are still different
    types.  That is important for making new types - it is how you get
    strong typing in C (albeit with less user convenience than in some
    other languages).  It means that you can't mix up two types just
    because of coincidences in the fields.

    This means that when you have a struct declaration in two translation
    units (locally in the C file, or via a header file - there is no
    distinction), they form two different types as they are separate
    declarations.  If C did not specify that these were compatible, it
    would be impossible (without UB) to use struct or union types across
    translation units.

    So, yes, you are saying that. In short, if a programmer says that incompatible types T and U are the same (where the compiler can only see
    T in module A and U in module B), then the programmer must be trusted,
    even though they would be wrong.


    Yes.

    Note that I, as the programmer, said this:

    "The types involved are somewhat different, but are compatible enough
    for it to work."


    It's not quite like that - C says that although they are different types
    (since they are in different translation units), they are compatible in
    this situation. Not "compatible enough to work", but /actually/
    compatible in the specific C technical sense. (Section 6.2.7 has
    "compatible type" in italics - it defines what is meant by that term in
    the C language.)


    What you are saying is that even though I was actually telling the
    truth, I was wrong. But I would be right if I lied about it....


    No, you were not telling the truth - you were wildly mixing things.

    We're either through the Looking-Glass at this point, or somewhere not
    in Kansas!

    I'll have to think about this before replying to any other points.

    Marvellous - I'd appreciate you putting more thought into this, and less knee-jerk reactions and exaggerations. Please also read the relevant
    parts of the standards before replying - at the very least, section
    6.2.7p1 and section 6.2.2. Once you have read these and tried to
    understand them, it will be a lot easier to clear up any remaining issues.


    You are still wrong.

    Never mind. I've just spotted this at the end. In that case, and given
    what you said above where you arguing that Black is White, discussion is futile.


    I believe there is still hope. But it does require you to read and think.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Ike Naar on Wed Apr 9 14:54:05 2025
    On 09/04/2025 11:00, Ike Naar wrote:
    On 2025-04-08, bart <bc@freeuk.com> wrote:
    However if I need to initialise the variable:

    extern int table[]; // shared
    int table[] = (10, 20, 30)

    then other modules can't pick up length of the array.

    extern int table[3];

    That is fine if you know the size in advance of initialisation. Very
    often, of course, you /do/ know the size - especially when talking about
    data shared directly between translation units. (And if it is not
    shared, you don't declare it in a header.)

    An array really needs two bits of information - a way to find the first element, and the number of elements. (There are also other bits of compile-time data such as the type.) In C, these two things are not
    tightly joined - you typically have to pass them separately when
    exchanging information about an array. This means you get maximal
    efficiency - you don't need to pass around information that you have no
    use of or know from somewhere else. But it also means you need a little
    extra effort in the code when you need them both.

    For example, you can have :

    // unit.h
    extern int table[];
    extern const int table_count;


    // unit.c
    #include "unit.h"

    int table = [10, 20, 30};
    const int table_count = sizeof(table) / sizeof(table[0]);

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Wed Apr 9 14:24:15 2025
    On 09/04/2025 12:16, Michael S wrote:
    On Wed, 9 Apr 2025 11:42:36 +0200
    David Brown <david.brown@hesbynett.no> wrote:

    On 08/04/2025 18:28, bart wrote:
    On 08/04/2025 15:50, David Brown wrote:
    On 08/04/2025 13:35, bart wrote:
    But it is true that some compilers have by default supported an
    extension that was designed to make interoperability with Fortran
    programs easier

    Which means a pile of badly written programs.

    That is why I said it was a bad idea for gcc to have "-fcommon" as
    the default. It is a real shame that it took so long to change it.

    However, while that default meant that some people wrote C code with
    a misunderstanding of linkages and the difference between
    declarations and definitions, most C programmers don't make that
    mistake. When gcc eventually changed the default, it did not lead to
    wide-spread breakage of code.


    I wouldn't be so sure.
    I have no statistics, but would expect that very significant part of Unix-only C programmers, especially grumpy old timers, believes that '-fcommon' is the real C and the rest are heresies.


    One of the tests the gcc folk (or other interested parties) do before
    releasing a new version of gcc is to do a complete rebuild of some Linux distributions - Debian, Red Hat Fedora, and perhaps others. This can
    lead to reversal of planned changes to default flags in gcc if there is significant breakage, or to changes in makefiles or build flags for some
    of the upstream packages if there are only a few packages affected. So
    a change of the defaults in gcc is a good indication that very few open
    source programs are affected by the change - few enough that changing
    the defaults is worth the effort fixing any conflicting packages.

    Of course even Debian does not contain /all/ *nix software, but it
    certainly covers a lot.

    I certainly have seen C code with things like "int x;" in header files,
    but it is not that common. After all, plenty of people will tell you
    how terrible "global variables" are, no matter how they are declared.

    A much more common bad style is to have file-scope variables declared as
    "int x;" inside a C file even though they were not intended to be
    externally linked - they should have been declared "static int x;".
    With "-fcommon", if you have coincidentally done that with the same
    identifier name in more than one translation unit, these will be merged
    - potentially leading to all kinds of "fun" bugs. With "-fno-common",
    you get a link-time error. This is why "-fno-common" is so important -
    it makes these code errors visible.


    But we have more than a few grumpy old timers in this newsgroup -
    perhaps some of them would like to chime in if they believe "-fcommon"
    is how C should be.

    (I may be grumpy, and I have grey in my beard and were sandals with
    socks, but I am not yet an "old timer" by the standards of this group -
    so my opinion doesn't count!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Wed Apr 9 14:13:02 2025
    On 09/04/2025 13:36, David Brown wrote:
    On 09/04/2025 12:51, bart wrote:
    On 09/04/2025 10:42, David Brown wrote:
    On 08/04/2025 18:28, bart wrote:
    On 08/04/2025 15:50, David Brown wrote:

    The two types are entirely compatible.


    Are they?

    Yes.

    So why does gcc report an error here (the two types are from my
    example):

       typedef struct point {float a; float b;} Point;

       typedef float length;
       typedef struct _tag {length x, y;} vector;

       Point p;
       vector v;

       p=v;

    c.c:14:5: error: incompatible types when assigning to type
    'Point' {aka 'struct point'} from type
    ector' {aka 'struct _tag'}
        14 |   p=v;
           |     ^


    That is a different situation.  In the first case, the types were
    defined in different translation units - and are compatible.  In the
    second case, they are within the same translation unit, and are not
    compatible.

    This doesn't make sense at all.

    Turning it around, you're saying that if T an U are incompatible types
    within the same translation unit, they suddenly become compatible if
    split across two translation units?


    In the specific case of structs and unions matching the requirements in 6.2.7, yes.  /Please/ read that section of the standard before making
    any more posts about it.

    There are plenty of differences between compiling two C files
    independently, and pasting them directly together in one file and
    compiling that.  This is one of those differences.


    In C, if you declare two structs in the same translation unit with
    the same field types and the same field names, they are still
    different types.  That is important for making new types - it is how
    you get strong typing in C (albeit with less user convenience than in
    some other languages).  It means that you can't mix up two types just
    because of coincidences in the fields.

    This means that when you have a struct declaration in two translation
    units (locally in the C file, or via a header file - there is no
    distinction), they form two different types as they are separate
    declarations.  If C did not specify that these were compatible, it
    would be impossible (without UB) to use struct or union types across
    translation units.

    So, yes, you are saying that. In short, if a programmer says that
    incompatible types T and U are the same (where the compiler can only
    see T in module A and U in module B), then the programmer must be
    trusted, even though they would be wrong.


    Yes.

    Note that I, as the programmer, said this:

    "The types involved are somewhat different, but are compatible enough
    for it to work."


    It's not quite like that - C says that although they are different types (since they are in different translation units), they are compatible in
    this situation.  Not "compatible enough to work", but /actually/
    compatible in the specific C technical sense.  (Section 6.2.7 has "compatible type" in italics - it defines what is meant by that term in
    the C language.)


    What you are saying is that even though I was actually telling the
    truth, I was wrong. But I would be right if I lied about it....


    No, you were not telling the truth - you were wildly mixing things.

    We're either through the Looking-Glass at this point, or somewhere not
    in Kansas!

    I'll have to think about this before replying to any other points.

    Marvellous - I'd appreciate you putting more thought into this, and less knee-jerk reactions and exaggerations.  Please also read the relevant
    parts of the standards before replying - at the very least, section
    6.2.7p1 and section 6.2.2.  Once you have read these and tried to
    understand them, it will be a lot easier to clear up any remaining issues.

    I'm not going to wade through reams of Standard minutiae, sorry.

    Are T and U compatible types are not? The answer must be unequivocal
    without needing to be a 'standards-head'. This has been said in this thread:


    BC: The types involved are somewhat different, but are compatible enough
    for it to work. [In that the member types, offsets and overall size,
    since pass-by-value is used, correspond]

    DB: The two types are entirely compatible.

    BC: Are they?

    TR: No, they are not.

    You say they're compatible, Tim Rentsch says they're not; who's right?


    The original point I'd been making was that, in C, there is no dedicated mechansism for sharing user-defined named entities like types, across
    modules.

    The user has to arrange for the compiler to see corresponding type
    declarations in each translation unit. This is error prone, and means
    that an RGBFLOAT struct can be used in place of a CIRCLE struct, and
    they will superficially work as each comprises three floats.

    But it would be an error in the program logic, one that cannot be picked
    up by the compiler.

    However you also state that RGBFLOAT and CIRCLE are compatible
    nonetheless. Even though, if you take the two modules are legally
    compiled before, and put refactor them into the same module, will now no
    longer compile.

    You seem to be saying that if this was an actual mistake on the part of
    the programmer, it's still actually fine as as far as the compiler and
    language is concerned (so we're still in Wonderland!)

    I notice you ignored the example in my language, many posts back, which
    makes it impossible to make such a mistake. That is how you fix such
    problems, not sending someone off to sweat through the 700 pages of C
    standard to prove some stupid point.

    So I still say they approach in C is ad hoc. (There are ways to mitigate
    that, but many come down to wrapping or superimposing a higher level
    language layer on top.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Wed Apr 9 16:00:57 2025
    On 09/04/2025 15:13, bart wrote:
    On 09/04/2025 13:36, David Brown wrote:
    On 09/04/2025 12:51, bart wrote:

    I'll have to think about this before replying to any other points.

    Marvellous - I'd appreciate you putting more thought into this, and
    less knee-jerk reactions and exaggerations.  Please also read the
    relevant parts of the standards before replying - at the very least,
    section 6.2.7p1 and section 6.2.2.  Once you have read these and tried
    to understand them, it will be a lot easier to clear up any remaining
    issues.

    I'm not going to wade through reams of Standard minutiae, sorry.

    Again, no one is suggesting that you read the entire C standard. After
    all, that would clearly be an absurd idea for someone who spends such a
    lot of his time arguing about the C language and who even claims to have
    made a C compiler.

    I have given you clear references to two small parts of the standard.
    It really is not a lot of effort.


    Are T and U compatible types are not? The answer must be unequivocal
    without needing to be a 'standards-head'.

    I have told you several times, for different variations of that "T" and
    "U" mean.

    Since you don't believe my explanations, and won't read the standards,
    I'm not sure how much more help I can be.

    This has been said in this
    thread:


    BC: The types involved are somewhat different, but are compatible enough
        for it to work. [In that the member types, offsets and overall size,
        since pass-by-value is used, correspond]

    DB: The two types are entirely compatible.

    BC: Are they?

    TR: No, they are not.

    You say they're compatible, Tim Rentsch says they're not; who's right?


    You have moved the goalposts around so often that it is hard to keep
    track. But Tim is correct - the names, when given, have to match as
    well as the types of the fields (but a typedef alias giving a different
    name to the same type is fine).


    The original point I'd been making was that, in C, there is no dedicated mechansism for sharing user-defined named entities like types, across modules.

    There /is/ a dedicated mechanism - described in 6.2.7p1.

    There is also a common way to handle this - using shared header files -
    that is almost universally adopted in C programming.

    It is not as strict as in some other languages, and is open to abuse -
    but you pretty much have to go out of your way to mix things up. Follow
    normal C programming methods, and you will have no more risk of mistakes
    here than in languages with more formal inter-unit interfacing.


    I notice you ignored the example in my language, many posts back, which
    makes it impossible to make such a mistake.

    Yes, I ignore your examples in your language - they have no bearing or relevance to anyone except you. We all know there are other ways for a language to implement inter-unit sharing of information. We all know
    that some of these can reduce the risk of certain errors. We all know
    that you have to follow a simple rule in order to negate that risk in C
    - put shared types in shared headers. No language negates all risks of
    errors - whatever language you use, you follow practices that balance
    the risk of errors with the convenience or flexibility that you want in
    the code.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Wed Apr 9 16:37:13 2025
    On 09/04/2025 15:00, David Brown wrote:
    On 09/04/2025 15:13, bart wrote:
    On 09/04/2025 13:36, David Brown wrote:
    On 09/04/2025 12:51, bart wrote:

    I'll have to think about this before replying to any other points.

    Marvellous - I'd appreciate you putting more thought into this, and
    less knee-jerk reactions and exaggerations.  Please also read the
    relevant parts of the standards before replying - at the very least,
    section 6.2.7p1 and section 6.2.2.  Once you have read these and
    tried to understand them, it will be a lot easier to clear up any
    remaining issues.

    I'm not going to wade through reams of Standard minutiae, sorry.

    Again, no one is suggesting that you read the entire C standard.  After
    all, that would clearly be an absurd idea for someone who spends such a
    lot of his time arguing about the C language and who even claims to have
    made a C compiler.

    I have given you clear references to two small parts of the standard. It really is not a lot of effort.


    Are T and U compatible types are not? The answer must be unequivocal
    without needing to be a 'standards-head'.

    I have told you several times, for different variations of that "T" and
    "U" mean.

    Since you don't believe my explanations, and won't read the standards,
    I'm not sure how much more help I can be.

    This has been said in this thread:


    BC: The types involved are somewhat different, but are compatible enough
         for it to work. [In that the member types, offsets and overall size,
         since pass-by-value is used, correspond]

    DB: The two types are entirely compatible.

    BC: Are they?

    TR: No, they are not.

    You say they're compatible, Tim Rentsch says they're not; who's right?


    You have moved the goalposts around

    Not really me.

    so often that it is hard to keep
    track.  But Tim is correct - the names, when given, have to match as
    well as the types of the fields (but a typedef alias giving a different
    name to the same type is fine).

    So who's right, you or Tim? Since you are saying contrary things.



    The original point I'd been making was that, in C, there is no
    dedicated mechansism for sharing user-defined named entities like
    types, across modules.

    There /is/ a dedicated mechanism - described in 6.2.7p1.

    According to that, then the 'Point' and 'vector' types in my original
    two-file example are not compatible, since they have different struct
    tags, plus they have different member names. But above you say they are 'entirely compatible'.

    Maybe it's /you/ who needs brush up on the Standard! I merely said they
    are compatible enough to my program to work, since at the machine level,
    this is merely two consecutive f32 types.

    BTW1 that paragraph doesn't say anything what 'pack()' setting is in
    force; that /has/ to be the same if otherwise different amounts of
    padding exist.

    BTW2 that doesn't really say anything about how to share named
    non-linkage entities across translation units.

    I notice you ignored the example in my language, many posts back,
    which makes it impossible to make such a mistake.

    Yes, I ignore your examples in your language - they have no bearing or relevance to anyone except you.

    You're welcome to post the same example in a more mainstream language.
    However most still seem to based around independent compilation. Many
    still require two parts to each shared resource: a definition, and a
    separate interface, with some mechanism needed to keep them in sync.

    My scheme only needs a definition for resources forming part of the same program. It also works for ALL named entities, not just those with
    'linkage'.

      We all know there are other ways for a
    language to implement inter-unit sharing of information.  We all know
    that some of these can reduce the risk of certain errors.  We all know
    that you have to follow a simple rule in order to negate that risk in C
    - put shared types in shared headers.

    If there was a 1:1 correspondence between a .c file and its .h, that
    would be great, but that rarely happens. In the LIBJPEG project for
    example, there are 76 .c files, and 12 .h files (but at least they are
    in the same folder).

    There are still risks: suppose a project uses include files in multiple locations made known to the compiler. It will follow an
    implementation-defined algorithm to search multiple paths for an include
    file. But if one accidentally gets deleted or renamed, if may pick up up
    an identically named file elsewhere. They may be similar enough to allow compilation to proceed, but now it is buggy.


      No language negates all risks of
    errors - whatever language you use, you follow practices that balance
    the risk of errors with the convenience or flexibility that you want in
    the code.


    The point is that C's scheme is 'ad hoc' with myriad (רבבה?) points of failure. You like to deny that. (Apparently if a compiler follows the
    same consistent set of rules, then it cannot be 'ad hoc'. But you can
    say this about any computer program; they are only following orders!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Wed Apr 9 12:50:25 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Wed, 9 Apr 2025 12:58:08 +0200
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    On 09.04.2025 11:42, David Brown wrote:

    On 08/04/2025 18:28, bart wrote:

    [...]

    I believe the meaning of "extern" in combination with other
    storage-class specifiers was picked to work with existing old code
    from before "extern" was added to the language.

    Assuming you mean the "C" language I don't quite understand the last
    part of the sentence. Wasn't 'extern' already in "K&R" - so what was
    "the language" before the addition of 'extern'?

    Or did you just mean to say "[...] before _combinations_ of 'extern'
    and other storage-class specifier were added to the language."

    Janis, puzzled

    K&R was published in 1978, 5 years after C got its first users.
    Back in 1973-74 C language was significantly different from what it
    became few years later.

    I haven't made any effort to verify this, but I would be
    surprised to learn that 'extern' was not part of C well
    before K&R.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Wed Apr 9 12:56:55 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 08 Apr 2025 10:59:50 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    [...]

    My apologies; I gave the wrong impression. I didn't mean I wanted
    to see the answers myself. What I did mean is that the questions
    are good for you (or someone else) to ask of themselves

    Even more interesting question to ask myself is why I want stackless coroutines in C to be different from how they were recently added to
    C++ and Rust - two languages that are relatively similar to C in their assumed execution models. Relatively, that is.

    It would be good to address that question in your postings.

    to decide
    whether comp.lang.c or comp.lang.misc (or possibly some other group)
    is a better place for a posting.

    I took a look at comp.lang.misc.
    It does not appear to have much of the life of its own. Nearly all
    threads that lasted for more that 5 messages did so due to crossposts
    from other groups.

    I look forward to seeing your ideas on stackless coroutines,
    in comp.lang.misc (and see if we can't up the participation).

    By the way, to my way of thinking longer threads doesn't
    necessarily imply a better result.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Wed Apr 9 15:07:38 2025
    bart <bc@freeuk.com> writes:

    On 09/04/2025 00:27, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    If you want to make a point or ask a question about C code,
    SHOW THE CODE. And show all of it. Don't make people guess
    by showing only some of the code or by giving just a description.

    I'm showing the code but you keep snipping it! [...]

    No, I don't. Don't be so obtuse. I included the code I was
    originally commenting on, in my first followup. My comment about
    showing code was about your second posting. Let me repeat the two
    important paragraphs (quoted above) taken from that posting:

    I get an incompatible error (from the example you snipped) even when I >>>>> remove both struct tags.

    The phrase "even when I remove both struct tags" describes code, it
    doesn't show the code.

    I showed this example a few lines later [in an earlier posting]
    which has both struct tags omitted:

    There is a simple lesson that you need to learn:

    When someone is responding to a post, they are responding ONLY to
    the content in the posting they are responing to; not to some
    earlier posting in the same thread, not to a different posting
    submitted two weeks ago, not to what you meant to say but didn't,
    not to thoughts in your head but that you didn't say, but ONLY TO
    WHAT IS SAID IN THE POSTING BEING RESPONDED TO.

    If you can learn to follow this simple rule everyone in the
    newsgroup will be better off, including you.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Tim Rentsch on Thu Apr 10 00:49:51 2025
    On 09/04/2025 23:07, Tim Rentsch wrote:
    bart <bc@freeuk.com> writes:

    On 09/04/2025 00:27, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    If you want to make a point or ask a question about C code,
    SHOW THE CODE. And show all of it. Don't make people guess
    by showing only some of the code or by giving just a description.

    I'm showing the code but you keep snipping it! [...]

    No, I don't. Don't be so obtuse. I included the code I was
    originally commenting on, in my first followup. My comment about
    showing code was about your second posting. Let me repeat the two
    important paragraphs (quoted above) taken from that posting:

    I get an incompatible error (from the example you snipped) even when I >>>>>> remove both struct tags.

    The phrase "even when I remove both struct tags" describes code, it
    doesn't show the code.

    I showed this example a few lines later [in an earlier posting]
    which has both struct tags omitted:

    There is a simple lesson that you need to learn:

    Please don't be patronising. We are not kids in your PL class.


    When someone is responding to a post, they are responding ONLY to
    the content in the posting they are responing to; not to some
    earlier posting in the same thread, not to a different posting
    submitted two weeks ago, not to what you meant to say but didn't,
    not to thoughts in your head but that you didn't say, but ONLY TO
    WHAT IS SAID IN THE POSTING BEING RESPONDED TO.

    If you can learn to follow this simple rule everyone in the
    newsgroup will be better off, including you.

    I'm not sure what your gripe is other than maybe I picked up on
    something you got wrong. The discussion was about two struct types like
    this:

    typedef struct tag1 {...} T1;
    typedef struct tag2 {...} T2;

    and whether T1 and T2 were compatible or not. You said:

    "and those types are not compatible, because the two struct tags are different."

    In this case the tags would be "tag1" and "tag2". I then said:

    "I get an incompatible error (from the example you snipped) even when I
    remove both struct tags."

    That means removing "tag1" and "tag2" so the example above looks like this:

    typedef struct {...} T1;
    typedef struct {...} T2;

    Here, you can't say the struct tags are different, as they are not
    visible! Maybe there are internal ones that differ, but that is not
    obvious. What /can/ be seen from the source is two distinct types.

    But it seems you've lost interest in that, and are berating me for not illustrating what:

    typedef struct tag1 {...} T1;
    typedef struct tag2 {...} T2;

    might look like with "both tags removed". I think you also wanted me to illustrate what it might look like when both have the same tag, after I
    said they would clash in both in same scope. That is, you wanted an
    example like this:

    typedef struct tag1 {...} T1;
    {typedef struct tag1 {...} T2; ... }

    (This one was interesting to me (obviously no longer to you) because the
    tags are now clearly identical, yet T1/T2 are still incompatible.

    As I concluded, your assertion about compatibility being based on tags
    being the same or not didn't seem right.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Thu Apr 10 00:20:29 2025
    On 2025-04-09, bart <bc@freeuk.com> wrote:
    I'm not sure what your gripe is other than maybe I picked up on
    something you got wrong. The discussion was about two struct types like
    this:

    typedef struct tag1 {...} T1;
    typedef struct tag2 {...} T2;

    and whether T1 and T2 were compatible or not. You said:

    "and those types are not compatible, because the two struct tags are different."

    In this case the tags would be "tag1" and "tag2". I then said:

    "I get an incompatible error (from the example you snipped) even when I remove both struct tags."

    When you remove the tag from a struct definition, the implementation
    behaves as if it were implementing a unique tag which is different
    from any other such tag, and any tag that can possibly be written
    using textual syntax.

    How did you implement tagless struct declarations in your compiler?

    That means removing "tag1" and "tag2" so the example above looks like this:

    typedef struct {...} T1;
    typedef struct {...} T2;

    Here, you can't say the struct tags are different, as they are not
    visible!

    So if you close your eyes, two things that were different are now
    no longer different, since they are invisible?

    The tag is a property of the type, not of printed type declaration.

    A struct type has a tag. If the declaration doesn't show one,
    that doesn't mean it doesn't have a tag.

    If a "Simulation" object has a "gravity" member, do you conclude
    that a given simulation has no gravity, because the constructor
    omitted specifying it?

    Simulation s = new Simulation(windSpeed = 35.7)

    As I concluded, your assertion about compatibility being based on tags
    being the same or not didn't seem right.)

    Or, you know, you could stop caring about what someone wrote in
    comp.lang.c, be they right or wrong, and ... look it up?

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Keith Thompson on Thu Apr 10 11:55:01 2025
    On Wed, 09 Apr 2025 14:44:39 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 9 Apr 2025 12:58:08 +0200
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    On 09.04.2025 11:42, David Brown wrote:
    On 08/04/2025 18:28, bart wrote:
    [...]

    I believe the meaning of "extern" in combination with other
    storage-class specifiers was picked to work with existing old
    code from before "extern" was added to the language.

    Assuming you mean the "C" language I don't quite understand the
    last part of the sentence. Wasn't 'extern' already in "K&R" - so
    what was "the language" before the addition of 'extern'?

    Or did you just mean to say "[...] before _combinations_ of
    'extern' and other storage-class specifier were added to the
    language."

    Janis, puzzled

    K&R was published in 1978, 5 years after C got its first users.
    Back in 1973-74 C language was significantly different from what it
    became few years later.

    The earliest C reference I have is cman74.pdf, currently at <http://cm.bell-labs.co/who/dmr/cman74.pdf>. It includes "extern" in
    the list of keywords.

    It was inherited from B, which had "extrn" as a keyword as of 1972.


    O.k. Then David Brown will have to look for different justification for
    this particular misfeature of great majority of Unix implementations of
    C language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Kaz Kylheku on Thu Apr 10 12:08:31 2025
    On Thu, 10 Apr 2025 00:20:29 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wrote:

    On 2025-04-09, bart <bc@freeuk.com> wrote:
    I'm not sure what your gripe is other than maybe I picked up on
    something you got wrong. The discussion was about two struct types
    like this:

    typedef struct tag1 {...} T1;
    typedef struct tag2 {...} T2;

    and whether T1 and T2 were compatible or not. You said:

    "and those types are not compatible, because the two struct tags
    are different."

    In this case the tags would be "tag1" and "tag2". I then said:

    "I get an incompatible error (from the example you snipped) even
    when I remove both struct tags."

    When you remove the tag from a struct definition, the implementation
    behaves as if it were implementing a unique tag which is different
    from any other such tag, and any tag that can possibly be written
    using textual syntax.

    How did you implement tagless struct declarations in your compiler?

    That means removing "tag1" and "tag2" so the example above looks
    like this:

    typedef struct {...} T1;
    typedef struct {...} T2;

    Here, you can't say the struct tags are different, as they are not
    visible!

    So if you close your eyes, two things that were different are now
    no longer different, since they are invisible?

    The tag is a property of the type, not of printed type declaration.

    A struct type has a tag. If the declaration doesn't show one,
    that doesn't mean it doesn't have a tag.


    In the message above Bart demonstrated that type of struct with
    explicit tag depends not just on tag and fields, but also on
    lexical scope.
    IMHO, instead of going into irrelevant details, it is much simpler to
    postulate that all struct declarations within given translation unit
    have different types. Upthread, somebody said that already. May be, you.


    If a "Simulation" object has a "gravity" member, do you conclude
    that a given simulation has no gravity, because the constructor
    omitted specifying it?

    Simulation s = new Simulation(windSpeed = 35.7)


    I am not quite understand how C++ is relevant.

    As I concluded, your assertion about compatibility being based on
    tags being the same or not didn't seem right.)

    Or, you know, you could stop caring about what someone wrote in
    comp.lang.c, be they right or wrong, and ... look it up?


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Thu Apr 10 12:00:03 2025
    On 10/04/2025 01:20, Kaz Kylheku wrote:
    On 2025-04-09, bart <bc@freeuk.com> wrote:
    I'm not sure what your gripe is other than maybe I picked up on
    something you got wrong. The discussion was about two struct types like
    this:

    typedef struct tag1 {...} T1;
    typedef struct tag2 {...} T2;

    and whether T1 and T2 were compatible or not. You said:

    "and those types are not compatible, because the two struct tags are
    different."

    In this case the tags would be "tag1" and "tag2". I then said:

    "I get an incompatible error (from the example you snipped) even when I
    remove both struct tags."

    When you remove the tag from a struct definition, the implementation
    behaves as if it were implementing a unique tag which is different
    from any other such tag, and any tag that can possibly be written
    using textual syntax.

    How did you implement tagless struct declarations in your compiler?

    That means removing "tag1" and "tag2" so the example above looks like this: >>
    typedef struct {...} T1;
    typedef struct {...} T2;

    Here, you can't say the struct tags are different, as they are not
    visible!

    So if you close your eyes, two things that were different are now
    no longer different, since they are invisible?

    The tag is a property of the type, not of printed type declaration.

    Someone, not anyone but the all-knowing Tim, said: "and those types are
    not compatible, because the two struct tags are different."

    Do you agree with that? Or is there something more to making two types
    be incompatible?

    My examples included ones where tags /were/ different; tags which were identical (in nested scopes) and tags which were missing.

    My view is that even if type discrimination was 100% dependent on tags,
    then it would be poor to rely on something which can be invisible in
    source code (either tags don't exist, or they appear identical).



    A struct type has a tag. If the declaration doesn't show one,
    that doesn't mean it doesn't have a tag.

    If a "Simulation" object has a "gravity" member, do you conclude
    that a given simulation has no gravity, because the constructor
    omitted specifying it?

    Simulation s = new Simulation(windSpeed = 35.7)

    This is quite irrelevant, since 'gravity' will be defined somewhere in
    the source code, but you are talking about some internal attribute that
    may or may not be used by an implementation.

    As I concluded, your assertion about compatibility being based on tags
    being the same or not didn't seem right.)

    Or, you know, you could stop caring about what someone wrote in
    comp.lang.c, be they right or wrong, and ... look it up?

    Why don't you just tell me?

    In my C compiler, each type has a unique index which is what is compared
    to see if two types are the same type. It has nothing to do with tags.

    This C code:

    struct {int x;};
    struct {int x;};
    struct Tag {int x;};
    {struct Tag {int x;};}

    Produces these 4 distinct types, with indices 23-26:

    23 struct (i32 x)
    Name: struct $T1
    Def: 03C24580 $T1.1 # .1 etc is a block scope index

    24 struct (i32 x)
    Name: struct $T2
    Def: 03C246C0 $T2.1

    25 struct (i32 x)
    Name: struct Tag
    Def: 03C247F0 Tag.1

    26 struct (i32 x)
    Name: struct Tag
    Def: 038D2910 Tag.2

    The types without tags will have an internal tag supplied, since each
    user type is required to have an ST entry. But it is the 23/24/25/26
    that is used in the type system to discriminate between them.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Thu Apr 10 14:46:00 2025
    On 10/04/2025 10:55, Michael S wrote:
    On Wed, 09 Apr 2025 14:44:39 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 9 Apr 2025 12:58:08 +0200
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    On 09.04.2025 11:42, David Brown wrote:
    On 08/04/2025 18:28, bart wrote:
    [...]

    I believe the meaning of "extern" in combination with other
    storage-class specifiers was picked to work with existing old
    code from before "extern" was added to the language.

    Assuming you mean the "C" language I don't quite understand the
    last part of the sentence. Wasn't 'extern' already in "K&R" - so
    what was "the language" before the addition of 'extern'?

    Or did you just mean to say "[...] before _combinations_ of
    'extern' and other storage-class specifier were added to the
    language."

    Janis, puzzled

    K&R was published in 1978, 5 years after C got its first users.
    Back in 1973-74 C language was significantly different from what it
    became few years later.

    The earliest C reference I have is cman74.pdf, currently at
    <http://cm.bell-labs.co/who/dmr/cman74.pdf>. It includes "extern" in
    the list of keywords.

    It was inherited from B, which had "extrn" as a keyword as of 1972.


    O.k. Then David Brown will have to look for different justification for
    this particular misfeature of great majority of Unix implementations of
    C language.


    There have been a variety of things under discussion here, but I think
    this particular one was about the linkage rules in C if an identifier is declared with "static int foo;" and/or "extern int foo;" and/or "int
    foo;" at file scope, possibly in different orders. My thought was that
    one influence on the rules was consistency of existing code after
    "extern" was added to the language, but it seems unlikely since no one
    knows of an early C without "extern".

    So currently, I have no explanation for why you may write "static int
    foo; extern int foo;" and have "foo" be internal linkage, while "extern
    int foo; static int foo;" is not allowed. Given that neither are likely
    to be of the remotest use, nor likely to be written by accident and go unnoticed, it should not affect anyone significantly.

    But if someone else has an explanation for this, or a realistic use-case
    for static followed by extern, I am curious to hear about it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Thu Apr 10 14:34:49 2025
    On 10/04/2025 12:28, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Someone, not anyone but the all-knowing Tim, said: "and those types
    are not compatible, because the two struct tags are different."

    Do you agree with that? Or is there something more to making two types
    be incompatible?

    I don't recall the exact discussion

    It stems from this, a reply from DB dated: "Tue, 8 Apr 2025 16:50:56
    +0200". (About half way down there is some quoted code of mine.)

    It concerned two struct types in different translations units, which
    needed to be compatible for the test program to work corectly.

    I said they were compatible enough. David said they were entirely
    compatible. Tim said "No they are not". Three different opinions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to David Brown on Thu Apr 10 15:41:50 2025
    On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
    So currently, I have no explanation for why you may write "static int
    foo; extern int foo;" and have "foo" be internal linkage, while "extern
    int foo; static int foo;" is not allowed.

    What's also not allowed is "static int foo; int foo;" !

    It's because "extern" means "refer to the existing file scope
    declaration of the identifer if there is one propagating its
    properties, including linkage; otherwise if it doesn't exist,
    create an external linkage reference"

    You can use extern in a scope:

    ...
    {
    {
    extern int putchar(void);

    ...

    Even if the function has internal linkage, you must still use
    extern.

    static void foo(void);

    void bar(void)
    {
    static int foo(void); // wrong: must be extern

    If the "extern" keyword were called "filescope", it would be better
    reflect its action of referring to a filescope declaration of the
    identifier, assumed to have external linkage if it the declaration
    doesn't already exist.

    Also note how extern has the property of suppressing a definition.

    In a header file, for an object, we usually don't want:

    int obj;

    because that is a tentative definition, which will convert to a
    definition at the end of each translation unit which includes it. If we
    put in extern, it's no longer a tentative definition, but only a
    declaration. (Unless there is an initializer.)

    But if someone else has an explanation for this, or a realistic use-case
    for static followed by extern, I am curious to hear about it.

    The only thing I can think of is to skip around shadowing:

    static int x(void);

    ...
    {
    int x; // shadowing identifier

    {
    extern int x(void); // "unshadowing"

    Macro-generated code could use this to make sure its references
    are not shadowed.

    However, if the macro interpolates argument expressions supplied
    by the use site, and those expressions expect to refer to "x",
    then it won't work. Hygiene has not been achieved.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Thu Apr 10 16:51:27 2025
    On 2025-04-10, bart <bc@freeuk.com> wrote:
    On 10/04/2025 01:20, Kaz Kylheku wrote:
    On 2025-04-09, bart <bc@freeuk.com> wrote:
    I'm not sure what your gripe is other than maybe I picked up on
    something you got wrong. The discussion was about two struct types like
    this:

    typedef struct tag1 {...} T1;
    typedef struct tag2 {...} T2;

    and whether T1 and T2 were compatible or not. You said:

    "and those types are not compatible, because the two struct tags are
    different."

    In this case the tags would be "tag1" and "tag2". I then said:

    "I get an incompatible error (from the example you snipped) even when I
    remove both struct tags."

    When you remove the tag from a struct definition, the implementation
    behaves as if it were implementing a unique tag which is different
    from any other such tag, and any tag that can possibly be written
    using textual syntax.

    How did you implement tagless struct declarations in your compiler?

    That means removing "tag1" and "tag2" so the example above looks like this: >>>
    typedef struct {...} T1;
    typedef struct {...} T2;

    Here, you can't say the struct tags are different, as they are not
    visible!

    So if you close your eyes, two things that were different are now
    no longer different, since they are invisible?

    The tag is a property of the type, not of printed type declaration.

    Someone, not anyone but the all-knowing Tim, said: "and those types are
    not compatible, because the two struct tags are different."

    That is true. If we know that two struct types have tags obtained
    from the source code declaration, and those tags are different,
    they are necessarily incompatible types, regardless of whether
    they are in the same translation unit or different ones.

    Do you agree with that? Or is there something more to making two types
    be incompatible?

    Tim: two fingerprints from the left hand index finger are from different
    humans if they are different.

    You: do you agree with this, or is there more that can make
    two humans different?

    Struct compatibility is determined by tag and content.

    My examples included ones where tags /were/ different; tags which were identical (in nested scopes) and tags which were missing.

    tags which are identical do not speak to the situation of tags not
    being identical.

    My view is that even if type discrimination was 100% dependent on tags,

    Given the logical statement P and Q would you say that it its
    truth is 50% dependent on P and 50% on Q?

    I would say that it's 100% dependent on P, and 100% on Q. :)

    source code (either tags don't exist, or they appear identical).

    A struct type has a tag. If the declaration doesn't show one,
    that doesn't mean it doesn't have a tag.

    If a "Simulation" object has a "gravity" member, do you conclude
    that a given simulation has no gravity, because the constructor
    omitted specifying it?

    Simulation s = new Simulation(windSpeed = 35.7)

    This is quite irrelevant, since 'gravity' will be defined somewhere in
    the source code, but you are talking about some internal attribute that
    may or may not be used by an implementation.

    It's completely relevant to the problem of pretending that there is
    no gravity just because it doesn't appear in the construction
    syntax.


    As I concluded, your assertion about compatibility being based on tags
    being the same or not didn't seem right.)

    Or, you know, you could stop caring about what someone wrote in
    comp.lang.c, be they right or wrong, and ... look it up?

    Why don't you just tell me?

    Because then you're still caring about what someone wrote in
    comp.lang.c, which could be unreliable.

    In my C compiler, each type has a unique index which is what is compared
    to see if two types are the same type. It has nothing to do with tags.

    How can it not?

    struct tag;
    struct tag { ... };

    these have to refer to the same type; how do you do that without tags?


    This C code:

    struct {int x;};
    struct {int x;};
    struct Tag {int x;};
    {struct Tag {int x;};}

    Produces these 4 distinct types, with indices 23-26:

    This is correct; but if the defining body were omitted from the fourth
    one, it would have to refer to the previous declaration upscope by tag matching.

    In separate lexical scopes, we can have structs that are completely
    different (different shape) and have the same tag.

    As far as different translation units go, there are rules. But most implementations of C operate on faith: implementations see only
    the type declarations in one translation unit being processed.
    It is trusted that cross-translation-unit uses of types are compatible.

    In most C implementations, there is /de facto/ structural compatibility
    in that two structures in separate units can have different tags,
    and different member names, used to alias the same object, will not
    cause any problem. The ISO C rules are stricter. The tags have
    to be the same as well as the names of corresponding struct members
    that have names.

    Additionally, there is this rule: two structs defined in separate
    translation units, each without a tag, but otherwise the same
    (same member names in same order, same types, alignment, ...)
    are compatible! This is even though they would not be compatible
    if they appeared in the same translation unit.
    This is something that will Just Work in implementations that don't care
    about tags across translation units.

    Another rule, much more obvious, is that if a struct in one translation
    unit is incomplete, and complete in another translation unit, and they
    have the same tag, then they are compatible. Obviously this is
    exploited in every program that uses incomplete structs in header files
    for opaque types.


    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Michael S on Thu Apr 10 16:23:58 2025
    On 2025-04-10, Michael S <already5chosen@yahoo.com> wrote:
    In the message above Bart demonstrated that type of struct with
    explicit tag depends not just on tag and fields, but also on
    lexical scope.

    In C, you cannot get the same type into two disjoint lexical
    scope, unless they come from a common parent lexical scope.

    The question simply does not arise:

    {
    struct foo { ... } x;

    }

    {
    struct foo { ... } x;

    }

    If there is no previous declaration of "struct foo", these two structs
    are in different universes; neither type is known outside of the
    scope bubble in which it is defined.

    No situation can arise in in which we would have to consider whether
    the types are compatible.

    Yes, struct tags are introduced into lexical scopes, and tags
    introduced in different scopes are not related.

    IMHO, instead of going into irrelevant details, it is much simpler to postulate that all struct declarations within given translation unit
    have different types.

    No, because struct declarations can refer to existing previous
    declarations by tag name.

    These two are not different types:

    struct foo;
    struct foo { int x; };

    We can probably say this: all occurrences of the "body braces"
    of a struct definition are attached to distinct struct types,
    in a program that requires no diagnostics.


    If a "Simulation" object has a "gravity" member, do you conclude
    that a given simulation has no gravity, because the constructor
    omitted specifying it?

    Simulation s = new Simulation(windSpeed = 35.7)


    I am not quite understand how C++ is relevant.

    That is pseudo-code, not C++. The purpose is to talk about the
    difference between the syntax which creates an entity, and
    the entity itself.

    Are you an LLM?

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Kaz Kylheku on Thu Apr 10 18:31:55 2025
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-10, bart <bc@freeuk.com> wrote:

    As far as different translation units go, there are rules. But most >implementations of C operate on faith: implementations see only
    the type declarations in one translation unit being processed.
    It is trusted that cross-translation-unit uses of types are compatible.

    And when they're not compatible, it can take _days_ to find the
    bug. I was once called in to debug a random SIGSEGV in a large
    crypto application (generated X.509 site certificates for most of the
    world at the time). Turned out that different components of the
    the application were linked against different versions of the crypto
    library (a proprietary predecessor to openssl).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Thu Apr 10 19:36:21 2025
    On 10/04/2025 17:51, Kaz Kylheku wrote:
    On 2025-04-10, bart <bc@freeuk.com> wrote:

    Do you agree with that? Or is there something more to making two types
    be incompatible?

    Tim: two fingerprints from the left hand index finger are from different humans if they are different.

    You: do you agree with this, or is there more that can make
    two humans different?

    Struct compatibility is determined by tag and content.

    This is more nuanced. There is two structs being the same type or not,
    which a compiler can determine if they are in the same translation unit;
    no need to analyse tags or anything to figure that out, it's either the
    exact same type or not.

    And there is two structs in two translation units which have separate definitions, which the compiler cannot compare, and which have to be
    compatible for the program to be valid. But the compiler cannot check that.

    The example was like this:

    module A: typedef struct point {float a; float b;} Point;

    module B: typedef float length;
    typedef struct _tag {length x, y;} vector;

    David Brown said: "The two types are entirely compatible."

    I said: "Are they?"

    Tim Rentsch said: "No, they are not."

    So DB and TR are disagreeing, but everyone is ignoring the fact that one
    of them is likely wrong, and sending /me/ off to read the standard!

    TR went on to say: "The type names 'Point' and 'vector' name two
    distinct types, and those types are not compatible, because
    the two struct tags are different."

    That does rather sound like it is the tags that are the sole deciding
    factor, which is when I started doing experiments.

    ATEOTD, to share such a type across two or more translation units, means
    each one seeing its own definition of it. Nothing stops you having
    somewhat different versions of it, as I had above, so this part has to
    be taken on trust. This was part of my broader point that sharing
    non-linkage named entities across modules in C was ad hoc.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Kaz Kylheku on Thu Apr 10 21:05:41 2025
    On 10/04/2025 17:41, Kaz Kylheku wrote:
    On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
    So currently, I have no explanation for why you may write "static int
    foo; extern int foo;" and have "foo" be internal linkage, while "extern
    int foo; static int foo;" is not allowed.

    What's also not allowed is "static int foo; int foo;" !

    It's because "extern" means "refer to the existing file scope
    declaration of the identifer if there is one propagating its
    properties, including linkage; otherwise if it doesn't exist,
    create an external linkage reference"


    That's a summary of how "extern" works, but it results in a kind of
    circular argument or tautology - it's just saying "extern means what it
    means". It does not explain /why/ it works this way, or where the rules
    came from, why C has use of a single keyword that works this way, and
    why it is called "extern".

    It would be much simpler if we had "static int x;" to mean "declare x
    with internal linkage and define it", "extern int x;" to mean "declare x
    to have extern linkage", and "int x;" to mean "declare x with external
    linkage and define it". That is how you use these in most circumstances
    (and there are gcc warning flags to enforce it, for those that want to
    do that).

    C rarely makes things more complicated without a good reason. You gave
    the example of using "extern" for "unshadowing" an identifier (thank you
    for that example!), but it doesn't strike me as sufficient
    justification. I had thought the reason for the way "extern" and
    "static" interact was historical compatibility, but that does not appear
    to be the case.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Thu Apr 10 20:11:01 2025
    On 10/04/2025 17:51, Kaz Kylheku wrote:
    On 2025-04-10, bart <bc@freeuk.com> wrote:

    In my C compiler, each type has a unique index which is what is compared
    to see if two types are the same type. It has nothing to do with tags.

    How can it not?

    struct tag;
    struct tag { ... };

    these have to refer to the same type; how do you do that without tags?

    The type can be denoted in the source code using 'struct tag'. Looking
    'tag' up in the ST, checking only names belonging to the special tag
    namespace, will yield an entry that has its type index, whatever that
    happens to be.

    But the tag is not what is used when comparing two types. It is just an anachronistic concept that C still needs.

    (In C++ I understand that special tag namespaces don't exist, they are
    just part of the normal namespace.

    And in my languages they have never been a concept, yet I can still
    compare one struct type with another.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Scott Lurndal on Thu Apr 10 19:14:20 2025
    On 2025-04-10, Scott Lurndal <scott@slp53.sl.home> wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-10, bart <bc@freeuk.com> wrote:

    As far as different translation units go, there are rules. But most >>implementations of C operate on faith: implementations see only
    the type declarations in one translation unit being processed.
    It is trusted that cross-translation-unit uses of types are compatible.

    And when they're not compatible, it can take _days_ to find the
    bug. I was once called in to debug a random SIGSEGV in a large
    crypto application (generated X.509 site certificates for most of the
    world at the time). Turned out that different components of the
    the application were linked against different versions of the crypto
    library (a proprietary predecessor to openssl).

    OpenSSL's libcrypto libcrypto doesn't do any symbol versioning, allowing
    old binary clients to link to the latest versions of its functions that
    require different structures. It's completely bonkers.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to David Brown on Thu Apr 10 15:14:36 2025
    On 4/10/25 08:46, David Brown wrote:
    ...
    There have been a variety of things under discussion here, but I think
    this particular one was about the linkage rules in C if an identifier is declared with "static int foo;" and/or "extern int foo;" and/or "int
    foo;" at file scope, possibly in different orders. My thought was that
    one influence on the rules was consistency of existing code after
    "extern" was added to the language, but it seems unlikely since no one
    knows of an early C without "extern".

    So currently, I have no explanation for why you may write "static int
    foo; extern int foo;" and have "foo" be internal linkage, while "extern
    int foo; static int foo;" is not allowed. Given that neither are likely
    to be of the remotest use, nor likely to be written by accident and go unnoticed, it should not affect anyone significantly.

    But if someone else has an explanation for this, or a realistic use-case
    for static followed by extern, I am curious to hear about it.

    According to the C89 Rationale
    "The Standard requires that the first declaration, implicit or explicit,
    of an identifier specify (by the presence or absence of the keyword
    static) whether the identifier has internal or external linkage. This requirement allows for one-pass compilation in an implementation which
    must treat internal linkage items differently than external linkage
    items. An example of such an implementation is one which produces
    intermediate assembler code, and which therefore must construct names
    for internal linkage items to circumvent identifier length and/or case restrictions in the target assembler.
    The definition model to be used for objects with external linkage was a
    major standardization issue. The basic problem was to decide which
    declarations of an object define storage for the object, and which
    merely reference an existing object.
    A related problem was whether multiple definitions of storage are
    allowed, or only one is acceptable. Existing implementations of C
    exhibit at least four different models, listed here in order of
    increasing restrictiveness:
    *Common* Every object declaration with external linkage (whether or not
    the keyword extern appears in the declaration) creates a definition of
    storage. When all of the modules are combined together, each definition
    with the same name is located at the same address in memory. (The name
    is derived from common storage in FORTRAN.) This model was the intent of
    the original designer of C, Dennis Ritchie.
    *Relaxed Ref/Def* The appearance of the keyword extern (whether it is
    used outside of the scope of a function or not) in a declaration
    indicates a pure reference (ref), which does not define storage.
    Somewhere in all of the translation units, at least one definition (def)
    of the object must exist. An external definition is indicated by an
    object declaration in file scope containing no storage class indication.
    A reference without a corresponding definition is an error. Some implementations also will not generate a reference for items which are
    declared with the extern keyword, but are never used within the code.
    The UNIX operating system C compiler and linker implement this model,
    which is recognized as a common extension to the C language (F.4.11).
    UNIX C programs which take advantage of this model are standard
    conforming in their environment, but are not maximally portable.
    *Strict Ref/Def* This is the same as the relaxed ref/def model, save
    that only one definition is allowed. Again, some implementations may
    decide not to put out references to items that are not used. This is the
    model specified in K&R and in the Base Document.
    *Initialization* This model requires an explicit initialization to
    define storage. All other declarations are references.
    Figure 3.1 demonstrates the differences between the models.
    The model adopted in the Standard is a combination of features of the
    strict ref/def model and the initialization model. As in the strict
    ref/def model, only a\ single translation unit contains the definition
    of a given object | many environments cannot effectively or efficiently
    support the \distributed definition" inherent in the common or relaxed
    ref/def approaches. However, either an initialization, or an appropriate declaration without storage class specifier (see x3.7), serves as the
    external definition. This composite approach was chosen to accommodate
    as wide a range of environments and existing implementations as possible."

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Thu Apr 10 19:29:12 2025
    On 2025-04-10, bart <bc@freeuk.com> wrote:
    ATEOTD, to share such a type across two or more translation units, means
    each one seeing its own definition of it. Nothing stops you having
    somewhat different versions of it, as I had above, so this part has to
    be taken on trust. This was part of my broader point that sharing
    non-linkage named entities across modules in C was ad hoc.

    Nothing stops you because struct types are de-facto non-linkage
    entities in the toolchain technology that is in widespread use.

    Nothing stops an implementation from recording, into object files, info
    that can be used to implement stricter type checking among
    translation units at link time.

    Here is one possible implementation.

    All file-scope struct/union types are compiled in some kind of
    struct/union table in the object file.

    Those struct/union types are included which have been used as follows,
    either directly or via nesting:

    - in a parameter type of an external linkage function;
    - in the return type of an external linkage function; or
    - in the type of an object declared with external linkage.

    In the table we have entries, say, consisting of the tag and, say,
    tag name and, say, a 32 bit hash of the structure shape, taken over
    all the members: their names, types, alignment and everything else
    that influences compatibility.

    Then, when linking, we merge all of the struct/union tables together.
    Whenever we see a tag that has a different 32 bit hash, that's a
    conflict, and we report those two files with the different hashes as conflicting on their definition of the type indicated by the tag name.

    The diagnostic dcould be given in tabular form, e.g:

    error: 3 incompatible definitions of "struct foo" exist:

    1: foo.o foo-helper.o
    2: bar.o
    3: stack.o queue.o

    The rules for which types are included in the tables allow uses
    where the types are not depended upon to be compatible.

    Two mdoules can have a different "struct foo { ... }" at file scope,
    which they each only use locally: neither module passes an
    instance of its foo to the other module where it is interpreted
    as that module's foo.

    These exchanges happen via the arguments of external functions,
    via global variables and via function returns. That's why we
    suspect those places.

    The rules could give rise to false positives, like when the
    foo module has helper functions that take "struct foo *" and
    are not called from outside of the module, but the helpers have not been declared static, and another module does the same thing, creating a
    clash in the table entries.

    That diagnostic would then be misleading; but it would still
    indicate that something is not tidy in the program.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Thu Apr 10 20:27:05 2025
    On 10/04/2025 20:05, David Brown wrote:
    On 10/04/2025 17:41, Kaz Kylheku wrote:
    On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
    So currently, I have no explanation for why you may write "static int
    foo; extern int foo;" and have "foo" be internal linkage, while "extern
    int foo; static int foo;" is not allowed.

    What's also not allowed is "static int foo; int foo;" !

    It's because "extern" means "refer to the existing file scope
    declaration of the identifer if there is one propagating its
    properties, including linkage; otherwise if it doesn't exist,
    create an external linkage reference"


    That's a summary of how "extern" works, but it results in a kind of
    circular argument or tautology - it's just saying "extern means what it means".  It does not explain /why/ it works this way, or where the rules came from, why C has use of a single keyword that works this way, and
    why it is called "extern".

    It would be much simpler if we had "static int x;" to mean "declare x
    with internal linkage and define it", "extern int x;" to mean "declare x
    to have extern linkage", and "int x;" to mean "declare x with external linkage and define it".  That is how you use these in most circumstances (and there are gcc warning flags to enforce it, for those that want to
    do that).

    It can't be that simple in C because of shared headers.

    If module A wants to export 'abc' to other modules, then the source code
    seen by the compiler for A.c has to look like this:

    extern int abc; // in A.h
    ......
    int abc; // in A.c


    The other modules include A.h and see 'extern int abc' which means 'abc'
    is imported. But its home module sees both of these, including the
    'extern' version, but here 'abc' is exported!

    That is counter-intuitive: how can a module both import a name (via
    'extern int') and export it (via 'int' without 'static')?

    You can't say that A.h is only for consumption by other modules, since
    it could include stuff that all module including A will need, such as
    macros, types and enums.

    So, here C is complicated because the same attribute has to mean
    different things depending on whether this is the entity's home module
    or not.


    C rarely makes things more complicated without a good reason.

    C usually makes things more complicated without a good reason!

    Here's one example, of dozens, of perfectly legal C:

    long unsigned const long const const typedef int A;
    int long unsigned const long const const typedef A;
    long unsigned const long const typedef int A;
    .....

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to James Kuyper on Thu Apr 10 16:25:01 2025
    On 4/10/25 15:14, James Kuyper wrote:
    ...
    According to the C89 Rationale

    Note: I have the C89 Rationale in PDF format. I an using an Ubuntu Linux machine, and am viewing the file with the "Document Viewer" program. I
    copied the text from that program, and pasted it into a Thunderbird
    message window. All occurrences of "ff" and "fi" in the text got
    converted to whitespace. Does anyone have any idea why that might have happened?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to James Kuyper on Thu Apr 10 21:42:04 2025
    On 10/04/2025 21:25, James Kuyper wrote:
    On 4/10/25 15:14, James Kuyper wrote:
    ...
    According to the C89 Rationale

    Note: I have the C89 Rationale in PDF format. I an using an Ubuntu Linux machine, and am viewing the file with the "Document Viewer" program.

    evince, presumably.

    I
    copied the text from that program, and pasted it into a Thunderbird
    message window. All occurrences of "ff" and "fi" in the text got
    converted to whitespace. Does anyone have any idea why that might have happened?

    ff and fi are common ligatures, so I suppose they're losing
    something in the translation, and - just a guess - you may well
    have the same problem with fl and ft.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Thu Apr 10 20:57:24 2025
    On 2025-04-10, bart <bc@freeuk.com> wrote:
    On 10/04/2025 20:05, David Brown wrote:
    It would be much simpler if we had "static int x;" to mean "declare x
    with internal linkage and define it", "extern int x;" to mean "declare x
    to have extern linkage", and "int x;" to mean "declare x with external
    linkage and define it".  That is how you use these in most circumstances
    (and there are gcc warning flags to enforce it, for those that want to
    do that).

    It can't be that simple in C because of shared headers.

    If module A wants to export 'abc' to other modules, then the source code
    seen by the compiler for A.c has to look like this:

    extern int abc; // in A.h
    ......
    int abc; // in A.c


    The other modules include A.h and see 'extern int abc' which means 'abc'
    is imported. But its home module sees both of these, including the
    'extern' version, but here 'abc' is exported!

    That is counter-intuitive: how can a module both import a name (via
    'extern int') and export it (via 'int' without 'static')?

    "extern int abc" says something like "If you henceforth use the name
    abc, it refers to an external definition, which must be supplied
    somewhere as an object with this type".

    "int abc" says, "I am supplying a tentative external definition
    for the name abc; if it is not superseded by the end of this translation
    unit, it will be put into effect as if with a zero initializer".

    These are not in conflict.

    There is no "import" or "export", just stating what an identifier means,
    and provisioning it into existence.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to David Brown on Thu Apr 10 20:21:32 2025
    On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
    On 10/04/2025 17:41, Kaz Kylheku wrote:
    On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
    So currently, I have no explanation for why you may write "static int
    foo; extern int foo;" and have "foo" be internal linkage, while "extern
    int foo; static int foo;" is not allowed.

    What's also not allowed is "static int foo; int foo;" !

    It's because "extern" means "refer to the existing file scope
    declaration of the identifer if there is one propagating its
    properties, including linkage; otherwise if it doesn't exist,
    create an external linkage reference"


    That's a summary of how "extern" works, but it results in a kind of
    circular argument or tautology - it's just saying "extern means what it

    I would never be so sloppy as to leave the two ends of any argument
    of mine dangling, not neatly closed into a circle.

    means". It does not explain /why/ it works this way, or where the rules
    came from, why C has use of a single keyword that works this way, and
    why it is called "extern".

    Where the rules came from is partially answered by the Rationale
    for ANSI C, where it discusses the various linkage models for external
    names that were in the wild.

    The "ISO-ized" version of the Rationale is found here:

    https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf

    There is a 6.2.2 Linkages of Identifiers that has useful info,
    starting with:

    "The first declaration of an identifier, including implicit declarations
    before C9X, must specify by the presence or absence of the keyword
    static whether the identifier has internal or external linkage."

    (OK, so right of the bat, that confirms that "extern" has no role
    to play in establishing linkage other than that when it is present
    in a first declaration, the static specifier must be absent, and the
    absence of static is what is important. This is not a statement of
    rationale, though, just status quo.)

    The remaning text presents a brief summary of what existed before
    the standard in terms of how internal linkage was implemented,
    and several models for external linkage, given the names "Common",
    "Relaxed Ref/Def", "Strict Ref/Def" and "Initialization":

    Common

    Every object declaration with external linkage, regardless of whether
    the keyword extern appears in the declaration, creates a definition
    of storage. When all of the modules are combined together, each
    definition with the same name is located at the same address in
    memory. (The name is derived from common storage in Fortran.) This
    model was the intent of the original designer of C, Dennis Ritchie.

    Relaxed Ref/Def

    The appearance of the keyword extern in a declaration, regardless
    of whether it is used inside or outside of the scope of a
    function, indicates a pure reference (ref), which does not define
    storage. Somewhere in all of the translation units, at least one
    definition (def) of the object must exist. An external definition
    is indicated by an object declaration in file scope containing
    no storage class indication. A reference without a corresponding
    definition is an error. Some implementations also will not generate
    a reference for items which are declared with the extern keyword but
    are never used in the code. The UNIX operating system C compiler
    and linker implement this model, which is recognized as a common
    extension to the C language (see §K.5.11). UNIX C programs
    which take advantage of this model are standard conforming in
    their environment, but are not maximally portable (not strictly
    conforming).


    Strict Ref/Def

    This is the same as the relaxed ref/def model, save that only one
    definition is allowed. Again, some implementations may decide not
    to put out references to items that are not used. This is the model
    specified in K&R.

    Initialization

    This model requires an explicit initialization to define storage. All
    other declarations are references.


    This is all relevant. The Common model for linkage was originally intended by Ritchie. But then in K&R, the authors documented Strict Ref/Def.

    Unix compiler and linkers used Relaxed Ref/Def: not every declaration
    is a definition, but multiple definitions are allowed (as long as
    they are the same).

    Knowing that Unix uses Relaxed Ref/Def, they recommended something more
    safer and more portable that will work off Unix: ensuring there is only
    one definition of an external name that is used.

    It looks like Ritchie's Common model informs the concept of a tentative definition. When you have file scope declarations like "int x;" without extern, that translation unit defines x. You never use extern, other than in a lexical scope in order to reach an existing external name. If you have shared variables, you put them in a header file and include it. That ensures that everyone has the same definition. The definitions coming from different compiled files get merged so there is one "int x" which sits at the same address.

    It looks like this Common model, related to Fortran, is probably
    the best explanation of how we got here.

    However, the Rationale says:

    "The model adopted in the Standard is a combination of features of the strict ref/def model and the initialization model."

    It would be much simpler if we had "static int x;" to mean "declare x
    with internal linkage and define it"

    There are sometimes reasons why we need a static forward
    declarations for an object (not to mention function). Example:

    static struct foo_operations;

    static void foo_create_similar(struct foo *old_foo)
    {
    struct foo *new_foo = malloc(sizeof *foo);
    ...
    // for whatever reason, this is not copied from old_foo
    new_foo->ops = &foo_operations;
    ...
    return foo;
    }

    static struct foo_operations = { ..., foo_clone, ... };

    The function needs to refer to foo_operations for whatever reason, and the initialisation of foo_operations need the function.

    "extern int x;" to mean "declare x
    to have extern linkage", and "int x;" to mean "declare x with external linkage and define it". That is how you use these in most circumstances
    (and there are gcc warning flags to enforce it, for those that want to
    do that).

    So this describes the Strict Ref/Def model, like recommended in the K&R; but not reflecting restrictions actually implemented in the wild!

    C rarely makes things more complicated without a good reason. You gave
    the example of using "extern" for "unshadowing" an identifier (thank you
    for that example!), but it doesn't strike me as sufficient
    justification. I had thought the reason for the way "extern" and
    "static" interact was historical compatibility, but that does not appear
    to be the case.

    Dennis Ritchie's 1975 C reference manual already describes a local use
    of extern:

    "In the extern case there must be an external definition (see below) for the
    given identifiers somewhere outside the function in which they are declared."

    This is the only mention of the extern specifier that Ritchie gives,
    indicating that it's not meant for file scope use (making external definitions).

    About external definitions (what the "see below" refers to above), he writes:

    "An external definition declares an identifier to have storage class extern
    and a specified type."

    He does not specify that this requires the extern specifier!

    Also, the static keyword exists in this manual but is again for local use,
    not for file scope use.

    IN an appendix about platform differences he writes:

    "The externanl definition "static int . . " is legal on GCOS, but gets a
    diagnostic on UNIX. (On GCOS it means an identifier global to the routines in
    the file but invisible to routines compiled separately.)

    Wow! So static meaning "private to this file" was essentially a hack introduced on GCOS that didn't owrk on Unix. I think that marks the first instance where static was given an overloaded meaning: GCOS is the culprit.

    Let us turn to the B language also, where extern was known as extrn.
    (If that had not been changd, the authors would have two regrets: not putting the 'e' in "creat" and in "extrn".)

    The B user manual says:

    6.1 External Declaration

    The external declaration has the form:

    extrn name1 , name2 ... ;

    The external declaration specifies that each of the named variables
    is of the external storage class. The declaration must occur before
    the first use of each of the variables. Each of the variables must
    also be externally defined.

    Again, in B, extrn are declarations that a name or names exist
    externally, not definitions!

    The following example occurs (abridged):

    main() {
    extrn putchar, n, v;
    auto i, c, col, a;

    i = col = 0;
    while(i<n)
    v[i++] = 1;
    while(col<2*n) {
    a = n+1 ;
    c = i = 0;
    while (i<n) {
    c =+ v[i] *10;
    v[i++] = c%a;
    c =/ a--;
    }

    putchar(c+'0');
    if(!(++col%5))
    putchar(col%50?' ': '*n');
    }
    putchar('*n*n');
    }

    v[2000];
    n 2000;

    For whatever reason, the extrn is put into the scope of main and not
    at file scope. The subsequent definitions v[2000] and n 2000
    do not mention any extrn; they are definitions, not declarations of
    existence.

    In B, extrn clearly means "trust me that the following names are
    definied somewhere globally".

    Lastly, a BNF grammar is given in the B manual. In this grammar
    we have this:

    statement ::=
    ...
    extrn name {, name}0 ; statement

    extrn isn't anything like storage class specifier at all, but
    a statement keyword! And that is why it *must not* appear at
    file scope.

    The B language has no way to indicate that osmething exists
    externally somewhere other than inside the body of a function.

    The situations in which we must use extern at file scope today
    are the result of the Strict Ref/Def model that came later.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Fri Apr 11 00:02:24 2025
    On 10/04/2025 20:29, Kaz Kylheku wrote:
    On 2025-04-10, bart <bc@freeuk.com> wrote:
    ATEOTD, to share such a type across two or more translation units, means
    each one seeing its own definition of it. Nothing stops you having
    somewhat different versions of it, as I had above, so this part has to
    be taken on trust. This was part of my broader point that sharing
    non-linkage named entities across modules in C was ad hoc.

    Nothing stops you because struct types are de-facto non-linkage
    entities in the toolchain technology that is in widespread use.

    Nothing stops an implementation from recording, into object files, info
    that can be used to implement stricter type checking among
    translation units at link time.

    Here is one possible implementation.

    All file-scope struct/union types are compiled in some kind of
    struct/union table in the object file.

    Those struct/union types are included which have been used as follows,
    either directly or via nesting:

    - in a parameter type of an external linkage function;
    - in the return type of an external linkage function; or
    - in the type of an object declared with external linkage.

    In the table we have entries, say, consisting of the tag and, say,
    tag name and, say, a 32 bit hash of the structure shape, taken over
    all the members: their names, types, alignment and everything else
    that influences compatibility.

    Then, when linking, we merge all of the struct/union tables together. Whenever we see a tag that has a different 32 bit hash, that's a
    conflict, and we report those two files with the different hashes as conflicting on their definition of the type indicated by the tag name.

    The diagnostic dcould be given in tabular form, e.g:

    error: 3 incompatible definitions of "struct foo" exist:

    1: foo.o foo-helper.o
    2: bar.o
    3: stack.o queue.o

    The rules for which types are included in the tables allow uses
    where the types are not depended upon to be compatible.

    Two mdoules can have a different "struct foo { ... }" at file scope,
    which they each only use locally: neither module passes an
    instance of its foo to the other module where it is interpreted
    as that module's foo.

    These exchanges happen via the arguments of external functions,
    via global variables and via function returns. That's why we
    suspect those places.

    The rules could give rise to false positives, like when the
    foo module has helper functions that take "struct foo *" and
    are not called from outside of the module, but the helpers have not been declared static, and another module does the same thing, creating a
    clash in the table entries.

    That diagnostic would then be misleading; but it would still
    indicate that something is not tidy in the program.

    That sounds quite ambitious, and lot of work for something that may or
    may detect type issues - at link time.

    It involves a compiler infering the types that may be exported from a
    module, and writing it to a, presumably, standard format object file (I
    guess as some kind of extra global variable).

    But then you want to get a linker to do the checking. Existing ones
    won't know anything about this.

    If you're going to be doing heavyweight changes to an implementation,
    then it could worth think more deeply about what can be possible.

    However this is going to be hamstrung by the language: non-linkage
    entities like macros, enumerations and types don't have any means to
    indicate that they are exported or imported. Especially macros which
    don't really exist after lexing, but which could be an essential part of
    some API.

    Importing wouldn't actually be a thing at all; duplicates of the
    definitions that exist in the exporting modules must also exist in this translation unit.

    I'm not entirely convinced by your scheme to detect candidates that
    might be exported, which is only for certain types anyway, and which
    ought to include function signatures. At present only function names are exported and imported.

    (I'm aware of the C++ scheme that encodes signatures within function
    names; that sounds hacky. However that could conceivably be used to
    check passed struct types too.)

    In short, I don't think it buys you enough for the effort. The schemes
    I'd be interested in would wrap or augment the language. They would
    provide error detection in the compiler. They would allow genuine
    sharing (a entity is defined in one place only).

    Unless ... you've already implemented your proposal?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Fri Apr 11 00:49:48 2025
    On 10/04/2025 23:23, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 10/04/2025 12:28, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Someone, not anyone but the all-knowing Tim, said: "and those types
    are not compatible, because the two struct tags are different."

    Do you agree with that? Or is there something more to making two types >>>> be incompatible?
    I don't recall the exact discussion

    It stems from this, a reply from DB dated: "Tue, 8 Apr 2025 16:50:56
    +0200". (About half way down there is some quoted code of mine.)

    It concerned two struct types in different translations units, which
    needed to be compatible for the test program to work corectly.

    I said they were compatible enough. David said they were entirely
    compatible. Tim said "No they are not". Three different opinions.

    Either David or Tim was right; I don't much care which.

    No? BUT YOU CARE VERY MUCH THAT I AM WRONG!

    You were wrong.

    See?! Funny that isn't it; two people both make strong unequivocal
    statements that are at odds with each other, such that one is likely to
    be wrong, but you don't care about putting THEM right.

    Yet I make a minor observation, and everyone comes down on me like a ton
    of bricks.

    There is no such thing as "compatible enough"; two types
    either are compatible or are not compatible. I won't speculate on what
    you might have meant by "compatible enough".

    You must have seen the example, and based on my lifetime experience in
    low level coding, those types ARE compatible enough: one consists of two consecutive 32-bit floats, so does the other. What more is needed?

    I don't buy the nonsense in the standard that the member names must
    match; what possible difference can that make?

    I will admit it might not meet /those/ standards for compatibility,
    that's why I said it was compatible enough. That is, for all practical purposes.

    And this was my original point: the C language can't force a sharing of
    a particular type; compatibility between the versions seen in different translations is on trust. This is the reason for member names having to
    be the same, to make it less likely that the structs match by chance,
    and to encourage people to share the same definition via a header.

    This is why my example chose different tags and different names (and
    wrapped one set of member types in a typedef): it DELIBERATELY created
    two structs which were compatible at the machine level (ie. both being
    the tuple (f32, f32)), but likely intended for different purposes.

    And that was to back up my point that C could not detect the usage of
    such a mix of types.

    Do you understand now WHY I said 'compatible enough'?

    Are you are utterly incapable of understanding anything outside of the
    'the standard'?

    Either David or Tim was right; I don't much care which.

    This is now of most interest to me; somebody might be wrong on some
    detail of the C standard, but you don't care?!

    I don't buy it. I don't know what's going on here but it stinks.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Keith Thompson on Thu Apr 10 20:57:17 2025
    On 4/10/25 18:49, Keith Thompson wrote:
    ...
    Do you have a URL for a PDF C89 Rationale?

    No, I have it on disk, but I have no idea where I downloaded it from. As
    a general rule, I download documents like that after seeing links to
    them posted in usenet messages. It's current name is "C89.pdf", but I
    probably renamed it from something less descriptive. Anyone who wants a
    copy of unknown provenance, let me know.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Thu Apr 10 20:40:09 2025
    On 09/04/2025 15:13, bart wrote:
    On 09/04/2025 13:36, David Brown wrote:
    On 09/04/2025 12:51, bart wrote:

    [Restore previously clipped context]
    Turning it around, you're saying that if T an U are incompatible types
    within the same translation unit, they suddenly become compatible if
    split across two translation units?

    ...
    I'll have to think about this before replying to any other points.

    Marvellous - I'd appreciate you putting more thought into this, and
    less knee-jerk reactions and exaggerations.  Please also read the
    relevant parts of the standards before replying - at the very least,
    section 6.2.7p1 and section 6.2.2.  Once you have read these and tried
    to understand them, it will be a lot easier to clear up any remaining
    issues.

    I'm not going to wade through reams of Standard minutiae, sorry.I

    ...
    Are T and U compatible types are not? The answer must be unequivocal
    without needing to be a 'standards-head'.

    I have no idea what qualifies as being a "standards-head". However, it
    does not take "reams of Standard minutiae" to answer that question, only
    about one page, which I've quoted below.

    The clipping that I restored above seems to be the complete definition
    of T and U in this context. However, the problem doesn't come up in the
    general case where T and U are incompatible types. It applies only to
    struct, union, and enumeration types that are incompatible because they
    occur in separate declarations in the same translation unit, and there
    are additional requirements on those types listed below. The key
    relevant clause is:

    "Two declarations of structure, union, or enumerated types which ... use different tags declare distinct types. Each declaration of a structure,
    union, or enumerated type which does not include a tag declares a
    distinct type." (6.7.2.3p9).

    So if T and U are tags, they declare distinct types. If either one is a
    typedef for a type declared without a tag, they are distinct types. Note
    that types declared in different translation units are automatically
    distinct types, because file scope is the largest scope that exists in
    C, and it terminates at the end of a translation unit.

    Now, because they are distinct types, the first sentence of 6.2.7
    doesn't apply:

    "Two types are compatible types if they are the same."

    Therefore, you'll have to skip to the rest of 6.2.7:

    "Moreover, two complete structure, union, or enumerated types declared
    with the same tag are compatible if members satisfy the following
    requirements:
    — there shall be a one-to-one correspondence between their members such
    that each pair of corresponding members are declared with compatible types;
    — if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier;
    — and, if one member of the pair is declared with a name, the other is declared with the same name.
    For two structures, corresponding members shall be declared in the same
    order. For two unions declared in the same translation unit,
    corresponding members shall be declared in the same order. For two
    structures or unions, corresponding bit-fields shall have the same
    widths. For two enumerations, corresponding members shall have the same
    values; if one has a fixed underlying type, then the other shall have a compatible fixed underlying type. For determining type compatibility,
    anonymous structures and unions are considered a regular member of the containing structure or union type, and the type of an anonymous
    structure or union is considered compatible to the type of another
    anonymous structure or union, respectively, if their members fulfill the
    above requirements.

    Furthermore, two structure, union, or enumerated types declared in
    separate translation units are compatible in the following cases:
    — both are declared without tags and they fulfill the requirements above;
    — both have the same tag and are completed somewhere in their respective translation units and they fulfill the requirements above;
    — both have the same tag and at least one of the two types is not
    completed in its translation unit.

    Otherwise, the structure, union, or enumerated types are incompatible."

    Pay close attention to the last three bullet items.

    Whether or not T and U change from being incompatible to being
    compatible if declared in different translation units depends upon
    whether T and U are tags or typedefs. If T and U are both tags, only the
    last two bullets can apply, and T and U remain incompatible even if
    declared in different translation units.

    However, If T and U are typedefs for types "declared without tags and
    they fulfill the requirements above", then they qualify as compatible
    types under the first bullet above.

    Note that the length of this quotation is almost entirely taken up by
    detailing "the requirements above" - but those requirements can be
    summarized by saying that the declarations of the members are,
    recursively, only permitted to be different by reason of specifying
    distinct but compatible types.

    ...
    This has been said in this
    thread:


    BC: The types involved are somewhat different, but are compatible enough
        for it to work. [In that the member types, offsets and overall size,
        since pass-by-value is used, correspond]

    DB: The two types are entirely compatible.

    BC: Are they?

    TR: No, they are not.

    You say they're compatible, Tim Rentsch says they're not; who's right?

    I haven't seen Tim's contributions to this thread, so I can't be sure,
    but since the answer depends upon whether they are tags or typedefs, I
    would imagine that that distinction might be involve in that discrepancy.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Keith Thompson on Fri Apr 11 02:12:17 2025
    On 2025-04-10, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    [...]
    Where the rules came from is partially answered by the Rationale
    for ANSI C, where it discusses the various linkage models for external
    names that were in the wild.

    The "ISO-ized" version of the Rationale is found here:

    https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf
    [...]

    N850 is an early version of the C9x (later C99) Rationale.
    A later version is at

    http://www.open-std.org/jtc1/sc22/WG14/www/C99RationaleV5.10.pdf

    But that n850 says that

    This Rationale summarizes the deliberations of NCITS J11 (formerly
    X3J11) and SC22 WG14, 5 respectively the ANSI Technical Committee and
    ISO/IEC JTC 1 Working Group, charged with revising the International
    Standard for the C programming language; and it retains much of the
    text of the Rationale for the original ANSI Standard (ANSI
    X3.159-1989, the so-called "C89").

    It has the ANSI Rationale content; it has served my purpose here,
    since it has all the same material about linkage of identifiers.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Thu Apr 10 18:52:04 2025
    bart <bc@freeuk.com> writes:

    [... compatibility of struct types ...]

    The example was like this:

    module A: typedef struct point {float a; float b;} Point;

    module B: typedef float length;
    typedef struct _tag {length x, y;} vector;

    David Brown said: "The two types are entirely compatible."

    I said: "Are they?"

    Tim Rentsch said: "No, they are not."

    I withdraw my earlier statement. Please leave me out of any
    future discussion of the subject.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Thu Apr 10 22:55:06 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    bart <bc@freeuk.com> writes:

    [... compatibility of struct types ...]

    The example was like this:

    module A: typedef struct point {float a; float b;} Point;

    module B: typedef float length;
    typedef struct _tag {length x, y;} vector;

    David Brown said: "The two types are entirely compatible."

    I said: "Are they?"

    Tim Rentsch said: "No, they are not."

    I withdraw my earlier statement. Please leave me out of any
    future discussion of the subject.

    Do you mean that your earlier statement was incorrect (i.e., that
    the types are compatible), or do you merely wish to pretend you
    never said anything without taking a position on whether they're
    compatible, or do you refuse to say?

    I am specifically _not_ saying either that my earlier statement
    was right or that my earlier statement was wrong. My hope is
    that henceforth people will act as though the statement never
    entered the discussion. Does that clarify the matter for you?

    Don't worry, I'm not planning to start or participate in a
    lengthy discussion on your statement (that never turns out well).
    I'm inviting you to clarify if you choose to do so. [...]

    I appreciate the invitation and have made an earnest effort
    to accommodate it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Kaz Kylheku on Fri Apr 11 11:33:22 2025
    On 10/04/2025 22:21, Kaz Kylheku wrote:
    On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
    On 10/04/2025 17:41, Kaz Kylheku wrote:
    On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
    So currently, I have no explanation for why you may write "static int
    foo; extern int foo;" and have "foo" be internal linkage, while "extern >>>> int foo; static int foo;" is not allowed.

    What's also not allowed is "static int foo; int foo;" !

    It's because "extern" means "refer to the existing file scope
    declaration of the identifer if there is one propagating its
    properties, including linkage; otherwise if it doesn't exist,
    create an external linkage reference"


    That's a summary of how "extern" works, but it results in a kind of
    circular argument or tautology - it's just saying "extern means what it

    I would never be so sloppy as to leave the two ends of any argument
    of mine dangling, not neatly closed into a circle.


    :-)

    means". It does not explain /why/ it works this way, or where the rules
    came from, why C has use of a single keyword that works this way, and
    why it is called "extern".

    Where the rules came from is partially answered by the Rationale
    for ANSI C, where it discusses the various linkage models for external
    names that were in the wild.

    The "ISO-ized" version of the Rationale is found here:

    https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf


    Thank you for posting that. I'm snipping it for space here, but I
    appreciate the historical explanation.


    It would be much simpler if we had "static int x;" to mean "declare x
    with internal linkage and define it"

    There are sometimes reasons why we need a static forward
    declarations for an object (not to mention function). Example:

    Sure. I was simplifying things with just "int" objects. Static forward declarations are essential in recursive structures and recursive
    functions. (I was also simplifying by ignoring initialisation.)


    static struct foo_operations;

    static void foo_create_similar(struct foo *old_foo)
    {
    struct foo *new_foo = malloc(sizeof *foo);
    ...
    // for whatever reason, this is not copied from old_foo
    new_foo->ops = &foo_operations;
    ...
    return foo;
    }

    static struct foo_operations = { ..., foo_clone, ... };

    The function needs to refer to foo_operations for whatever reason, and the initialisation of foo_operations need the function.

    "extern int x;" to mean "declare x
    to have extern linkage", and "int x;" to mean "declare x with external
    linkage and define it". That is how you use these in most circumstances
    (and there are gcc warning flags to enforce it, for those that want to
    do that).

    So this describes the Strict Ref/Def model, like recommended in the K&R; but not reflecting restrictions actually implemented in the wild!

    C rarely makes things more complicated without a good reason. You gave
    the example of using "extern" for "unshadowing" an identifier (thank you
    for that example!), but it doesn't strike me as sufficient
    justification. I had thought the reason for the way "extern" and
    "static" interact was historical compatibility, but that does not appear
    to be the case.

    Dennis Ritchie's 1975 C reference manual already describes a local use
    of extern:

    "In the extern case there must be an external definition (see below) for the
    given identifiers somewhere outside the function in which they are declared."

    This is the only mention of the extern specifier that Ritchie gives, indicating that it's not meant for file scope use (making external definitions).

    About external definitions (what the "see below" refers to above), he writes:

    "An external definition declares an identifier to have storage class extern
    and a specified type."

    He does not specify that this requires the extern specifier!

    I think it is fair to say that the early C reference manuals were not as formal, rigorous and tightly specified as later ISO standards.

    Again, thank you for the history of B, which I have read but snipped for brevity.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Richard Heathfield on Fri Apr 11 11:35:38 2025
    On 10/04/2025 22:42, Richard Heathfield wrote:
    On 10/04/2025 21:25, James Kuyper wrote:
    On 4/10/25 15:14, James Kuyper wrote:
    ...
    According to the C89 Rationale

    Note: I have the C89 Rationale in PDF format. I an using an Ubuntu Linux
    machine, and am viewing the file with the "Document Viewer" program.

    evince, presumably.

    I
    copied the text from that program, and pasted it into a Thunderbird
    message window. All occurrences of "ff" and "fi" in the text got
    converted to whitespace. Does anyone have any idea why that might have
    happened?

    ff and fi are common ligatures, so I suppose they're losing something in
    the translation, and - just a guess - you may well have the same problem
    with fl and ft.


    And also "fj", as seen in phrases like "It's not dead, it's pining for
    the fjords".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Fri Apr 11 11:17:04 2025
    On 10/04/2025 21:27, bart wrote:
    On 10/04/2025 20:05, David Brown wrote:
    On 10/04/2025 17:41, Kaz Kylheku wrote:
    On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
    So currently, I have no explanation for why you may write "static int
    foo; extern int foo;" and have "foo" be internal linkage, while "extern >>>> int foo; static int foo;" is not allowed.

    What's also not allowed is "static int foo; int foo;" !

    It's because "extern" means "refer to the existing file scope
    declaration of the identifer if there is one propagating its
    properties, including linkage; otherwise if it doesn't exist,
    create an external linkage reference"


    That's a summary of how "extern" works, but it results in a kind of
    circular argument or tautology - it's just saying "extern means what
    it means".  It does not explain /why/ it works this way, or where the
    rules came from, why C has use of a single keyword that works this
    way, and why it is called "extern".

    It would be much simpler if we had "static int x;" to mean "declare x
    with internal linkage and define it", "extern int x;" to mean "declare
    x to have extern linkage", and "int x;" to mean "declare x with
    external linkage and define it".  That is how you use these in most
    circumstances (and there are gcc warning flags to enforce it, for
    those that want to do that).

    It can't be that simple in C because of shared headers.

    If module A wants to export 'abc' to other modules, then the source code
    seen by the compiler for A.c has to look like this:

         extern int abc;     // in A.h
         ......
         int abc;            // in A.c


    Yes.

    In A.c, "abc" is declared to have external linkage, then it is declared
    with external linkage and defined.


    The other modules include A.h and see 'extern int abc' which means 'abc'
    is imported.

    There is no "import" or "export" in C - only "internal linkage" or
    "external linkage" - file local or program global, if you prefer. The combinations "declare with external linkage but do not define" and
    "declare with external linkage and define" are used to achieve import
    and export of identifiers.

    But its home module sees both of these, including the
    'extern' version, but here 'abc' is exported!

    Yes - "extern" does /not/ mean "export".


    That is counter-intuitive: how can a module both import a name (via
    'extern int') and export it (via 'int' without 'static')?

    If the keyword "extern" were written "export", I'd agree on it being counter-intuitive. But it is not written that way. The point of
    "extern" is that it indicates external linkage - program-wide sharing of
    the identifier in question. It is shared amongst the units that exports
    it (by defining it) and units that import it (by using it), usually
    achieved by having the same shared header included by the exporting unit
    and the importing units. This has a huge advantage compared to
    languages where importing units read some kind of interface import file
    but the exporting one does not - it is extremely easy in C to ensure
    that all your shared identifiers match up correctly by keeping all
    external declarations in shared headers and all definitions in C files.


    You can't say that A.h is only for consumption by other modules, since
    it could include stuff that all module including A will need, such as
    macros, types and enums.

    Of course - "A.h" is /not/ only for consumption by other translation
    units. (Please call them "translation units" or just "C files", not
    "modules" since we are discussing the C alternatives to code modules
    found in some other languages.) "A.h" is for consumption in "A.c" as
    well. This is the normal way of structuring C code.


    So, here C is complicated because the same attribute has to mean
    different things depending on whether this is the entity's home module
    or not.

    No, it means /exactly/ the same thing in both situations.

    "Linkage" is about the /link/, not one side of the link (export or
    import). "extern" declares external linkage.

    Some other programming languages make the distinction between import and export. That can work too, if you have enough extra support (such as
    compiled "interface" files generated from an exporting module). Without
    that support - such as is the case for most assembly languages - it's
    very easy to get mixups between what one assembly file "foo.asm" exports
    and what other modules import from "foo.inc". One way to handle that limitation is a whole collection of messy macros. I've been there, done
    that, and am glad to have left it behind.




    C rarely makes things more complicated without a good reason.

    C usually makes things more complicated without a good reason!

    Nope.


    Here's one example, of dozens, of perfectly legal C:

      long unsigned const long const const typedef int A;
      int long unsigned const long const const typedef A;
      long unsigned const long const typedef int A;
      .....


    That is not more complicated, nor is it without good reason. The
    language quite simply doesn't bother insisting on a specific order for
    some parts of declarations. It is simpler to describe in the standard.

    (Putting storage-class specifiers other than at the start of a
    declaration has been obsolescent since at least C99 - but it has not
    been removed from the language. I think that is because it would be
    extra work in specifying the syntax rules, rather than because many
    people write declarations like yours.)

    Nothing will ever stop some programmers from writing complicated or
    messy code.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Fri Apr 11 12:14:38 2025
    On 11/04/2025 07:00, Keith Thompson wrote:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    [...]
    I withdraw my earlier statement. Please leave me out of any
    future discussion of the subject.

    Do you mean that your earlier statement was incorrect (i.e., that
    the types are compatible), or do you merely wish to pretend you
    never said anything without taking a position on whether they're
    compatible, or do you refuse to say?

    I am specifically _not_ saying either that my earlier statement
    was right or that my earlier statement was wrong. My hope is
    that henceforth people will act as though the statement never
    entered the discussion. Does that clarify the matter for you?

    That answers precisely what I was asking, thank you.

    As often happens, I am mystified by your decision, but it is
    unquestionably yours.

    I'll try not to include you in any further discussion, but I do
    not promise to try very hard.

    Don't worry, I'm not planning to start or participate in a
    lengthy discussion on your statement (that never turns out well).
    I'm inviting you to clarify if you choose to do so. [...]

    I appreciate the invitation and have made an earnest effort
    to accommodate it.



    I wonder if I could withdraw all MY statements in this thread, and be
    treated with an equal amount of civility?

    No, I thought not.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Keith Thompson on Fri Apr 11 14:26:36 2025
    On Thu, 10 Apr 2025 17:59:15 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:


    An understanding of what "compatible types" means.

    Bart didn't say that types are compatible or non-compatible.
    He said that they are 'compatible enough'. That is not terminology of C Standard, but terminology of his own. And he seems to understand it.

    In my own translation, 'compatible enough' means that when these structs
    are accessed then any sane or even semi-sane compiler will generate code
    that will have the same effect as in case of access through structures
    with literally identical declarations.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to James Kuyper on Fri Apr 11 14:37:39 2025
    On Thu, 10 Apr 2025 20:57:17 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 4/10/25 18:49, Keith Thompson wrote:
    ...
    Do you have a URL for a PDF C89 Rationale?

    No, I have it on disk, but I have no idea where I downloaded it from.
    As a general rule, I download documents like that after seeing links
    to them posted in usenet messages. It's current name is "C89.pdf",
    but I probably renamed it from something less descriptive. Anyone who
    wants a copy of unknown provenance, let me know.

    Does this copy have the same problems? https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Fri Apr 11 12:51:05 2025
    On 11/04/2025 10:17, David Brown wrote:
    On 10/04/2025 21:27, bart wrote:
    On 10/04/2025 20:05, David Brown wrote:

    C rarely makes things more complicated without a good reason.

    C usually makes things more complicated without a good reason!

    Nope.


    Here's one example, of dozens, of perfectly legal C:

       long unsigned const long const const typedef int A;
       int long unsigned const long const const typedef A;
       long unsigned const long const typedef int A;
       .....


    That is not more complicated, nor is it without good reason.

    Huh? That demonstrates several things:

    1 That the same identifier can be redeclared multiple times

    2 That 'typedef' needn't be on the left, but can be anywhere in the
    middle of a type spec

    3 That 'const' can also be anywhere inside the type spec

    4 That duplicate 'const's are tolerated

    5 That the three tokens ('int', 'unsigned' and two 'long's) denoting the
    type can be be any order (and mixed up with other attributes)

    I missed out:

    6 'int' can be optionally omitted in this case.

    That makes it pretty complicated to me! And I can't see that any of
    these are necessary. A syntax like this:

    typedef A = const unsigned long long int;

    which is only allowed once; typedef always on the left; 'const' only
    once; and the token order must be as specified, will achieve everything
    that needs to be achieved.

    I haven't remarked on:

    7 That you need 3/4 tokens to specify a simple u64 type.

    since you suggest that 'uint64_t' used. However, that adds to the
    complication:

    8 A u64 type can be denoted as either 'uint64_t' OR as some combination
    of the tokens (long, long, unsigned, [int])

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Fri Apr 11 16:11:32 2025
    On 11/04/2025 13:26, Michael S wrote:
    On Thu, 10 Apr 2025 17:59:15 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:


    An understanding of what "compatible types" means.

    Bart didn't say that types are compatible or non-compatible.
    He said that they are 'compatible enough'. That is not terminology of C Standard, but terminology of his own. And he seems to understand it.

    In my own translation, 'compatible enough' means that when these structs
    are accessed then any sane or even semi-sane compiler will generate code
    that will have the same effect as in case of access through structures
    with literally identical declarations.


    With that kind of thing, you always have to consider future-proofing for
    more advanced compilers.

    With separately compile units that are then linked with a traditional
    linker, the compiler has no information about the details of struct
    definitions in different units. Thus you can be sure that it everything
    will work even if the two different structs are defined with different
    tags and field names - indeed, as long as you stick to a common prefix
    with fields with the same representation and alignments, I have great difficulty imagining how it might possible fail to work just as if the
    struct types had actually been compatible.

    However, compilers don't have to work that way. Once you introduce
    link-time optimisation or other whole-program analysis, or compile the
    two units in one compile command, or allow more advanced object file
    formats that pass type details on to the linker, such assumptions don't
    hold. A compiler with LTO can quite reasonably optimise code on the
    assumption that a pointer to one type could not alias a pointer to an incompatible type, even if those types were otherwise extremely similar.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to James Kuyper on Fri Apr 11 14:02:57 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 4/10/25 18:49, Keith Thompson wrote:
    ...
    Do you have a URL for a PDF C89 Rationale?

    No, I have it on disk, but I have no idea where I downloaded it from. As
    a general rule, I download documents like that after seeing links to
    them posted in usenet messages. It's current name is "C89.pdf", but I >probably renamed it from something less descriptive. Anyone who wants a
    copy of unknown provenance, let me know.

    google sez:

    http://port70.net/%7Ensz/c/c89/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Fri Apr 11 16:25:03 2025
    On 11/04/2025 13:51, bart wrote:
    On 11/04/2025 10:17, David Brown wrote:
    On 10/04/2025 21:27, bart wrote:
    On 10/04/2025 20:05, David Brown wrote:

    C rarely makes things more complicated without a good reason.

    C usually makes things more complicated without a good reason!

    Nope.


    Here's one example, of dozens, of perfectly legal C:

       long unsigned const long const const typedef int A;
       int long unsigned const long const const typedef A;
       long unsigned const long const typedef int A;
       .....


    That is not more complicated, nor is it without good reason.

    Huh? That demonstrates several things:

    1 That the same identifier can be redeclared multiple times

    Many types of declarations can be repeated, as long as they define the
    same identifier to be the same thing. If you want the details, they are
    in section 6.7 of the standard.


    2 That 'typedef' needn't be on the left, but can be anywhere in the
    middle of a type spec

    Correct. Putting it anywhere other than the left may be disallowed
    sometime in the future (it is an "obsolescent feature"), but it is
    currently supported in C.


    3 That 'const' can also be anywhere inside the type spec

    Correct.


    4 That duplicate 'const's are tolerated

    Correct.


    5 That the three tokens ('int', 'unsigned' and two 'long's) denoting the
    type can be be any order (and mixed up with other attributes)


    Correct.

    You seem to think that allowing a variation in the way a declaration is
    made makes the feature "more complicated". That is simply incorrect.
    The feature - the syntax and the rules in the language definition - are
    /less/ complicated because of this flexibility. It means the syntax
    here can be, as given in 6.7p1 :

    declaration-specifiers:
    storage-class-specifier declaration-specifiers opt
    type-specifier declaration-specifiers opt
    type-qualifier declaration-specifiers opt
    function-specifier declaration-specifiers opt
    alignment-specifier declaration-specifiers opt

    If the order were to be strictly specified, there would need to be a
    half-dozen more named and defined specifier lists in the syntax.

    It would certainly have been possible to specify an order - either in
    the syntax or the constraints. I think that would have been a good
    idea, and would make C code a little more consistent. But by the time
    this was codified, there was probably a variety of orderings in use in
    real code, and such ordering would make the standard, and therefore the language, a little more complicated.

    I missed out:

    6 'int' can be optionally omitted in this case.

    That makes it pretty complicated to me! And I can't see that any of
    these are necessary.

    No one suggested it was at all necessary.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Fri Apr 11 15:50:41 2025
    On 11/04/2025 15:25, David Brown wrote:
    On 11/04/2025 13:51, bart wrote:
    On 11/04/2025 10:17, David Brown wrote:
    On 10/04/2025 21:27, bart wrote:
    On 10/04/2025 20:05, David Brown wrote:

    C rarely makes things more complicated without a good reason.

    C usually makes things more complicated without a good reason!

    Nope.


    Here's one example, of dozens, of perfectly legal C:

       long unsigned const long const const typedef int A;
       int long unsigned const long const const typedef A;
       long unsigned const long const typedef int A;
       .....


    That is not more complicated, nor is it without good reason.

    Huh? That demonstrates several things:

    1 That the same identifier can be redeclared multiple times

    Many types of declarations can be repeated, as long as they define the
    same identifier to be the same thing.  If you want the details, they are
    in section 6.7 of the standard.


    2 That 'typedef' needn't be on the left, but can be anywhere in the
    middle of a type spec

    Correct.  Putting it anywhere other than the left may be disallowed
    sometime in the future (it is an "obsolescent feature"), but it is
    currently supported in C.


    3 That 'const' can also be anywhere inside the type spec

    Correct.


    4 That duplicate 'const's are tolerated

    Correct.


    5 That the three tokens ('int', 'unsigned' and two 'long's) denoting
    the type can be be any order (and mixed up with other attributes)


    Correct.

    You seem to think that allowing a variation in the way a declaration is
    made makes the feature "more complicated".  That is simply incorrect.
    The feature - the syntax and the rules in the language definition -
    are /less/ complicated because of this flexibility.  It means the syntax here can be, as given in 6.7p1 :

    declaration-specifiers:
        storage-class-specifier declaration-specifiers opt
        type-specifier declaration-specifiers opt
        type-qualifier declaration-specifiers opt
        function-specifier declaration-specifiers opt
        alignment-specifier declaration-specifiers opt

    That always reads to me like 'lots of twisty windy passages, all alike'.

    If the order were to be strictly specified, there would need to be a half-dozen more named and defined specifier lists in the syntax.

    This is the similar feature for my syntax, a bit of BNF:

    typedef = [scopeattr] 'type' name = typespec

    It does a bit more than C's 'typedef' in that such names can be
    exported, to render them visible to modules that import this one.

    Notice that the 'type' keyword and the new identifier are outside of the type-spec, which is part of what makes C syntax a nightmare.


    It would certainly have been possible to specify an order - either in
    the syntax or the constraints.  I think that would have been a good
    idea, and would make C code a little more consistent.  But by the time
    this was codified, there was probably a variety of orderings in use in
    real code, and such ordering would make the standard, and therefore the language, a little more complicated.

    I missed out:

    6 'int' can be optionally omitted in this case.

    That makes it pretty complicated to me! And I can't see that any of
    these are necessary.

    No one suggested it was at all necessary.

    /You/ did: "That is not more complicated, nor is it without good reason."

    What are those good reasons, that it makes code more readable? That it
    is easier to describe in a grammar? That it makes it easier to parse?

    I've parsed C code; I can confirm it is much harder to do that any
    language I've devised.

    Pretending for a minute that I have 'const' in my syntax, the example I
    posted would be written like this:

    type A = const u64

    You can only define it once. The new name is ALWAYS on the left of the
    '=', unlike C, where here:

    typedef int (*A)[];

    the name is in the middle of the 'int(*)[]' type.

    If shared across multiple modules, then you'd write it like this (and
    not in a header either):

    global type A = const u64

    *That* is simple. Remember you said this:

    "C rarely makes things more complicated without a good reason."

    And I responded woth this:

    "C usually makes things more complicated without a good reason!"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Michael S on Fri Apr 11 11:16:37 2025
    On 4/11/25 07:37, Michael S wrote:
    ...
    Does this copy have the same problems? https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf

    No. For example, the first line containing "fi" is:

    "3.Terms and definitions............................................................................................................6"

    the "fi" in definitions required no fix up after cut-and-paste.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to James Kuyper on Fri Apr 11 18:31:51 2025
    On Fri, 11 Apr 2025 11:16:37 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 4/11/25 07:37, Michael S wrote:
    ...
    Does this copy have the same problems? https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf

    No. For example, the first line containing "fi" is:

    "3.Terms and definitions............................................................................................................6"

    the "fi" in definitions required no fix up after cut-and-paste.

    Then I can't help. That's the only copy I have.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Fri Apr 11 17:24:08 2025
    On 11/04/2025 16:50, bart wrote:
    On 11/04/2025 15:25, David Brown wrote:
    On 11/04/2025 13:51, bart wrote:
    On 11/04/2025 10:17, David Brown wrote:
    On 10/04/2025 21:27, bart wrote:
    On 10/04/2025 20:05, David Brown wrote:

    C rarely makes things more complicated without a good reason.

    C usually makes things more complicated without a good reason!

    Nope.


    Here's one example, of dozens, of perfectly legal C:

       long unsigned const long const const typedef int A;
       int long unsigned const long const const typedef A;
       long unsigned const long const typedef int A;
       .....


    That is not more complicated, nor is it without good reason.

    Huh? That demonstrates several things:

    1 That the same identifier can be redeclared multiple times

    Many types of declarations can be repeated, as long as they define the
    same identifier to be the same thing.  If you want the details, they
    are in section 6.7 of the standard.


    2 That 'typedef' needn't be on the left, but can be anywhere in the
    middle of a type spec

    Correct.  Putting it anywhere other than the left may be disallowed
    sometime in the future (it is an "obsolescent feature"), but it is
    currently supported in C.


    3 That 'const' can also be anywhere inside the type spec

    Correct.


    4 That duplicate 'const's are tolerated

    Correct.


    5 That the three tokens ('int', 'unsigned' and two 'long's) denoting
    the type can be be any order (and mixed up with other attributes)


    Correct.

    You seem to think that allowing a variation in the way a declaration
    is made makes the feature "more complicated".  That is simply
    incorrect. The feature - the syntax and the rules in the language
    definition - are /less/ complicated because of this flexibility.  It
    means the syntax here can be, as given in 6.7p1 :

    declaration-specifiers:
         storage-class-specifier declaration-specifiers opt
         type-specifier declaration-specifiers opt
         type-qualifier declaration-specifiers opt
         function-specifier declaration-specifiers opt
         alignment-specifier declaration-specifiers opt

    That always reads to me like 'lots of twisty windy passages, all alike'.

    Try reading it without your usual anti-C prejudice. Perhaps read the
    whole section of the standard.


    If the order were to be strictly specified, there would need to be a
    half-dozen more named and defined specifier lists in the syntax.

    This is the similar feature for my syntax, a bit of BNF:

      typedef = [scopeattr] 'type' name = typespec

    It does a bit more than C's 'typedef' in that such names can be
    exported, to render them visible to modules that import this one.


    The C syntax for declarations here is for /all/ declarations in C. It's
    not just for typedefs in a simple little toy language. (And yes, if you
    are going to make absurd claims about your language in comparison to C,
    you can expect to hear that it is a toy in comparison C.)


    That makes it pretty complicated to me! And I can't see that any of
    these are necessary.

    No one suggested it was at all necessary.

    /You/ did: "That is not more complicated, nor is it without good reason."

    You just quoted me - at no point did I say it was "necessary".

    Are you still surprised that sometimes people say you are trolling or lying?

    I didn't give the slightest reason to suggest the syntax of C's
    declarations was necessary. Nor did I suggest that I like C's rules
    here - on the contrary, I have made it clear that I'd prefer a stricter ordering. But C is not a language I designed, nor is it designed for my
    needs alone.


    What are those good reasons, that it makes code more readable? That it
    is easier to describe in a grammar?

    That is, as I have already said, a good reason for this. It is also
    more flexible - some people like that. Remember also that not all C
    code is written out by hand - some is generated, some is also the result
    of macro expansion. It is a language designed to work well for a vast
    number of people in a vast number of circumstances - not a plaything for
    a single person.

    That it makes it easier to parse?


    Who cares? That's irrelevant to the language design, except for toys
    where the only user is the person who writes the tools.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Scott Lurndal on Fri Apr 11 15:24:43 2025
    scott@slp53.sl.home (Scott Lurndal) writes:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 4/10/25 18:49, Keith Thompson wrote:
    ...
    Do you have a URL for a PDF C89 Rationale?

    No, I have it on disk, but I have no idea where I downloaded it from. As
    a general rule, I download documents like that after seeing links to
    them posted in usenet messages. It's current name is "C89.pdf", but I >>probably renamed it from something less descriptive. Anyone who wants a >>copy of unknown provenance, let me know.

    google sez:

    http://port70.net/%7Ensz/c/c89/

    John Mashey's thread there on 'long long' is intresting, particularly point 4) weighing LLP64 (Windows) vs LP64 (unix). We had several discussions
    during the Large File Summit about 64-bit C data types, somewhat heated
    at times - but the existing implementations at the time were all LP64 which won.

    He also touches on a future 64 bit -> 128 bit transition, which is still
    as far away now as it was three decades ago :-)

    Aug 1995:

    "I think I have good reason to believe that 128-bit-integer
    machines are 25 years away, i.e., longer than the existence of C..."
    - John Mashey

    "|> nightmares. Thus, "long long" is attractive *now*, but will cause
    |> problems
    |> with 128-bit architectures. 32-bit machines started to arrive around 1978
    |> and 64-bit machines around 1991 (my dates are approximate). 128-bit
    |> machines will become available around 2004."
    - Frank Farance

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Scott Lurndal on Fri Apr 11 18:46:48 2025
    On Fri, 11 Apr 2025 15:24:43 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    scott@slp53.sl.home (Scott Lurndal) writes:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 4/10/25 18:49, Keith Thompson wrote:
    ...
    Do you have a URL for a PDF C89 Rationale?

    No, I have it on disk, but I have no idea where I downloaded it
    from. As a general rule, I download documents like that after
    seeing links to them posted in usenet messages. It's current name
    is "C89.pdf", but I probably renamed it from something less
    descriptive. Anyone who wants a copy of unknown provenance, let me
    know.

    google sez:

    http://port70.net/%7Ensz/c/c89/

    John Mashey's thread there on 'long long' is intresting, particularly
    point 4) weighing LLP64 (Windows) vs LP64 (unix). We had several
    discussions during the Large File Summit about 64-bit C data types,
    somewhat heated at times - but the existing implementations at the
    time were all LP64 which won.

    He also touches on a future 64 bit -> 128 bit transition, which is
    still as far away now as it was three decades ago :-)

    Aug 1995:

    "I think I have good reason to believe that 128-bit-integer
    machines are 25 years away, i.e., longer than the existence of
    C..."
    - John Mashey

    "|> nightmares. Thus, "long long" is attractive *now*, but will
    cause |> problems
    |> with 128-bit architectures. 32-bit machines started to arrive
    around 1978 |> and 64-bit machines around 1991 (my dates are
    approximate). 128-bit |> machines will become available around
    2004."
    - Frank Farance

    Even if Moore's law was still in effect, the time distance between 64
    and 128 is still twice longer than between 32 nad 64.
    Besides, 32->64 was unusually quick. 4 times smaller 24->32 transition
    took about the same time.
    Of course, in reality Moore's low is not working for quite some time.

    Or, may be, they were thinking about bitness not in terms of # bits in
    directly accessible virtual address space?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to James Kuyper on Fri Apr 11 12:20:00 2025
    On 4/10/25 20:40, James Kuyper wrote:
    ...
    "Two declarations of structure, union, or enumerated types which ... use different tags declare distinct types. Each declaration of a structure, union, or enumerated type which does not include a tag declares a
    distinct type." (6.7.2.3p9).
    ...

    I get the impression that the reason why the rules for compatible
    struct, union, and enumerated types were defined the way they are might
    not be obvious.
    In C, within a single translation unit, there are three ways to define a struct, union, or enumeration exactly once, and then use that type in
    multiple locations:
    1. Define the type with a tag, and then use that tag anywhere within its
    scope to refer to the definition.
    2. Define the type with a typedef, and then use that typedef anywhere
    withing it's scope to refer to the definition.
    3. Define the type in the "type-specifier" of a declaration with
    multiple declarators. All of the declarators will share the definition
    of that type.

    Because these methods for sharing a type definition exist, the type compatibility rules were designed on the assumption that anybody who
    defines two distinct types must have intended them to be distinct, even
    if the definitions of those types are identical. It would therefore be a logical error to use one of those types in a context where the other was intended. even though the machine code to read and write those types
    would be identical. That's the reason such types are not considered
    compatible.

    However, none of those techniques would be sufficient to allow use of
    such a type to communicate between different translation units. Types
    defined in two different translation units are necessarily distinct
    types, even if defined identically. That's why there's a special rule
    that allows distinct types in different translation units to be
    compatible with each other, but only if their definitions meet certain requirements. They must be essentially identical, except that member
    types are allowed to be compatible, rather than exactly the same - which
    is necessary because, for user-defined types, they can't be the same in different translation units. The most significant difference allowed by
    this rule is that in one definition, a member's type can be an
    enumerated type, while in the other definition, the same name identifies
    member with the underlying type of that enumerated type. I don't think
    that was a desired consequence, just a side-effect of the way the rule
    had to be worded.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Michael S on Fri Apr 11 12:27:03 2025
    On 4/9/25 06:04, Michael S wrote:
    On Wed, 9 Apr 2025 11:42:36 +0200
    David Brown <david.brown@hesbynett.no> wrote:


    In C, if you declare two structs in the same translation unit with
    the same field types and the same field names, they are still
    different types.

    That is clear for structs with tags. Less clear for tagless structs
    that have exactly the same fields.

    "Two declarations of structure, union, or enumerated types which are in different scopes or use different tags declare distinct types. Each
    declaration of a structure, union, or enumerated type which does not
    include a tag declares a distinct type." (6.7.2.3p9)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Fri Apr 11 17:56:30 2025
    On 11/04/2025 16:24, David Brown wrote:
    On 11/04/2025 16:50, bart wrote:

    declaration-specifiers:
         storage-class-specifier declaration-specifiers opt
         type-specifier declaration-specifiers opt
         type-qualifier declaration-specifiers opt
         function-specifier declaration-specifiers opt
         alignment-specifier declaration-specifiers opt

    That always reads to me like 'lots of twisty windy passages, all alike'.

    Try reading it without your usual anti-C prejudice.  Perhaps read the
    whole section of the standard.


    If the order were to be strictly specified, there would need to be a
    half-dozen more named and defined specifier lists in the syntax.

    This is the similar feature for my syntax, a bit of BNF:

       typedef = [scopeattr] 'type' name = typespec

    It does a bit more than C's 'typedef' in that such names can be
    exported, to render them visible to modules that import this one.


    The C syntax for declarations here is for /all/ declarations in C.  It's
    not just for typedefs in a simple little toy language.

    That's not right. You pasted part of 6.7p1. The full syntax for
    declarations comprises all of 6.7.p1, plus 6.7.1p1, 6.7.2p1, 6.7.2p2 (constraints to do with the ordering of long, int etc), 6.7.2.1,
    6.7.2.2, 6.7.3, 6.7.6, 6.7.7, and 6.7.8.


    (And yes, if you
    are going to make absurd claims about your language in comparison to C,
    you can expect to hear that it is a toy in comparison C.)

    Really? Please show /any/ declaration in C that I can't write in mine,
    but in a saner and less convoluted manner. Please define /any/ data
    structure that I can't express.

    I could spend all day showing absurdity after absurdity in C. And you're
    saying /my/ language is a toy?!

    My language /has/ a module scheme. All that palaver about type
    compatability just doesn't arise, because of careful language design.

    My language /has/ the ability to import and export types, structs,
    enums, macros; anything that can be named.

    My language /has/ named and default arguments. It /has/ reference
    parameters. It /has/ multiple function returns.

    My language /has/ embedded text and binary files (and in a far simpler
    manner than proposed for C23).

    Lots more, and it does it with a sane syntax

    Still think it's a toy?

    (Silly question, of source you will say Yes.)

    That it makes it easier to parse?


    Who cares?  That's irrelevant to the language design, except for toys
    where the only user is the person who writes the tools.

    Humans have to parse it too. C must be the only non-esoteric language
    where you need to use third-party tools (CDECL etc) to make sense of type-declarations. Either that or follow complex spirular algorithms to
    decade them.

    A complete fail in my view.

    Yes, your tools (thanks to 1000s of man-years of effort) are superior
    and more expansive that any of mine**, but your language is still a
    turd, sorry. All those tools can do is polish it.

    (** in some ways, but not in the ways /I/ value.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Fri Apr 11 10:07:56 2025
    bart <bc@freeuk.com> writes:

    On 09/04/2025 23:07, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    On 09/04/2025 00:27, Tim Rentsch wrote:

    bart <bc@freeuk.com> writes:

    If you want to make a point or ask a question about C code,
    SHOW THE CODE. And show all of it. Don't make people guess by
    showing only some of the code or by giving just a description.

    I'm showing the code but you keep snipping it! [...]

    No, I don't. Don't be so obtuse. I included the code I was
    originally commenting on, in my first followup. My comment about
    showing code was about your second posting. Let me repeat the
    two important paragraphs (quoted above) taken from that posting:

    I get an incompatible error (from the example you snipped)
    even when I remove both struct tags.

    The phrase "even when I remove both struct tags" describes code, it
    doesn't show the code.

    I showed this example a few lines later [in an earlier posting]
    which has both struct tags omitted:

    There is a simple lesson that you need to learn:

    Please don't be patronising. We are not kids in your PL class.

    I'm sorry you feel that way. I was trying to be helpful.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to James Kuyper on Fri Apr 11 17:30:30 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 4/10/25 20:40, James Kuyper wrote:
    ...
    "Two declarations of structure, union, or enumerated types which ... use
    different tags declare distinct types. Each declaration of a structure,
    union, or enumerated type which does not include a tag declares a
    distinct type." (6.7.2.3p9).
    ...

    I get the impression that the reason why the rules for compatible
    struct, union, and enumerated types were defined the way they are might
    not be obvious.
    In C, within a single translation unit, there are three ways to define a >struct, union, or enumeration exactly once, and then use that type in >multiple locations:
    1. Define the type with a tag, and then use that tag anywhere within its >scope to refer to the definition.
    2. Define the type with a typedef, and then use that typedef anywhere
    withing it's scope to refer to the definition.
    3. Define the type in the "type-specifier" of a declaration with
    multiple declarators. All of the declarators will share the definition
    of that type.

    Go back far enough:
    4. MoS (Members of Struct) are global symbols that can be used
    with a pointer of any type.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Michael S on Fri Apr 11 17:22:37 2025
    On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:
    On Thu, 10 Apr 2025 17:59:15 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:


    An understanding of what "compatible types" means.

    Bart didn't say that types are compatible or non-compatible.
    He said that they are 'compatible enough'. That is not terminology of C Standard, but terminology of his own. And he seems to understand it.

    In my own translation, 'compatible enough' means that when these structs
    are accessed then any sane or even semi-sane compiler will generate code
    that will have the same effect as in case of access through structures
    with literally identical declarations.

    so struct { long x; } and struct { int x; } are compatible enough,
    in situations that are portable enough.

    A sphere and a cow are similar enough, ...

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Fri Apr 11 20:29:40 2025
    On 11/04/2025 18:56, bart wrote:
    On 11/04/2025 16:24, David Brown wrote:
    On 11/04/2025 16:50, bart wrote:

    declaration-specifiers:
         storage-class-specifier declaration-specifiers opt
         type-specifier declaration-specifiers opt
         type-qualifier declaration-specifiers opt
         function-specifier declaration-specifiers opt
         alignment-specifier declaration-specifiers opt

    That always reads to me like 'lots of twisty windy passages, all alike'.

    Try reading it without your usual anti-C prejudice.  Perhaps read the
    whole section of the standard.


    If the order were to be strictly specified, there would need to be a
    half-dozen more named and defined specifier lists in the syntax.

    This is the similar feature for my syntax, a bit of BNF:

       typedef = [scopeattr] 'type' name = typespec

    It does a bit more than C's 'typedef' in that such names can be
    exported, to render them visible to modules that import this one.


    The C syntax for declarations here is for /all/ declarations in C.
    It's not just for typedefs in a simple little toy language.

    That's not right. You pasted part of 6.7p1. The full syntax for
    declarations comprises all of 6.7.p1, plus 6.7.1p1, 6.7.2p1, 6.7.2p2 (constraints to do with the ordering of long, int etc), 6.7.2.1,
    6.7.2.2, 6.7.3, 6.7.6, 6.7.7, and 6.7.8.


    It is the full syntax for declaration specifiers - the matter under
    discussion. I did not include initialisation, static assertions, the
    syntax for identifiers, or any number of different parts of the syntax of C.


    (And yes, if you
    are going to make absurd claims about your language in comparison to
    C, you can expect to hear that it is a toy in comparison C.)

    Really? Please show /any/ declaration in C that I can't write in mine,
    but in a saner and less convoluted manner. Please define /any/ data
    structure that I can't express.


    I have no idea about your language, nor do I care.

    I could spend all day showing absurdity after absurdity in C. And you're saying /my/ language is a toy?!

    Yes.

    It is a toy because it is a personal little language for your ego.
    There is no specification or description of it, there are no serious implementations of it, there are no users of it other than you, there is
    no consistency in it - you change your language and your tools to suit
    the program you are writing at the time, and regularly don't know
    yourself how it works or what features it has. It is in no sense "battle-tested" - the only user writes code that he knows will not cause trouble. Thus you avoid all the issues that real languages have to
    handle - real programs written by many different people for many
    different purposes.

    The fact that you have made a living using your language(s) does not
    mean they are not toys.

    You are like an Esperanto fanatic trying to tell people their language
    is so much better than English because the spelling is consistent, so
    the world would be a better place if we all switched over. Except in
    your case, you are the only one who speaks the language.


    That it makes it easier to parse?


    Who cares?  That's irrelevant to the language design, except for toys
    where the only user is the person who writes the tools.

    Humans have to parse it too. C must be the only non-esoteric language
    where you need to use third-party tools (CDECL etc) to make sense of type-declarations. Either that or follow complex spirular algorithms to decade them.


    I have never heard of anyone other than you who views cdecl as a
    necessity. A tiny proportion of C programmers find it helpful when
    dealing with code written by others - especially if the code is written
    in a poor style and the reader is relatively new to C.


    If you want to learn more about C, ask about it here - if you want to
    promote your own language, perhaps comp.lang.misc is a better place.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ike Naar@21:1/5 to bart on Fri Apr 11 19:45:58 2025
    On 2025-04-11, bart <bc@freeuk.com> wrote:
    I haven't remarked on:

    7 That you need 3/4 tokens to specify a simple u64 type.

    On the PC in front of me, two tokens are sufficient:

    unsigned long

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Fri Apr 11 20:46:39 2025
    On 11/04/2025 18:22, Kaz Kylheku wrote:
    On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:
    On Thu, 10 Apr 2025 17:59:15 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:


    An understanding of what "compatible types" means.

    Bart didn't say that types are compatible or non-compatible.
    He said that they are 'compatible enough'. That is not terminology of C
    Standard, but terminology of his own. And he seems to understand it.

    In my own translation, 'compatible enough' means that when these structs
    are accessed then any sane or even semi-sane compiler will generate code
    that will have the same effect as in case of access through structures
    with literally identical declarations.

    so struct { long x; } and struct { int x; } are compatible enough,
    in situations that are portable enough.


    What about struct {long x;} and struct {int64_t x;}?

    Whether they are compatible seems to be depend on platform.

    Or rather, whether or not int64_t happens to defined on top of 'long' or
    'long long'.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Ike Naar on Fri Apr 11 16:00:09 2025
    On 4/11/25 15:45, Ike Naar wrote:
    On 2025-04-11, bart <bc@freeuk.com> wrote:
    I haven't remarked on:

    7 That you need 3/4 tokens to specify a simple u64 type.

    On the PC in front of me, two tokens are sufficient:

    unsigned long
    ,
    That type is not guaranteed to be exactly 64 bits long, nor is it
    guaranteed to be at least 64 bits long. That it happens to be 64 bits on
    a particular implementation isn't especially useful, at least not as far
    as portable code is concerned.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Fri Apr 11 22:24:03 2025
    On 11/04/2025 19:29, David Brown wrote:
    On 11/04/2025 18:56, bart wrote:

    That's not right. You pasted part of 6.7p1. The full syntax for
    declarations comprises all of 6.7.p1, plus 6.7.1p1, 6.7.2p1, 6.7.2p2
    (constraints to do with the ordering of long, int etc), 6.7.2.1,
    6.7.2.2, 6.7.3, 6.7.6, 6.7.7, and 6.7.8.


    It is the full syntax for declaration specifiers - the matter under discussion.  I did not include initialisation, static assertions, the
    syntax for identifiers, or any number of different parts of the syntax
    of C.

    So how much of:

    long unsigned const long const const typedef int A;

    does it cover? I can see that it doesn't cover any of the terminals (all
    tokens up to 'A'); the identifier ('A'); or the semicolon.

    I suggest there's more missing that you seem to think.


    I could spend all day showing absurdity after absurdity in C. And
    you're saying /my/ language is a toy?!

    Yes.

    It is a toy because it is a personal little language for your ego. There
    is no specification or description of it, there are no serious implementations of it, there are no users of it other than you, there is
    no consistency in it - you change your language and your tools to suit
    the program you are writing at the time, and regularly don't know
    yourself how it works or what features it has.  It is in no sense "battle-tested" - the only user writes code that he knows will not cause trouble.  Thus you avoid all the issues that real languages have to
    handle - real programs written by many different people for many
    different purposes.

    Yes, it is partly experimental. But how does that invalidate the
    usefulness of a particular feature?

    How does that invalidate its sane left-to-right type syntax compared to
    the nightware syntax that C uses?

    Even an experimental language can throw up dozens of useful features and improvements.

    'Battle-testing' is more useful for getting solid implementations,
    finding bugs, filling in patches in coverage. But I am not providing an implementation, only ideas and comparisons of language features.

    You were talking about named arguments, well here is how /my/ version
    works (which i first tried 30 years ago); here is the benefit of my
    experience; here is how I solved the same problems you might have.

    My language has been in use for over 40 years, and it has been
    self-hosted in a continuous chain over the same period. That's some toy.

    It has also managed to evolve a lot more than C has, BECAUSE there are
    few users and there is a small codebase.




    You are like an Esperanto fanatic trying to tell people their language
    is so much better than English because the spelling is consistent, so
    the world would be a better place if we all switched over.  Except in
    your case, you are the only one who speaks the language.

    (Huh. I grow up, in the UK, in a family and circle of relatives where we
    spoke our own obscure dialect from a region of Italy. We seemed to get by.)

    Computer languages are different: if you have a compiler for a private language, then it can do anything. Plus it is possible to write
    conversion programs to advantage of tooling available for the more
    mainstream language.


    I have never heard of anyone other than you who views cdecl as a
    necessity.  A tiny proportion of C programmers find it helpful when
    dealing with code written by others - especially if the code is written
    in a poor style and the reader is relatively new to C.

    Rubbish. Everyone finds C declaration syntax a nightmare.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Fri Apr 11 18:24:41 2025
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.

    I don't.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Sat Apr 12 00:13:30 2025
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.

    Rubbish. I find C declaration syntax annoying, not a "nightmare".


    Annoying would be having to get letter case or punctuation just right.

    But C typepecs can go far beyond it. I can just about do arrays of
    pointers, or pointers to arrays. Anything more complicated is pretty
    much trial and error.

    In an example in my post which I then deleted (DB will just ignore
    examples), I wanted to create an array of 10 pointers to functions that
    take an int and return an int.

    I started with something like this that I recalled from memory
    (otherwise it would be even more wrong):

    int (*A)[10](int);

    but CDECL said it was something different. I tried one or two more
    combinations before I gave up and asked CDECL to tell me the type from
    the English.

    C type syntax is just not fit for purpose. This is not how a language is
    meant to work, and this is not supposed to be the hard part of a
    language! Syntax should be the easy bit.

    This is that English spec (with the significant bits numbered):

    array 10 pointer to func take int return int
    1 2 3 4 5 6

    Here is what CDECL came up with:

    int (*A[10])(int);
    6 3 1 2 4 5 (Not sure which bit is the '4')

    The numbers below show the correspondence with the English. You can see
    it's all over the place. This is how I'd write it in another actual
    language syntax:

    [10]ref func(int)int A
    1 2 3 4 5 6

    Notice that that numbering here exactly corresponds to the English. THIS
    is how easy it should be. I could write this as fast as I can type.

    Further, the variable name is well out of it. In my syntax, any names go
    on the right; names on the left is also popular. But no language other
    than C and C++ has names IN THE MIDDLE.

    So, yeah, a 'nightmare' is more apt than 'annoying'.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Sat Apr 12 02:27:21 2025
    On 12/04/2025 00:59, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.
    Rubbish. I find C declaration syntax annoying, not a "nightmare".

    Annoying would be having to get letter case or punctuation just right.
    [...]
    So, yeah, a 'nightmare' is more apt than 'annoying'.

    Bart, bart, bart.





    You made a false statement about how *everyone* feels about
    C's declaration syntax.

    So what would be a true statement? That everyone finds it at least midly annoying?

    C type syntax is famous for being difficult and confusing; I think most
    will agree about that. Even the creators said so.

    This was the discussion:

    BC:
    Humans have to parse it too. C must be the only non-esoteric language
    where you need to use third-party tools (CDECL etc) to make sense of type-declarations. Either that or follow complex spirular algorithms to [decode] them.

    DB:
    I have never heard of anyone other than you who views cdecl as a necessity.

    So, is that last statement true or not? I didn't say it was a necessity,
    but that you need to use such tools or special methods to understand
    them. And clearly, that would be the more complicated ones; people can
    usually cope with 'int'.

    I replied to one sweeping statement with another.

    We all know that you consider it to be
    a nightmare. I don't think I've ever said or implied that you
    shouldn't feel that way. You think everyone *should* find it
    a nightmare? Fine.

    You cannot possibly be so deluded that you think everyone feels
    the same way as you do, and we're all lying about it.

    There are plenty of resources like this about:

    http://www.unixwiz.net/techtips/reading-cdecl.html

    https://news.ycombinator.com/item?id=42564861

    Why are they even necessary?


    (That last link includes this comment: "If you need a program to help
    you read C programs, that suggests a serious flaw in C." I have to give
    quotes from others because everybody here thinks it is only me.

    Here's a couple from Ritchie and Stroustrop: https://dev.to/pauljlucas/musings-on-c-c-declarations-169o)


    You want to be treated better? Stop making deeply silly statements.

    DB was making light of the type syntax issue and pretty much dismissed
    it out of hand. How should I have responded?

    Not that it would cut any ice with him. Nothing is ever that complicated
    or too onerous or too slow or too over the top or too badly designed or ...

    I suggest also that you stop taking throwaway comments too literally.
    Yet, there is probably more truth in my remark than in David's.

    You might also consider that while many features of C have been copied,
    I don't know of any language that has copied its type syntax.

    I wonder why? Do you think the designers had an opinion about it closer
    to mine, or to David Brown's?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Sat Apr 12 02:43:45 2025
    On 2025-04-12, bart <bc@freeuk.com> wrote:
    On 12/04/2025 00:59, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.
    Rubbish. I find C declaration syntax annoying, not a "nightmare".

    Annoying would be having to get letter case or punctuation just right.
    [...]
    So, yeah, a 'nightmare' is more apt than 'annoying'.

    Bart, bart, bart.


    You made a false statement about how *everyone* feels about
    C's declaration syntax.

    So what would be a true statement? That everyone finds it at least midly annoying?

    C type syntax is famous for being difficult and confusing; I think most
    will agree about that. Even the creators said so.

    If you had a function that takes an int, that returned a pointer to an
    array, how would you pass in 42, and then get at the third element?

    f(42) // gets the pointer to the array

    (*f(42)) // designates the array

    (*f(42))[2] // gets at the third element.

    Ok, now declaring a function of int, which returns a pointer to an array
    of 16 elements:

    (*f(int))[16];

    Notice any resemblance? The 42 argumet has changed to a type specifier
    for the corresponding parameter type. The array reference turns into
    the size. Minor!

    We need a type specifier to the elements:

    double (*f(int))[16];

    Declaration follows use: it's not just a slogan, it's real!

    If you don't like the declaration syntax, it's possibly because
    you don't like the expression syntax for working with pointer
    dereferencing and arrays, which it mirrors. (You not liking
    C expression syntax: billion to one odds, right?)

    Making the type operators in the declarator resemble the unary
    and postfix operators of the use is kind of clever though!

    IDEA: maybe you would like the "dedclaration follows use", if it was
    rendered over a different expression grammar in which pointer, arrays
    and whatnot work the way you like. If didn't dislike the "use",
    you might not dislike "declaration follows use".

    Now, from this "envelope shape":

    double (.......)[16];

    we know that whatever ..... is, it is an array of 16 doubles.
    This .... is called a "type hole" by functional programmers working
    in Haskell and whatnot.

    If we replace the hole with a name like abc:

    double (abc)[16];

    then what is being declared is that name. We get an object abc which is
    such an array. The parentheses are then unnecessary and we can drop
    them.

    If we plug in *f(int) instead of abc, then *f(int) isn't what is
    being declared: f is. But we know that when this f is called, and the
    pointer it returns is dereferenced, we get an array. We know that from
    its correspondence to the ..... hole in the expression. Thus the
    function mut be returning a pointer to an array (of 16 double).

    The parentheses remain necessary then because the * on the left
    has lower precedence than the postfixes (int) and [16].

    There is kind of minor algebra to it all, where you can
    play these substitution games.

    The declarator type constructors like the (...) function
    parentheses, [...] array brackets and the prefix * pointer are not
    called operators in ISO C, but they mimic the unary and postfix
    operators and have the same associativity and precedence. Moreover, the parentheses function the same way, for overriding precedence.

    If you know that postfix binds tighter than unary, but parentheses
    override, that's 90% of it.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sat Apr 12 06:33:41 2025
    bart <bc@freeuk.com> writes:

    Rubbish. Everyone finds C declaration syntax a nightmare.

    There's people (also a couple regulars in this Usenet group) that are constructing sentences of various generalizing forms (like yours, and
    also with other forms and contents; like concerning tools, people).

    I think it should be unnecessary to say that such sentences are often
    just projections, or wishful thinking, or unnecessary rhetoric moves,
    rarely backed up by facts, and typically also just not true (at least
    in their typical absolute and generalized form).

    On 11/04/2025 22:36, Keith Thompson wrote:

    Rubbish. I find C declaration syntax annoying, not a "nightmare".

    There's so many attributes!

    I (for example) think they're (in some respects) "badly designed".

    On 12.04.2025 01:13, bart wrote:

    Annoying would be having to get letter case or punctuation just right.

    Are you now _defining_ what "annoying" *commonly* means? Or what it
    *has to* mean [in your opinion]?

    Please try to decouple your personal sight from the clear facts and
    formulate your statements appropriately. - Unless your intention is
    to just inflict communication disruptions.


    But C typepecs can go far beyond it. I can just about do arrays of
    pointers, or pointers to arrays. Anything more complicated is pretty
    much trial and error.

    I understand you have problems with it. And I'm not astonished...


    In an example in my post which I then deleted (DB will just ignore
    examples), I wanted to create an array of 10 pointers to functions that
    take an int and return an int.

    Because of "C"'s somewhat convoluted (IMO "bad") syntax it might
    help you to make use of 'typedef's to incrementally construct your
    types! - That's at least what I did when I wanted to create better
    legible "C" code in cases of overly complex type structures. - It's
    also a general method to handle complexity.


    I started with something like this that I recalled from memory
    (otherwise it would be even more wrong):

    int (*A)[10](int);

    but CDECL said it was something different. I tried one or two more combinations before I gave up and asked CDECL to tell me the type from
    the English.

    C type syntax is just not fit for purpose.

    Reality shows that it *is* (de facto) "fit for purpose". (Probably
    not yours. - I'm still wondering why you act in a "C" newsgroup.)

    This is not how a language is
    meant to work, and this is not supposed to be the hard part of a
    language! Syntax should be the easy bit.

    I agree that language designers can do a much better job. (There's
    quite some examples for languages with an IMO "better" syntax.)


    This is that English spec (with the significant bits numbered):

    array 10 pointer to func take int return int

    My English might not be good enough, but in my book this is not an
    English sentence and for me not (not much) easier to understand than
    the "C" syntax below; the latter can at least (with its formality!)
    be _understood_ by an experienced "C" programmer as a well defined
    code pattern.

    Guessing: An array with 10 elements that are pointers to functions
    that take an 'int' parameter and return an 'int' value?

    1 2 3 4 5 6

    Here is what CDECL came up with:

    int (*A[10])(int);
    6 3 1 2 4 5 (Not sure which bit is the '4')

    (This opening parenthesis syntactically indicates the function, as
    also indicated by the numberings above. - Or so I'd think. - No?)


    The numbers below show the correspondence with the English. You can see
    it's all over the place. This is how I'd write it in another actual
    language syntax:

    [10]ref func(int)int A
    1 2 3 4 5 6

    And what should that mean? - You know, since I haven't identified
    your "English sentence" as a clearly understandable English sentence
    I'm lost here, since I don't know that (your?) language. - For the
    "C" case I could at least read the "C" specs (in case I got lost).

    Assumed that my guess above was correct that's quite equivalent to
    the Algol 68 form

    [10] REF PROC (INT) INT a

    but in Algol 68 you'd probably rather use it without the unnecessary "pointer"/reference just as in

    [10] PROC (INT) INT a

    which - as you seem to like clearness - is even simpler!


    Notice that that numbering here exactly corresponds to the English. THIS
    is how easy it should be. I could write this as fast as I can type.

    Further, the variable name is well out of it. In my syntax, any names go
    on the right; names on the left is also popular. But no language other
    than C and C++ has names IN THE MIDDLE.

    Yes, as said, this mixing I also think to have been bad idea. - But
    the "C" language was originating in a culture where people seem to
    think that mixing date components (like "April 12th 2025") is also
    natural[*] or at least an appropriate usable representation. :-)

    [*] I have an idea how it came to that format, but that's speculation.


    So, yeah, a 'nightmare' is more apt than 'annoying'.

    Again, ITYM "for you". - Yes, we know that.

    Use type compositions (in case you are actually programming in "C")!

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sat Apr 12 12:00:41 2025
    On 12/04/2025 05:33, Janis Papanagnou wrote:
    bart <bc@freeuk.com> writes:

    Rubbish. Everyone finds C declaration syntax a nightmare.

    Because of "C"'s somewhat convoluted (IMO "bad") syntax it might
    help you to make use of 'typedef's to incrementally construct your
    types!

    This is a third kind of workround. All of them should be unnecessary.
    Unless the type really is complicated and needs to be decomposed anyway, whatever the syntax.

    C type syntax is just not fit for purpose.

    Reality shows that it *is* (de facto) "fit for purpose". (Probably
    not yours. - I'm still wondering why you act in a "C" newsgroup.)

    I 100% agree with what C is capable of as a systems language. The level
    of its type system, its size, its scope, its flexibility (to an extent)

    But I also 100% hate its syntax and various other bits and pieces. (OK,
    about 80% then.)

    So I've been avoiding using it for many decades. First because it wasn't practical (acquiring or using it). Then because I wanted to use it but
    it was just too dreadful. And later I couldn't avoid it because it comes
    up in every API for every library, or the library comes as C source code.

    And APIs use C type syntax. So, yeah, I am entitled to an opinion about it.


    This is not how a language is
    meant to work, and this is not supposed to be the hard part of a
    language! Syntax should be the easy bit.

    I agree that language designers can do a much better job. (There's
    quite some examples for languages with an IMO "better" syntax.)


    This is that English spec (with the significant bits numbered):

    array 10 pointer to func take int return int

    My English might not be good enough, but in my book this is not an
    English sentence and for me not (not much)

    I gave the full English description further up.

    Guessing: An array with 10 elements that are pointers to functions
    that take an 'int' parameter and return an 'int' value?

    Very good. It's not a guess though is it? If you extract the essential
    parts out, you get:

    array 10 pointers functions take int return int

    The same exercise with mine (both versions) yield:

    array 10 pointers functions take int return int
    array 10 pointer func take int return int

    There's not much in it.


    1 2 3 4 5 6

    Here is what CDECL came up with:

    int (*A[10])(int);
    6 3 1 2 4 5 (Not sure which bit is the '4')

    (This opening parenthesis syntactically indicates the function, as
    also indicated by the numberings above. - Or so I'd think. - No?)

    Not necessarily. This is a valid declaration in C:

    int (A);

    That opening parentheses is just noise. (I guess you just learned
    something new about C today?)




    The numbers below show the correspondence with the English. You can see
    it's all over the place. This is how I'd write it in another actual
    language syntax:

    [10]ref func(int)int A
    1 2 3 4 5 6

    And what should that mean? - You know, since I haven't identified
    your "English sentence" as a clearly understandable English sentence



    I'm lost here, since I don't know that (your?) language. - For the
    "C" case I could at least read the "C" specs (in case I got lost).

    A could of years ago I had a bit of fun with it so that my allowed this
    syntax:

    array [10] pointer to function (int) returning int A

    Still have trouble with it? You shouldn't do since this is pretty much
    what CDECL produces or can understand. I didn't keep this because such
    syntax is too much.

    Assumed that my guess above was correct that's quite equivalent to
    the Algol 68 form

    [10] REF PROC (INT) INT a

    So you do get it (maybe I should have read this far first). Yes, it
    directly comes from Algol68.

    But left-to-right type specifications must be common now everywhere.

    but in Algol 68 you'd probably rather use it without the unnecessary "pointer"/reference just as in

    [10] PROC (INT) INT a

    which - as you seem to like clearness - is even simpler!

    This is not as clear; the intent is to have a reference to a function;
    not an array of actual functions. For example:

    []ref func(int) int := (F, G, H)

    It is initialised to functions F, G, H which are defined elsewhere.
    Maybe in Algol68 you can have actual function definitions in that list.
    But not in mine, which was created as a leaner, simpler and more
    transparent systems language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Sat Apr 12 12:50:07 2025
    On 12/04/2025 03:43, Kaz Kylheku wrote:
    On 2025-04-12, bart <bc@freeuk.com> wrote:

    C type syntax is famous for being difficult and confusing; I think most
    will agree about that. Even the creators said so.

    If you had a function that takes an int, that returned a pointer to an
    array, how would you pass in 42, and then get at the third element?

    f(42) // gets the pointer to the array

    (*f(42)) // designates the array

    (*f(42))[2] // gets at the third element.

    Ok, now declaring a function of int, which returns a pointer to an array
    of 16 elements:

    (*f(int))[16];

    Notice any resemblance? The 42 argumet has changed to a type specifier
    for the corresponding parameter type. The array reference turns into
    the size. Minor!

    We need a type specifier to the elements:

    double (*f(int))[16];

    Declaration follows use: it's not just a slogan, it's real!

    I'm sorry, but it doesn't work! The thought processes are entirely
    different between writing expressions, and declaring types. They differ
    in many ways anyway:

    * A typespec needs a base type; an expr doesn't
    * A typespec needs to express the whole thing right up to the base type;
    an expr can be partial
    * A typespec can include 'const' and other attributes; an expr doesn't
    * A typespec uses '*' for pointers, an expr can use '*' or '[]' to deref
    * A typespec uses '[]' for arrays; an expression can choose to use '*'
    to index
    * A typespec uses (*) for function pointers, but an expression can
    choose to omit both that * and the accompanying ().

    Further if you have an expression like (*A)[i] + (*B[i]) + (*C[i]), then
    you necessarily have to elaborate each term, but it shouldn't be
    necessary to repeat that typespec for each in the declarations.

    C doesn't directly have the means to centralise a common type, you have
    to do:

    typedef int (*Arr)[10];
    Arr A, B, C;

    or:
    typeof(int (*)[10]) A, B, C

    Here there is a clear (and clean!) disconnect between each variable, and
    its type. A variable's type shouldn't be something it has to 'wear'
    wrapped around it, so that it literally looks like an expression. That
    would be a bizarre concept.

    But unfortunately people are used to thinking that this is normal:

    int (*A)[10], (*B[10]), (*C)[10];

    Even if you wrote this, perhaps you are passing those pointers to a
    function:

    F(A, B, C)

    Hmm, those terms don't look much like their declarations, do they?!


    If you don't like the declaration syntax, it's possibly because
    you don't like the expression syntax for working with pointer
    dereferencing and arrays, which it mirrors. (You not liking
    C expression syntax: billion to one odds, right?)

    Yes, making deref a prefix op was a bad idea. Postfix is much better
    (but the choice of '*' makes that problematical).

    My examples become (ignoring the unsuitability of '*'):

    int A*[10], B*[10], C*[10];
    A*[i] + B*[i] + C*[i]

    Generally cleaner syntax all round. Maybe people would now use proper pointer-to-array types (T(*)[] in current syntax) instead of the less
    safe T*.

    The -> operator can be dispensed with too: you write P*.m or Q**.m
    instead of the messy (*P).m or P->m or (*Q)->m.

    IDEA: maybe you would like the "dedclaration follows use", if it was
    rendered over a different expression grammar in which pointer, arrays
    and whatnot work the way you like. If didn't dislike the "use",
    you might not dislike "declaration follows use".

    Now, from this "envelope shape":

    double (.......)[16];

    we know that whatever ..... is, it is an array of 16 doubles.
    This .... is called a "type hole" by functional programmers working
    in Haskell and whatnot.

    If we replace the hole with a name like abc:

    double (abc)[16];

    then what is being declared is that name. We get an object abc which is
    such an array. The parentheses are then unnecessary and we can drop
    them.

    If we plug in *f(int) instead of abc, then *f(int) isn't what is
    being declared: f is. But we know that when this f is called, and the

    I'm lost, sorry. Things are getting more complicated, not simpler!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Sat Apr 12 14:39:00 2025
    On 12/04/2025 01:13, bart wrote:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.

    Rubbish.  I find C declaration syntax annoying, not a "nightmare".


    Annoying would be having to get letter case or punctuation just right.

    But C typepecs can go far beyond it. I can just about do arrays of
    pointers, or pointers to arrays. Anything more complicated is pretty
    much trial and error.

    In an example in my post which I then deleted (DB will just ignore
    examples), I wanted to create an array of 10 pointers to functions that
    take an int and return an int.

    If only C had a way to make that simple and clear. Oh, wait - it does.

    typedef int (*FIntInt)(int);

    FIntInt funcs[10];

    If a C programmer - such as yourself - is foolish enough to reject parts
    of the language designed to make coding simpler, safer, clearer and more portable, then I can see how your self-imposed restrictions make your
    coding harder. But the fault lies in the poor use of the language, not
    the language.

    (Typically you would give the function pointer type a name appropriate
    to its use rather than based on the parameter and return types - things
    like "keypress_event".)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Sat Apr 12 12:57:51 2025
    On 2025-04-12, bart <bc@freeuk.com> wrote:
    On 12/04/2025 03:43, Kaz Kylheku wrote:
    On 2025-04-12, bart <bc@freeuk.com> wrote:

    C type syntax is famous for being difficult and confusing; I think most
    will agree about that. Even the creators said so.

    If you had a function that takes an int, that returned a pointer to an
    array, how would you pass in 42, and then get at the third element?

    f(42) // gets the pointer to the array

    (*f(42)) // designates the array

    (*f(42))[2] // gets at the third element.

    Ok, now declaring a function of int, which returns a pointer to an array
    of 16 elements:

    (*f(int))[16];

    Notice any resemblance? The 42 argumet has changed to a type specifier
    for the corresponding parameter type. The array reference turns into
    the size. Minor!

    We need a type specifier to the elements:

    double (*f(int))[16];

    Declaration follows use: it's not just a slogan, it's real!

    I'm sorry, but it doesn't work! The thought processes are entirely
    different between writing expressions, and declaring types. They differ
    in many ways anyway:

    The main difference is that the the expressions are the payload that
    does the work, whereas declarations are just mental overead.

    The thought process is that the C programmer has a data structure
    layout in their mind and can write expressions to navigate through
    it, from the top-level reference down to its leaves.

    But, oh crap, the C programmer has to declare the things they are using
    in that expression.

    C brings a nice simplification here. If you can write the expression to
    access the thing you are imagining, the declaration can be derived
    from that shape.

    * A typespec needs a base type; an expr doesn't
    * A typespec needs to express the whole thing right up to the base type;
    an expr can be partial
    * A typespec can include 'const' and other attributes; an expr doesn't
    * A typespec uses '*' for pointers, an expr can use '*' or '[]' to deref
    * A typespec uses '[]' for arrays; an expression can choose to use '*'
    to index
    * A typespec uses (*) for function pointers, but an expression can
    choose to omit both that * and the accompanying ().

    "Declaration follow use" is not perfect or absolute, but it helps
    exactly with the confusing cases with mlutiple levels of pointers,
    arrays and functions.

    C doesn't directly have the means to centralise a common type, you have
    to do:

    typedef int (*Arr)[10];
    Arr A, B, C;

    or:
    typeof(int (*)[10]) , B, C

    Why would you showing two ways how C has the direct means to centralize
    a common array type, to illustrate the claim that it doesn't?

    Here there is a clear (and clean!) disconnect between each variable, and
    its type. A variable's type shouldn't be something it has to 'wear'
    wrapped around it, so that it literally looks like an expression. That
    would be a bizarre concept.

    If you had thought of it first, you'd think it's brilliant.

    Dennis Ritchie really showed us a nice way to deal with messes
    of pointers, arrays and function pointers.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Sat Apr 12 14:33:04 2025
    On 12/04/2025 13:57, Kaz Kylheku wrote:
    On 2025-04-12, bart <bc@freeuk.com> wrote:
    On 12/04/2025 03:43, Kaz Kylheku wrote:
    On 2025-04-12, bart <bc@freeuk.com> wrote:

    C type syntax is famous for being difficult and confusing; I think most >>>> will agree about that. Even the creators said so.

    If you had a function that takes an int, that returned a pointer to an
    array, how would you pass in 42, and then get at the third element?

    f(42) // gets the pointer to the array

    (*f(42)) // designates the array

    (*f(42))[2] // gets at the third element.

    Ok, now declaring a function of int, which returns a pointer to an array >>> of 16 elements:

    (*f(int))[16];

    Notice any resemblance? The 42 argumet has changed to a type specifier
    for the corresponding parameter type. The array reference turns into
    the size. Minor!

    We need a type specifier to the elements:

    double (*f(int))[16];

    Declaration follows use: it's not just a slogan, it's real!

    I'm sorry, but it doesn't work! The thought processes are entirely
    different between writing expressions, and declaring types. They differ
    in many ways anyway:

    The main difference is that the the expressions are the payload that
    does the work, whereas declarations are just mental overead.

    The thought process is that the C programmer has a data structure
    layout in their mind and can write expressions to navigate through
    it, from the top-level reference down to its leaves.

    But, oh crap, the C programmer has to declare the things they are using
    in that expression.

    C brings a nice simplification here. If you can write the expression to access the thing you are imagining, the declaration can be derived
    from that shape.

    * A typespec needs a base type; an expr doesn't
    * A typespec needs to express the whole thing right up to the base type;
    an expr can be partial
    * A typespec can include 'const' and other attributes; an expr doesn't
    * A typespec uses '*' for pointers, an expr can use '*' or '[]' to deref
    * A typespec uses '[]' for arrays; an expression can choose to use '*'
    to index
    * A typespec uses (*) for function pointers, but an expression can
    choose to omit both that * and the accompanying ().

    "Declaration follow use" is not perfect or absolute, but it helps
    exactly with the confusing cases with mlutiple levels of pointers,
    arrays and functions.

    C doesn't directly have the means to centralise a common type, you have
    to do:

    typedef int (*Arr)[10];
    Arr A, B, C;

    or:
    typeof(int (*)[10]) , B, C

    Why would you showing two ways how C has the direct means to centralize
    a common array type, to illustrate the claim that it doesn't?

    Those aren't direct. The only direct means C has is this form:

    T A, B, C

    when all the type info is concentrated in T. But T can only be a simple
    type, or the name of a user-defined type. (Or, in C23, typeof can be used).

    The problems come when you use modifiers that are applied to either side
    of each name:

    T A, *B, (*C)[10]

    It is these modifiers that are the bits that can be applied in expressions.

    That whole concept was a mistake. Such modifiers belong with the base
    type. That also allows all names declared in the list to share that
    exact same type.

    Here there is a clear (and clean!) disconnect between each variable, and
    its type. A variable's type shouldn't be something it has to 'wear'
    wrapped around it, so that it literally looks like an expression. That
    would be a bizarre concept.

    If you had thought of it first, you'd think it's brilliant.

    Dennis Ritchie really showed us a nice way to deal with messes
    of pointers, arrays and function pointers.

    The simplest function pointer type in C is this:

    void(*)(void)

    The simplest variable declaration is this:

    void(*F)(void)

    C23 (when it is widespread in 10-20 years) allows you to write
    'void(*)()' instead.

    I wouldn't call any of them 'nice'; they all look cryptic.

    I write those two examples as:

    ref proc
    ref proc F

    This comes from Algol68 which predated C by 4 years.

    Now try a more complicated function pointer type...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to David Brown on Sat Apr 12 14:21:45 2025
    On 12/04/2025 13:39, David Brown wrote:
    On 12/04/2025 01:13, bart wrote:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.

    Rubbish.  I find C declaration syntax annoying, not a
    "nightmare".


    Annoying would be having to get letter case or punctuation just
    right.

    But C typepecs can go far beyond it. I can just about do arrays
    of pointers, or pointers to arrays. Anything more complicated
    is pretty much trial and error.

    In an example in my post which I then deleted (DB will just
    ignore examples), I wanted to create an array of 10 pointers to
    functions that take an int and return an int.

    If only C had a way to make that simple and clear.

    But... but... but...!!!

      Oh, wait - it
    does.

    ...Finally!

        typedef int (*FIntInt)(int);

        FIntInt funcs[10];

    Just one tiny point, though. I've never been a fan of hiding
    pointers behind typedefs. I would much prefer:

    typedef int FIntInt(int);

    FIntInt *funcs[10];


    Better to have those *s out in the open, where we can keep an eye
    on them.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Richard Heathfield on Sat Apr 12 15:52:01 2025
    On 12/04/2025 15:21, Richard Heathfield wrote:
    On 12/04/2025 13:39, David Brown wrote:
    On 12/04/2025 01:13, bart wrote:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.

    Rubbish.  I find C declaration syntax annoying, not a "nightmare".


    Annoying would be having to get letter case or punctuation just right.

    But C typepecs can go far beyond it. I can just about do arrays of
    pointers, or pointers to arrays. Anything more complicated is pretty
    much trial and error.

    In an example in my post which I then deleted (DB will just ignore
    examples), I wanted to create an array of 10 pointers to functions
    that take an int and return an int.

    If only C had a way to make that simple and clear.

    But... but... but...!!!

      Oh, wait - it does.

    ...Finally!

         typedef int (*FIntInt)(int);

         FIntInt funcs[10];

    Just one tiny point, though. I've never been a fan of hiding pointers
    behind typedefs. I would much prefer:

    typedef int FIntInt(int);

    FIntInt *funcs[10];


    Better to have those *s out in the open, where we can keep an eye on them.


    C is a flexible language, and also caters for those that have heretical opinions. I have no use of a function type in a language that does not
    treat functions as first class objects - you cannot pass a function as a parameter, return one from a function, or even have a function object.
    You always deal with pointers to functions. Thus IMHO the pointer
    should be part of the typedef since you always need it.

    (I am not going to say which of us is the heretic here!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Sat Apr 12 09:59:55 2025
    bart <bc@freeuk.com> writes:
    On 12/04/2025 00:59, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.
    Rubbish. I find C declaration syntax annoying, not a "nightmare".

    Annoying would be having to get letter case or punctuation just right.
    [...]
    So, yeah, a 'nightmare' is more apt than 'annoying'.
    Bart, bart, bart.

    You made a false statement about how *everyone* feels about
    C's declaration syntax.

    So what would be a true statement? That everyone finds it at least
    midly annoying?

    That there's a wide variety of opinions on the matter, just as there is
    on just about every issue. The fact that C is one of the most widely
    used languages should clue you in to the fact that large numbers of
    people find it far less troublesome than you do, even if you can't
    imagine why anyone would be insane enough to disagree with you on this
    matter.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Sat Apr 12 15:43:05 2025
    On 12/04/2025 03:27, bart wrote:
    On 12/04/2025 00:59, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.
    Rubbish.  I find C declaration syntax annoying, not a "nightmare".

    Annoying would be having to get letter case or punctuation just right.
    [...]
    So, yeah, a 'nightmare' is more apt than 'annoying'.

    Bart, bart, bart.





    You made a false statement about how *everyone* feels about
    C's declaration syntax.

    So what would be a true statement? That everyone finds it at least midly annoying?

    I don't find C's declaration syntax annoying in the least.

    What I /do/ find annoying at times is the way some programmers write declarations in C. But that is a very different thing.

    If someone wrote "int (*A)[10](int);" in code that I had to maintain, I
    would find that mildly annoying. If someone wrote "int long unsigned
    const long const const typedef A;", I would find it extremely annoying.

    But I don't have any problem writing :

    typedef int (*FIntInt)(int);
    FIntInt A[10];

    or

    typedef const unsigned long long A;

    (other than that I'd want better names for the object or type).

    I write my C code in a way that I don't find annoying to read, nor do
    others that read me code. I'd recommend all programmers try to do the
    same (with the full understanding that different kinds of code will be
    read by different kinds of programmers).


    Like a great many things in C, if I were making the syntax for a
    language I would do it a little differently. Again, that is a different
    thing from saying that I find C's syntax a problem.

    And there /are/ things about C that I find annoying, or limiting. Some
    of these things I can work around using good tools and language
    extensions. Often I use C++ rather than C (C++ also has things I find annoying).

    However, C declaration syntax is not something that bothers me at all
    for the code I write.

    I'm sure that /some/ people find it annoying, at least in some
    situations. With a language used by so many people, pretty much every
    feature is going to annoy someone, and pretty much every programmer is
    going to find something annoying. But there will be a wide range of
    which things different people find annoying, and to what extent. Generalisations like you are giving, where you extrapolate your own
    rather radical opinions, are guaranteed to be wrong.


    C type syntax is famous for being difficult and confusing; I think most
    will agree about that. Even the creators said so.

    I disagree with that claim. I think it is probably fair to say that
    advanced, complicated and multi-layer types are difficult in any
    programming language. It is also fair to say that the way some people
    write complicated types in C can be confusing - as can be the case in
    any language. C lets you write confusing types - it does not force you
    to do so.


    This was the discussion:

    BC:
    Humans have to parse it too. C must be the only non-esoteric language
    where you need to use third-party tools (CDECL etc) to make sense of type-declarations. Either that or follow complex spirular algorithms to [decode] them.

    DB:
    I have never heard of anyone other than you who views cdecl as a necessity.

    So, is that last statement true or not?

    Are you asking Keith to tell you about my personal experience?

    Yes, it is true. Why would I have said it otherwise?

    I didn't say it was a necessity,
    but that you need to use such tools or special methods to understand
    them. And clearly, that would be the more complicated ones; people can usually cope with 'int'.

    So you didn't say it was a necessity, you said people need to use them?
    Or are you suggesting that people who can understand what complicated C
    type declarations mean by reading the C code are somehow using "special methods" ? Other people might just call that knowing the language and
    being experienced at reading it.

    To be clear - I think putting a complicated type declaration on a single
    line makes code harder to read. Putting /anything/ complicated and
    composed of many parts in one condensed lump makes it harder to
    understand - regardless of the programming language, and regardless of
    whether it is programming or something else. Dividing complex things
    into smaller and more manageable parts is usually a good thing - within
    reason, of course.

    "An array of 10 objects each of which is a pointer to a function that
    takes an int parameter and returns an int" is not much clearer than "int (*A)[10](int)", and for people who are used to seeing such C
    declarations, the familiarity of the C version makes it much faster to
    parse.


    I replied to one sweeping statement with another.

    One "sweeping statement" was about a single person, the other was about everyone.

    You want to be treated better?  Stop making deeply silly statements.

    DB was making light of the type syntax issue and pretty much dismissed
    it out of hand. How should I have responded?


    If you didn't make such wildly exaggerated remarks in the first place,
    you wouldn't have to respond to people telling you they are wildly
    exaggerated.

    No one - not me, and not anyone else in comp.lang.c - has ever claimed
    that C is perfect or flawless. What people have claimed is that they
    can understand the language, and write useful code in it, and that it is
    good enough for a lot of purposes. They have sometimes said why the
    language is the way it is, even though they think some things would have
    been better if done differently.


    Not that it would cut any ice with him. Nothing is ever that complicated
    or too onerous or too slow or too over the top or too badly designed or ...


    A vast number of people have written a vast amount of code in C.
    Clearly it is /not/ too complicated, or onerous, or slow. Clearly the declaration syntax in C is not a "nightmare" for everyone - clearly most
    C programmers find it is good enough to do the job even if some people
    have issues with it.


    I write code in C. If it were too complicated, I would not do so. And
    often my choice to replace C is C++ - at the risk of making a sweeping generalisation, I think most programmers would agree that C++ is more complicated than C. Yet like the millions of other C++ programmers, I
    manage to write code in C++ too.


    I suggest also that you stop taking throwaway comments too literally.
    Yet, there is probably more truth in my remark than in David's.

    You might also consider that while many features of C have been copied,
    I don't know of any language that has copied its type syntax.


    If another language copied all of C's syntax, it would just be C.

    The way that types work in a language is fairly fundamental to the kind
    of language you have, so it's not surprising that there is a lot of
    variety in the syntax for types. Some languages /have/ copied the
    syntax, such as C++, D, and Objective-C. No doubt you will call these derivatives of C rather than new languages. You could then say the same
    about other type syntaxes - what languages have copied Pascal's type
    syntax, other than Pascal derivatives like Ada and Modula 2 ?

    So what if other newer languages have a different syntax for type
    declarations? It means their designers feel they have a better way of
    writing types that suit their new language. Fair enough. It doesn't
    imply that they think the C syntax is a "nightmare" (though of course
    they /may/ think that).

    I wonder why? Do you think the designers had an opinion about it closer
    to mine, or to David Brown's?


    I have said multiple times that if I were to design a new programming
    language, its syntax would differ significantly from C's.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Sat Apr 12 15:01:06 2025
    On 12/04/2025 13:39, David Brown wrote:
    On 12/04/2025 01:13, bart wrote:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.

    Rubbish.  I find C declaration syntax annoying, not a "nightmare".


    Annoying would be having to get letter case or punctuation just right.

    But C typepecs can go far beyond it. I can just about do arrays of
    pointers, or pointers to arrays. Anything more complicated is pretty
    much trial and error.

    In an example in my post which I then deleted (DB will just ignore
    examples), I wanted to create an array of 10 pointers to functions
    that take an int and return an int.

    If only C had a way to make that simple and clear.  Oh, wait - it does.

        typedef int (*FIntInt)(int);

    Um, not really! You still need to /analyse/ this to see what exactly
    this is. You don't know it might be to do with functions until you hit
    the /second/ opening parenthesis. Unless somebody writes:

    typedef int ((*FIntInt))(int);

    then it's the /third/ parenthesis!


        FIntInt funcs[10];

    This is a comment I posted yesterday:

    "If you need a program to help you read C programs, that suggests a
    serious flaw in C." (https://news.ycombinator.com/item?id=42564861)

    The same applies to having to use workarounds (and needing to invent
    spurious user types) to write not very complicated typespecs.


    If a C programmer - such as yourself - is foolish enough to reject parts
    of the language designed to make coding simpler, safer, clearer and more portable, then I can see how your self-imposed restrictions make your
    coding harder.  But the fault lies in the poor use of the language, not
    the language.

    No, the fault likes in the language for having such appalling syntax in
    the first place.

    My last post touched on this, but it is the idea that a composite type
    requires 'modifiers' that wrap around each name that is declared in a list:

    T *A[10], (*B)[10], ***C, (*D)(int,int);

    So the type for D involves T on the far left; '*' on its immediate left; '(int,int)' on its right; plus those parentheses are needed to alter
    precedence (in a type-spec!).

    This is effing crazy, and you know it. It also gives rise to problematic
    code like this:

    T** A, B, C;

    designed to make coding simpler, safer, clearer and more

    Was typedef really designed to mitigate the problems of its type syntax?
    I doubt very much: Let's create this really stupid syntax, and let's
    then add X, Y and Z so that you don't need to use that stupid syntax.

    To complete your example:

    typedef int ((*FIntInt))(int);
    typedef FIntInt AFintInt[10];

    AFIntInt Table1, Table2, Table3;

    Two lots of typedefs, and two extra user-identifiers, when it could have
    been done like this, using a made-up LTR syntax:

    [10]*fn(int,int)int Table1, Table2, Table3;

    Everything is in one place without having to hunt down typedefs. No
    unnecessary user types. All three variables are guaranteed to have
    compatible types.

    And you can read off the actual type by simply scanning left-to-right,
    without using any tools or algorithms.

    I haven't mentioned my language (and this uses a different syntax), so
    you can't dismiss this by saying it's a toy! You know this is, and would
    have been, a far better scheme.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Sat Apr 12 15:15:05 2025
    On 12/04/2025 14:59, James Kuyper wrote:
    bart <bc@freeuk.com> writes:
    On 12/04/2025 00:59, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 11/04/2025 22:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.
    Rubbish. I find C declaration syntax annoying, not a "nightmare".

    Annoying would be having to get letter case or punctuation just right.
    [...]
    So, yeah, a 'nightmare' is more apt than 'annoying'.
    Bart, bart, bart.

    You made a false statement about how *everyone* feels about
    C's declaration syntax.

    So what would be a true statement? That everyone finds it at least
    midly annoying?

    That there's a wide variety of opinions on the matter, just as there is
    on just about every issue. The fact that C is one of the most widely
    used languages should clue you in to the fact that large numbers of
    people find it far less troublesome than you do,

    That says little about the quality of the language.

    It says rather more about the lack of choice regarding systems languages
    at this level, especially in previous decades, and also about it being
    foisted on people by those who created Unix.

    It's not so easy on that OS to prise apart OS, C language, C compiler, C headers and C libraries.

    There are a considerable number of design flaws in the language, some
    absolute howlers; that the language is also successful, for whatever
    reasons, doesn't suddenly make it a paragon of good design.

    A lot of those flaws make it more unsafe and more error prone than is
    needed.

    It also means a huge effort, probably several magnitudes more than would
    have been needed to just fix the language, has gone into tooling to help
    get around many of its shortcomings.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to David Brown on Sat Apr 12 16:32:49 2025
    On 12/04/2025 14:52, David Brown wrote:
    On 12/04/2025 15:21, Richard Heathfield wrote:
    On 12/04/2025 13:39, David Brown wrote:

    <snip>

         typedef int (*FIntInt)(int);

         FIntInt funcs[10];

    Just one tiny point, though. I've never been a fan of hiding
    pointers behind typedefs. I would much prefer:

    typedef int FIntInt(int);

    FIntInt *funcs[10];


    Better to have those *s out in the open, where we can keep an
    eye on them.


    C is a flexible language, and also caters for those that have
    heretical opinions.  I have no use of a function type in a
    language that does not treat functions as first class objects -
    you cannot pass a function as a parameter, return one from a
    function, or even have a function object. You always deal with
    pointers to functions.

    That's a perfectly valid reason to prefer your way, and mine is a
    perfectly valid reason to prefer mine. TMTOWTDI.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Sat Apr 12 17:52:16 2025
    On 12/04/2025 14:43, David Brown wrote:
    On 12/04/2025 03:27, bart wrote:

    C type syntax is famous for being difficult and confusing; I think
    most will agree about that. Even the creators said so.

    I disagree with that claim.  I think it is probably fair to say that advanced, complicated and multi-layer types are difficult in any
    programming language.

    But a type that is a simple linear chain should be straightforward, and
    usually is, just not in C. That was illustrated here:

    array of 10 pointer to function taking int and returning int
    1 2 3 4 5 6

    The C correspond to that fantastically complicated type (an array of
    function references!) is:

    int (*A[10])(int);
    6 3 1 2 4 5 (Not sure which bit is the '4')

    The numbers below show the crazy mixed-up correspondence with the
    left-to-right original. Using the made-up LTR syntax of a prior post:

    [10]* fn(int)int A
    1 2 3 4 5 6

    The bits correspond EXACTLY.

    Now I want a new type which is a pointer to such an array. In that new
    syntax you just add * on the left:

    *[10]* fn(int)int A

    In the C, you also need to add *, but where?! It is by no means obvious.
    In fact it is this (I had to employ Cdecl):

    int (*(*A)[10])(int )

    I had to add '*' and also '()' in a critical place. I still don't know
    which of those * is which.

    As I've many times, this is completely unfit for purpose. Beyond the
    simplest examples, this is just gibberish.

    With LTR syntax, you can create arbitrarily complex chains, and you will
    always now exactly what they mean, and which * is which. Modifying them
    is trivial:

    C LTR style

    int A[10] [10]int A # array of int
    int *A[10] [10]*int A # array of pointer to int
    int (*A)[10] *[10]int A # pointer to array of int
    int *(*A)[] *[]*[]int A # ptr to array of ptr to int
    int *(*A)[], B *[]*[]int A, B

    In the last example, A and B are different types in the C column (B is a
    simple int); in the LTR column, both are exactly the same type, another advantage.

    There is just no comparison. LTR style is far superior, more convenient,
    more readable, easy to write, and less error prone.

    To be clear - I think putting a complicated type declaration on a single
    line makes code harder to read.

    As C does it, yes. But the threshold at which it becomes gobbledygook is
    too low.

    A vast number of people have written a vast amount of code in C. Clearly
    it is /not/ too complicated, or onerous, or slow.

    That just means vast numbers have HAD to write complicated, onerous
    code. What other choice did they have? What alternates to C were possible?


    I have said multiple times that if I were to design a new programming language, its syntax would differ significantly from C's.

    But it would be a toy unless you could get it adopted by lots of people.

    By your standards, even a DSL that you create for use in your
    professional work would be a toy.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Sat Apr 12 17:40:25 2025
    On 2025-04-12, bart <bc@freeuk.com> wrote:
    On 12/04/2025 14:43, David Brown wrote:
    On 12/04/2025 03:27, bart wrote:

    C type syntax is famous for being difficult and confusing; I think
    most will agree about that. Even the creators said so.

    I disagree with that claim.  I think it is probably fair to say that
    advanced, complicated and multi-layer types are difficult in any
    programming language.

    But a type that is a simple linear chain should be straightforward, and usually is, just not in C. That was illustrated here:

    array of 10 pointer to function taking int and returning int
    1 2 3 4 5 6

    You make a good point in that since the type constructing operators are
    unary (prefix or postfix), the derivation chain is linear and could be linearized, without the need for any precedence parentheses.

    It follows the use, though.

    The function and array derivations are postfix. Only the pointer
    derivation is prefix.

    If we imagine a C with postfix pointer dereferencing, say using ^
    (setting aside the xor meaning for a moment), like:

    a[i]^(arg); // index into a at i, dereference, call with arg.

    Then the declarator would be similar under declaration-follows-use:


    int a[10]^(int); // same as int (*a[10])(int);

    the name would always be on the left, just after the declaration
    specifiers, and all the derivation would be postfix.

    Then, suppose if you didn't want an array of pointers, but
    a pointer to an array, you would not add, remove or rearrange
    precedence parentheses. You would just reorder the postfixes.

    int a^[10](int) // same as int (*a)[10](int);
    // Note: invalid! For syntactic discussion only!

    This is a type not supported in C: array of functions. I'm just using
    it for syntax comparisons to illustrate that if all the type derviations
    are postfix, then precedence parentheses serve no purpose and we don't entertain them.

    You do have a point, but the fact that C declarations follow C
    expressions (even with the way suboptimal dereferencing is on the left)
    is a good thing. The consistency makes it easy to learn declarations,
    and also to visually check code for sanity: do declarations match uses.

    "Declaration follows use" might be even better with a nicer
    expression grammar in the area of arrays and pointers, but we don't
    have that.

    This (*a[10])(int) clump may seem difficult, but a C programmer cannot
    get around learning that same shape in the context of expressions,
    where it could occur like this (*a[i])(x + 1). If you grok this,
    you're most of the way toward grokking the declarator.

    There are some subtleties like expressions giving you various shortcuts.
    Arrays can be used as if they were pointers and vice-versa, and
    function pointers can be called without explicit dereferencing.
    I believe those additional rules in expressions that are not found
    in type derivation cause some C programmers to have difficulties
    with nested declarations. It's precisely because they cause deviations
    from "declaration follow use". The use of a function pointer is rarely observed as (*ptr)(arg) because ptr(arg) works, but the declarator
    must still be (*ptr)(paramtype) as if ptr(arg) didn't exist.

    If there were no deviations in "declaration follows use", such that
    calling a function pointer taken from an array had to be written
    (*a[i])(arg), then new C programmers would struggle less with
    declarations. Or should we say, struggle less with declarations of
    entities that they already know how to use.

    I have said multiple times that if I were to design a new programming
    language, its syntax would differ significantly from C's.

    But it would be a toy unless you could get it adopted by lots of people.

    By your standards, even a DSL that you create for use in your
    professional work would be a toy.

    If the DSL reinvents a lot of risky wheels, like doing everything
    from scratch, that could be the case. It takes some years to mature
    something out of non-toy status at that level.

    A DSL that just transliterates some notation to a stable, mature
    language, according to a small body of rules, easily inherits
    the non-toy status from the platform it sits on.

    "Toy" is a not a well-defined concept, which mainly seems function
    as "not suitable for some unspecified purposes that I have in mind".
    People who use "toy" tend to move their secret goalposts.

    There are ways that a DSL could be unsuitable for some of the purposes
    it is supposedly designed for, even if it sits on a stable platform;
    then some people trying that DSL in earnest might abandon it
    and call it a toy.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to bart on Sat Apr 12 19:17:50 2025
    On 12/04/2025 17:52, bart wrote:

    With LTR syntax, you can create arbitrarily complex chains, and you will always now exactly what they mean, and which * is which. Modifying them
    is trivial:

       C                  LTR style

       int *(*A)[]        *[]*[]int A         # ptr to array of ptr to int

    The comment here doesn't match the LTR typespec; there's an 'array of'
    missing from the comment.

    I suspect the C matches the comment (since I had to enter the equivalent
    into CDECL to get the C typespec!).

    What's under LTR is the type I wanted, so the correct version is:

    C LTR

    int (*(*A)[])[] *[]*[]int A # ptr to array of ptr array of int

    The first * in LTR I think corresponds to the second * in the C version.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Sun Apr 13 00:09:23 2025
    On 12/04/2025 18:40, Kaz Kylheku wrote:
    On 2025-04-12, bart <bc@freeuk.com> wrote:
    On 12/04/2025 14:43, David Brown wrote:
    On 12/04/2025 03:27, bart wrote:

    C type syntax is famous for being difficult and confusing; I think
    most will agree about that. Even the creators said so.

    I disagree with that claim.  I think it is probably fair to say that
    advanced, complicated and multi-layer types are difficult in any
    programming language.

    But a type that is a simple linear chain should be straightforward, and
    usually is, just not in C. That was illustrated here:

    array of 10 pointer to function taking int and returning int
    1 2 3 4 5 6

    You make a good point in that since the type constructing operators are
    unary (prefix or postfix), the derivation chain is linear and could be linearized, without the need for any precedence parentheses.

    It follows the use, though.

    You still seem keen on making typespec syntax somehow match expression
    syntax. I think that's a mistake. Type syntax is not executed, not at
    this level of language.

    The function and array derivations are postfix. Only the pointer
    derivation is prefix.

    If we imagine a C with postfix pointer dereferencing, say using ^
    (setting aside the xor meaning for a moment), like:

    a[i]^(arg); // index into a at i, dereference, call with arg.

    Then the declarator would be similar under declaration-follows-use:

    int a[10]^(int); // same as int (*a[10])(int);

    Your example /still/ has type syntax that looks like an expression; they
    are easy to confuse. You WANT a type syntax that is more distinct.


    Then, suppose if you didn't want an array of pointers, but
    a pointer to an array, you would not add, remove or rearrange
    precedence parentheses. You would just reorder the postfixes.

    int a^[10](int) // same as int (*a)[10](int);
    // Note: invalid! For syntactic discussion only!

    This is a type not supported in C: array of functions.

    Yes, you'd move 'pointer to' symbol along. Or just add a new one. With
    postfix deref, you don't need to bother with round brackets (which was
    always a bizarre idea to me; normally brackets are used around parameter
    lists only.

    You do have a point, but the fact that C declarations follow C
    expressions (even with the way suboptimal dereferencing is on the left)
    is a good thing. The consistency makes it easy to learn declarations,
    and also to visually check code for sanity: do declarations match uses.

    I've tried for decades but still find them impossible without external
    help. Obviously for me it doesn't work.

    But, what the hell is there are learn anyway?! Typespecs are built out
    of primitive types, arrays, pointers and function signatures.

    If your type is a pointer to array of pointer to T, then you just write
    a pointer to array of T! That is:

    *[]*T X

    in my LTR syntax from earlier today. Then access to the T element is
    with X*[i]*.

    Here the ordering of those ops (deref, index, deref) does match the
    ordering of the corresponding type elements, but I'm not making a big
    deal out of that, to the extent that the syntax must match exactly. It
    won't do since X is on the opposite end for a start.

    In my real language, the type is:

    ref[]ref T X

    and the term is X[i]^. (The ^ between X and [ can be implicit.)

    Notice that while the ordering is similar, there is no attempt to match
    syntax. It is not necessary. I can't mistake one for the other, either.

    If the DSL reinvents a lot of risky wheels, like doing everything
    from scratch, that could be the case. It takes some years to mature
    something out of non-toy status at that level.

    My point was that a DSL is just another piece of custom software. But
    such software in general is not a toy because it has not been
    'battle-tested'. It will have the usual testing processes so that it
    meets its specs for client's application.

    My language was just another tool that worked remarkably well. It was
    not a general language intended for a mass market.

    But DB refuses to acknowledge any ideas that come out of it and will
    always insist that C is better. (I guess he would lend more credence to
    some hypothetical feature that has not been implemented and has never
    been proved.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Kaz Kylheku on Sun Apr 13 04:53:08 2025
    On 12.04.2025 14:57, Kaz Kylheku wrote:
    On 2025-04-12, bart <bc@freeuk.com> wrote:
    [...]

    The main difference is that the the expressions are the payload that
    does the work, whereas declarations are just mental overead.

    (Not for me, but okay.)

    The thought process is that the C programmer has a data structure
    layout in their mind and can write expressions to navigate through
    it, from the top-level reference down to its leaves.

    But, oh crap, the C programmer has to declare the things they are using
    in that expression.

    Different people might think differently. Myself (for example) I have
    the structure in mind first, and then the natural traversal/navigation
    through those structures; navigation follows the structure, which is
    defined by the declaration. (And not vice versa.)

    C brings a nice simplification here. If you can write the expression to access the thing you are imagining, the declaration can be derived
    from that shape.

    This "simplification" is what might be the reason for some to dislike
    it. And its "rationale" to be "derived from that _shape_[sic!]" which
    is probably the source of the convoluted declaration syntax.

    WRT "shape"; I'm certainly someone who would not mind (or rather who'd appreciate) to have a * declaration ('ptr') and a * operation ('deref')
    clearly differentiated and I've no need for a common "shape"; here my
    primary requirement is certainly a clean, non-convoluted declaration
    syntax.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sun Apr 13 04:27:57 2025
    On 12.04.2025 13:00, bart wrote:
    On 12/04/2025 05:33, Janis Papanagnou wrote:
    [ 'typedef' composition/decomposition for complex declarations ]

    This is a third kind of workround. All of them should be unnecessary.
    Unless the type really is complicated and needs to be decomposed anyway, whatever the syntax.

    Well, yes. If you have a somewhat [IMO] convoluted syntax then you
    pick your language choices to address it and do the best out of it.

    [...]

    But I also 100% hate its syntax and various other bits and pieces. (OK,
    about 80% then.)

    (I also don't like its syntax too much. I think I'm just complaining
    less than you about that. BTW, I've got the impression that all the shortcomings of "C" are well known by most regulars here; they just
    handle these facts in discussions differently than you.)

    [...

    And APIs use C type syntax. So, yeah, I am entitled to an opinion about it.

    That's fine. Although those repeated complaints also annoy me. (But
    that's my problem, of course.)

    [...]

    Guessing: An array with 10 elements that are pointers to functions
    that take an 'int' parameter and return an 'int' value?

    [...]

    (This opening parenthesis syntactically indicates the function, as
    also indicated by the numberings above. - Or so I'd think. - No?)

    Not necessarily. This is a valid declaration in C:

    int (A);

    That opening parentheses is just noise. (I guess you just learned
    something new about C today?)

    Not really. - I was merely pointing out that the messages you posted
    made sense to me; where I had the impression you were confused about
    it.


    Assumed that my guess above was correct that's quite equivalent to
    the Algol 68 form

    [10] REF PROC (INT) INT a

    So you do get it (maybe I should have read this far first). Yes, it
    directly comes from Algol68.

    But left-to-right type specifications must be common now everywhere.

    Not sure. A more regular syntax is at least something I appreciate a
    lot. (That' why, maybe many months ago, I spoke here about Algol 68
    as one the formally most consistent languages, and that I like it a
    lot because of that.)


    but in Algol 68 you'd probably rather use it without the unnecessary
    "pointer"/reference just as in

    [10] PROC (INT) INT a

    which - as you seem to like clearness - is even simpler!

    This is not as clear; the intent is to have a reference to a function;
    not an array of actual functions. For example:

    []ref func(int) int := (F, G, H)

    It is initialised to functions F, G, H which are defined elsewhere.

    In Algol 68 I can just write (without 'REF'), for example,

    [10] PROC (INT) INT apfii;
    PROC one_less = (INT i) INT : i-1;
    PROC one_more = (INT i) INT : i+1;
    apfii[2:3] := ( one_less, one_more );

    We don't need "pointers" (or references) which don't contribute to the clearness of the semantics for this purpose - 'REF's are used for other
    things -, for the case here they'd rather introduce low-level mechanics unnecessarily in the application. - Just saying. (I'm not intending to
    complain in that respect about "C" or about "your language". I'm merely reporting some simple facts about it.) - So the 'ref' necessity in your language may look clear to you but for me it's just obscuring ballast.

    Maybe in Algol68 you can have actual function definitions in that list.

    Yes. It makes no sense to unnecessarily expose low-level implementation mechanics to the programmer. (I think Algol 68 does that quite well.)

    But not in mine, which was created as a leaner, simpler and more
    transparent systems language.

    We obviously disagree about the "transparence". I prefer languages that
    don't make me have to use unnecessarily low-level mechanics. There's no necessity of "ref" here; that's a problem of (or a "solution" or maybe "workaround" in, or a design decision of) your language. - But as many
    others here, I anyway don't care much about other's personal languages.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sun Apr 13 12:33:11 2025
    On 13/04/2025 03:27, Janis Papanagnou wrote:
    On 12.04.2025 13:00, bart wrote:


    []ref func(int) int := (F, G, H) # [var name missing]

    It is initialised to functions F, G, H which are defined elsewhere.

    In Algol 68 I can just write (without 'REF'), for example,

    [10] PROC (INT) INT apfii;
    PROC one_less = (INT i) INT : i-1;
    PROC one_more = (INT i) INT : i+1;
    apfii[2:3] := ( one_less, one_more );

    I can write it like this using anonymous functions:

    [10] PROC (INT) INT apfii;
    apfii[2:3] := ((INT i)INT:i-1, (INT i)INT:i+1);

    print((apfii[2](42), apfii[3](42)))

    which is what I meant about having actual functions within the list. But
    I anyway consider this a higher level feature, and Algol68 is a higher
    level language. In my scripting language I can do:

    apfii := (2: {n:n-1}, {n:n+1})
    println apfii[2](42), apfii[3](42)

    (Which despite being interpreted /and/ dynamic, runs 20 times faster
    than interpreted A68G.)

    We don't need "pointers" (or references) which don't contribute to the clearness of the semantics for this purpose - 'REF's are used for other things -, for the case here they'd rather introduce low-level mechanics unnecessarily in the application. - Just saying. (I'm not intending to complain in that respect about "C" or about "your language". I'm merely reporting some simple facts about it.) - So the 'ref' necessity in your language may look clear to you but for me it's just obscuring ballast.

    'refs' occur in declarations. The equivalent 'deref' operation, '^' in
    my syntax, can be omitted in code when it is between terms. (So where C
    needs (*P)->m, I can just do P.m instead of P^^.m)

    My style of coding also separates declarations, which have type
    annotatons, from code.

    So my systems code is considerably cleaner than C. If you want really
    clean then you need to go to scripting languages with few type
    annotations and where most pointer/address-of ops are implicit.

    (However, many are now introducing type annotations! Or have new
    languages such as Typescript created on top.)

    Algol68 fits the role of systems language; it was famously impenetrable,
    and tried to do too much implicitly, so you had to spend time
    double-guessing what it might be up to. Implementation (if you had to
    create your own as I had to do), would have been quite impractical.

    But not in mine, which was created as a leaner, simpler and more
    transparent systems language.

    We obviously disagree about the "transparence". I prefer languages that
    don't make me have to use unnecessarily low-level mechanics. There's no necessity of "ref" here; that's a problem of (or a "solution" or maybe "workaround" in, or a design decision of) your language.

    I need 'ref' because I have a strict type system.

    I anyway needed a fully transparent language because I first had to
    implement it on an 8-bit microprocessor.

    - But as many
    others here, I anyway don't care much about other's personal languages.

    Neither do I. But I can at least appreciate (and appropriate) clever and
    useful features that they might have. Even more so if someone has
    managed to successfully use their product, instead of C, for a sustained period.

    I will not dismiss a potentially useful feature because their product
    has not been 'battle-tested'.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to bart on Sun Apr 13 12:36:00 2025
    On 13/04/2025 12:33, bart wrote:

    Algol68 fits the role of systems language;

    It somehow lost the word 'poorly'!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sun Apr 13 14:58:38 2025
    On 13/04/2025 03:27, Janis Papanagnou wrote:
    On 12.04.2025 13:00, bart wrote:

    But I also 100% hate its syntax and various other bits and pieces. (OK,
    about 80% then.)

    (I also don't like its syntax too much. I think I'm just complaining
    less than you about that. BTW, I've got the impression that all the shortcomings of "C" are well known by most regulars here; they just
    handle these facts in discussions differently than you.)

    The shortcomings are downplayed considerably. Especially in discussions involving me because they don't like it whenever someone states the obvious.

    But also, most here have to use it professionally, so have learned to
    work around it. I on the hand have more of a choice, and have
    /extensive/ experience of doing similar low level coding in an
    alternative, more agreeable syntax.

    It must be frustrating to not have that choice. However when someone
    claims that some appalling syntax or bizarre quirk of C is really an
    advantage, then I can be vocal about that.

    And when somebody just completely dismisses alternate syntax or features
    that I use ("it's just a toy") then you can tell it is sour grapes.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to David Brown on Sun Apr 13 14:48:17 2025
    On 2025-04-13, David Brown <david.brown@hesbynett.no> wrote:
    On 12/04/2025 17:32, Richard Heathfield wrote:
    function object. You always deal with pointers to functions.

    That's a perfectly valid reason to prefer your way, and mine is a
    perfectly valid reason to prefer mine. TMTOWTDI.



    My way is intellectually justified for me, and therefore you --- that
    doesn't mean your way is intellectually justified for you, therefore me.

    :)

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Sun Apr 13 14:54:54 2025
    bart <bc@freeuk.com> writes:
    On 13/04/2025 12:33, bart wrote:

    Algol68 fits the role of systems language;

    It somehow lost the word 'poorly'!

    That would suprise Burroughs/Unisys, where the operating
    system, database and utilites are all written in Algol.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Richard Heathfield on Sun Apr 13 16:26:55 2025
    On 12/04/2025 17:32, Richard Heathfield wrote:
    On 12/04/2025 14:52, David Brown wrote:
    On 12/04/2025 15:21, Richard Heathfield wrote:
    On 12/04/2025 13:39, David Brown wrote:

    <snip>

         typedef int (*FIntInt)(int);

         FIntInt funcs[10];

    Just one tiny point, though. I've never been a fan of hiding pointers
    behind typedefs. I would much prefer:

    typedef int FIntInt(int);

    FIntInt *funcs[10];


    Better to have those *s out in the open, where we can keep an eye on
    them.


    C is a flexible language, and also caters for those that have
    heretical opinions.  I have no use of a function type in a language
    that does not treat functions as first class objects - you cannot pass
    a function as a parameter, return one from a function, or even have a
    function object. You always deal with pointers to functions.

    That's a perfectly valid reason to prefer your way, and mine is a
    perfectly valid reason to prefer mine. TMTOWTDI.


    I entirely agree. My way is right for /me/ - that doesn't mean it is
    right for /you/.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Sun Apr 13 14:34:39 2025
    On 2025-04-13, bart <bc@freeuk.com> wrote:
    On 13/04/2025 03:27, Janis Papanagnou wrote:
    On 12.04.2025 13:00, bart wrote:

    But I also 100% hate its syntax and various other bits and pieces. (OK,
    about 80% then.)

    (I also don't like its syntax too much. I think I'm just complaining
    less than you about that. BTW, I've got the impression that all the
    shortcomings of "C" are well known by most regulars here; they just
    handle these facts in discussions differently than you.)

    The shortcomings are downplayed considerably. Especially in discussions involving me because they don't like it whenever someone states the obvious.

    But also, most here have to use it professionally, so have learned to
    work around it.

    There are lots of examples of people just liking C.

    Oh, Donald Knuth, in a 1993 Computer Literacy Bookshops interview:

    CLB: Did you integrate WEB with C because so many programmers today
    are using it, or do you personally like C and write with it?

    Knuth: I think C has a lot of features that are very important. The
    way C handles pointers, for example, was a brilliant innovation; it
    solved a lot of problems that we had before in data structuring and
    made the programs look good afterwards. C isn't the perfect language,
    no language is, but I think it has a lot of virtues, and you can avoid
    the parts you don't like. I do like C as a language, especially
    because it blends in with the operating system (if you're using UNIX,
    for example).

    All through my life, I've always used the programming language that
    blended best with the debugging system and operating system that I'm
    using. If I had a better debugger for language X, and if X went well
    with the operating system, I would be using that.

    Richard Stallman of the GNU Project: developed a C compiler and started
    cloning Unix in the mid 1980's, entirely as free software.

    Billions of lines have been written in C as free open source since.

    The reason some people have to use it for work is, ironically, is that
    people's unpaid side projects evolved into widely deployed platforms
    that the world relies on.

    C has spawned imitation in the form of "C like" languages, that all
    started as grenfield projects that could have chosen any syntax
    they wanted.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Sun Apr 13 17:48:59 2025
    On 13/04/2025 15:54, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 13/04/2025 12:33, bart wrote:

    Algol68 fits the role of systems language;

    It somehow lost the word 'poorly'!

    That would suprise Burroughs/Unisys, where the operating
    system, database and utilites are all written in Algol.

    Algol68 or Algol60? The former is very different.

    However even Algol60, in its pure form, would be unsuitable (and also
    supports advanced features like higher order functions that are not
    relevant to systems code).

    It could however be adapted. Google suggests that a special superset
    called ESPOL was used, with extra features to make systems programming
    viable.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Sun Apr 13 17:39:42 2025
    On 13/04/2025 15:34, Kaz Kylheku wrote:
    On 2025-04-13, bart <bc@freeuk.com> wrote:
    On 13/04/2025 03:27, Janis Papanagnou wrote:
    On 12.04.2025 13:00, bart wrote:

    But I also 100% hate its syntax and various other bits and pieces. (OK, >>>> about 80% then.)

    (I also don't like its syntax too much. I think I'm just complaining
    less than you about that. BTW, I've got the impression that all the
    shortcomings of "C" are well known by most regulars here; they just
    handle these facts in discussions differently than you.)

    The shortcomings are downplayed considerably. Especially in discussions
    involving me because they don't like it whenever someone states the obvious. >>
    But also, most here have to use it professionally, so have learned to
    work around it.

    There are lots of examples of people just liking C.


    C itself, or the things that C allowed you to do?

    I made a distinction a couple of posts up, where I said I liked what C
    could do, but not how it did it, in terms of language design.

    People still like this class of language, even though now there are
    advanced alternatives (Rust etc) because of the freedom it allows and
    trust it puts in the programmer (even if C frowns on a lot of things via
    UB).

    So it still comes down to there being few alternatives. Even where they
    exist, implementations may not be as ubiquitous or as mature as they are
    for C.

    (When I generate C code it is for two reasons: for a target I don't
    directly support; or to use its optimising compilers. Or both.)


    Oh, Donald Knuth, in a 1993 Computer Literacy Bookshops interview:

    CLB: Did you integrate WEB with C because so many programmers today
    are using it, or do you personally like C and write with it?

    Knuth: I think C has a lot of features that are very important. The
    way C handles pointers, for example, was a brilliant innovation; it
    solved a lot of problems that we had before in data structuring and
    made the programs look good afterwards. C isn't the perfect language,
    no language is, but I think it has a lot of virtues, and you can avoid
    the parts you don't like.

    Well, given Knuth's own language was MIX (assembly for a made-up
    machine), it is not surprising he prefers C.

    I do like C as a language, especially
    because it blends in with the operating system (if you're using UNIX,
    for example).

    This is something I cited as a disadvantage. If using Unix, you can't
    get away from the influence of C. But Windows was also implemented significantly in C; that does a much better job of hiding it.

    It also, for people using Unix, puts other systems languages at a
    disadvantage because C gets all the breaks.


    All through my life, I've always used the programming language that
    blended best with the debugging system and operating system that I'm
    using. If I had a better debugger for language X, and if X went well
    with the operating system, I would be using that.

    Richard Stallman of the GNU Project: developed a C compiler and started cloning Unix in the mid 1980's, entirely as free software.

    Billions of lines have been written in C as free open source since.

    The reason some people have to use it for work is, ironically, is that people's unpaid side projects evolved into widely deployed platforms
    that the world relies on.

    C has spawned imitation in the form of "C like" languages, that all
    started as grenfield projects that could have chosen any syntax
    they wanted.

    Some of this is to be expected: if they started off using brace syntax,
    then their language will use braces. But some of the things they copy
    are odd, like this for-loop from JS:

    for(let i = 1; i <= 36; i++) {

    Is it that hard to provide a proper for-loop where you don't have to
    spell out every single detail? Fortran managed it in the 1950s!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Keith Thompson on Sun Apr 13 20:57:03 2025
    On Fri, 11 Apr 2025 11:15:44 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    bart <bc@freeuk.com> writes:
    [...]
    8 A u64 type can be denoted as either 'uint64_t' OR as some
    combination of the tokens (long, long, unsigned, [int])

    "uint64_t" and "unsigned long long int" do not mean the same thing.


    And it's a PITA.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to James Kuyper on Sun Apr 13 21:03:03 2025
    On Fri, 11 Apr 2025 18:24:41 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.

    I don't.

    Combination of prefix and postfix modifiers in C decarations is hard to
    follow for majority of C users. If for you it is easy then you belong to minoity.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Kaz Kylheku on Sun Apr 13 20:45:21 2025
    On Fri, 11 Apr 2025 17:22:37 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wrote:

    On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:
    On Thu, 10 Apr 2025 17:59:15 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:


    An understanding of what "compatible types" means.

    Bart didn't say that types are compatible or non-compatible.
    He said that they are 'compatible enough'. That is not terminology
    of C Standard, but terminology of his own. And he seems to
    understand it.

    In my own translation, 'compatible enough' means that when these
    structs are accessed then any sane or even semi-sane compiler will
    generate code that will have the same effect as in case of access
    through structures with literally identical declarations.

    so struct { long x; } and struct { int x; } are compatible enough,
    in situations that are portable enough.


    I wish they would be, but according to C Standard they are not, ene
    when both represent 32-bt signed integer. That's because of misfeature
    called 'strong aliasing rules'.
    IMO, C would become better without this misfeature.


    A sphere and a cow are similar enough, ...


    Bad attempt of analogy.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Sun Apr 13 20:53:03 2025
    On 13/04/2025 19:57, Michael S wrote:
    On Fri, 11 Apr 2025 11:15:44 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    bart <bc@freeuk.com> writes:
    [...]
    8 A u64 type can be denoted as either 'uint64_t' OR as some
    combination of the tokens (long, long, unsigned, [int])

    "uint64_t" and "unsigned long long int" do not mean the same thing.


    And it's a PITA.


    There is only one thing I find a little bit annoying about the sized
    integer types in C - the printf specifiers. I tend to "cheat" with
    these, using "%lu" for uint32_t on the targets I usually use, where I
    know uint32_t is "long unsigned int". Other than that, I stick to the size-specific types for much of my code except local "throw-away"
    variables that might be "int". Compatibility or lack thereof between
    the size-specific types and the standard integer types is simply
    irrelevant in my code.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Kaz Kylheku on Sun Apr 13 21:40:46 2025
    On Sat, 12 Apr 2025 17:40:25 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wrote:

    On 2025-04-12, bart <bc@freeuk.com> wrote:
    On 12/04/2025 14:43, David Brown wrote:
    On 12/04/2025 03:27, bart wrote:

    C type syntax is famous for being difficult and confusing; I
    think most will agree about that. Even the creators said so.

    I disagree with that claim.  I think it is probably fair to say
    that advanced, complicated and multi-layer types are difficult in
    any programming language.

    But a type that is a simple linear chain should be straightforward,
    and usually is, just not in C. That was illustrated here:

    array of 10 pointer to function taking int and returning int
    1 2 3 4 5 6

    You make a good point in that since the type constructing operators
    are unary (prefix or postfix), the derivation chain is linear and
    could be linearized, without the need for any precedence parentheses.

    It follows the use, though.


    The funny thing is that in original C prefix form of [] indexing was
    equivalent to the postfix form. May be, it still is in C23, I didn't
    try to look in the docs or test.
    However in type declarations one always had to use only postfix form.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Sun Apr 13 22:14:57 2025
    On Sun, 13 Apr 2025 20:53:03 +0200
    David Brown <david.brown@hesbynett.no> wrote:

    On 13/04/2025 19:57, Michael S wrote:
    On Fri, 11 Apr 2025 11:15:44 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    bart <bc@freeuk.com> writes:
    [...]
    8 A u64 type can be denoted as either 'uint64_t' OR as some
    combination of the tokens (long, long, unsigned, [int])

    "uint64_t" and "unsigned long long int" do not mean the same thing.


    And it's a PITA.


    There is only one thing I find a little bit annoying about the sized
    integer types in C - the printf specifiers.


    Yes, in practice it is the main reason why I find absence of
    system-independent correspondence between [u]intn_t types and basic
    integer types a PITA. But there exist few other cases where it causes
    problems, e.g. using Intel intrinsic like _addcarry_u64() in code that
    have to be compiled on different 64-bit OSes.

    As to why you feel stronger than you about it, I'd guess it's because I
    write code that has to be compiled, preferably without warnings, on
    different platforms more often than you do. Most of 32-bit and 64-bit
    platforms are compatible to each other, but 64-bit Unix/Linus is at
    odds with the rest of them.

    I tend to "cheat" with
    these, using "%lu" for uint32_t on the targets I usually use, where I
    know uint32_t is "long unsigned int". Other than that, I stick to
    the size-specific types for much of my code except local "throw-away" variables that might be "int". Compatibility or lack thereof between
    the size-specific types and the standard integer types is simply
    irrelevant in my code.


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Michael S on Sun Apr 13 20:08:52 2025
    On 2025-04-13, Michael S <already5chosen@yahoo.com> wrote:
    The funny thing is that in original C prefix form of [] indexing was equivalent to the postfix form. May be, it still is in C23, I didn't
    try to look in the docs or test.

    Are you thinking of a[i] being *(a + i) being i[a] due to commutativity?

    That's really not a useful feature. Actually right down to a + i being commutative when a is a pointer. It would be fine if only the
    <pointer> + <integer> combination were allowed.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Kaz Kylheku on Mon Apr 14 00:30:03 2025
    On Sun, 13 Apr 2025 20:08:52 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wrote:

    On 2025-04-13, Michael S <already5chosen@yahoo.com> wrote:
    The funny thing is that in original C prefix form of [] indexing was equivalent to the postfix form. May be, it still is in C23, I
    didn't try to look in the docs or test.

    Are you thinking of a[i] being *(a + i) being i[a] due to
    commutativity?


    My impression rfrom old books was that indexing as [i]arr was (is ?)
    also legal.

    That's really not a useful feature. Actually right down to a + i being commutative when a is a pointer. It would be fine if only the
    <pointer> + <integer> combination were allowed.


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Michael S on Sun Apr 13 20:50:34 2025
    On 4/13/25 14:40, Michael S wrote:
    On Sat, 12 Apr 2025 17:40:25 -0000 (UTC)
    ...
    The funny thing is that in original C prefix form of [] indexing was equivalent to the postfix form. May be, it still is in C23, I didn't
    try to look in the docs or test.

    You mean the fact that array[5] and 5[array] have exactly the same
    meaning? That's still there. It follows from the fact that E1[E2] is
    defined as equivalent to *(E1+E2), and from the fact that E1+E2 means
    the same as E2+E1, when one of them is a pointer, and the other is a
    integer.

    However in type declarations one always had to use only postfix form.

    The "declaration follows use" concept normally picks only one of the
    ways in which a declarator can be used, as the one that is mirrored by
    the declaration syntax.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Michael S on Sun Apr 13 20:56:12 2025
    On 4/13/25 14:03, Michael S wrote:
    On Fri, 11 Apr 2025 18:24:41 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    bart <bc@freeuk.com> writes:
    [...]
    Rubbish. Everyone finds C declaration syntax a nightmare.

    I don't.

    Combination of prefix and postfix modifiers in C decarations is hard to follow for majority of C users. If for you it is easy then you belong to minoity.

    For me, the fact that the syntax for prefix and postfix modifiers in declrations mirrors the syntax for prefix and postfix expressions makes
    it relatively easy to understand. I'd find it a lot more confusing if
    there were postfix expressions but I had to use prefix declarations to
    declare things suitable for use in those expressions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Michael S on Sun Apr 13 21:07:08 2025
    On 4/13/25 17:30, Michael S wrote:
    ...
    My impression rfrom old books was that indexing as [i]arr was (is ?)
    also legal.

    If it had ever been legal, I would have expected it to be mentioned in
    K&R 1st edition, in the section where it describes obsolete syntax that
    used to be valid. It isn't.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Keith Thompson on Sun Apr 13 22:57:22 2025
    On 4/13/25 21:33, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 4/13/25 17:30, Michael S wrote:
    ...
    My impression rfrom old books was that indexing as [i]arr was (is ?)

    Note: [i]arr

    also legal.

    If it had ever been legal, I would have expected it to be mentioned in
    K&R 1st edition, in the section where it describes obsolete syntax that
    used to be valid. It isn't.

    It isn't mentioned there because the syntax isn't obsolete.

    It's mentioned in K&R1 Appendix A section 14.3, page 210:

    By definition, the subscript operator [] is interpreted in such a
    way that E1 [E2] is identical to *((E1)+(E2)). Because of the
    conversion rules which apply to +, if E1 is an array and E2 an
    integer, then E1 [E2] refers to the E2-th member of E1. Therefore,
    despite its asymmetric appearance, subscripting is a commutative
    operation.

    This is still true in all editions up to and including C23.

    He's not talking about E2[E1]. He's talking about [E2]E1.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Mon Apr 14 05:59:11 2025
    On 13.04.2025 18:48, bart wrote:
    On 13/04/2025 15:54, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 13/04/2025 12:33, bart wrote:

    Algol68 fits the role of systems language;

    It somehow lost the word 'poorly'!

    That would suprise Burroughs/Unisys, where the operating
    system, database and utilites are all written in Algol.

    Algol68 or Algol60? The former is very different.

    I don't recall whether it was "Burroughs/Unisys" (that Scott mentioned)
    but I know that there were systems programmed in Algol 68.

    If you know Algol 60 you'd probably have recognized that it's unsuited
    for systems programming (as opposed to Algol 68). - At least IMO.

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Mon Apr 14 06:23:43 2025
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    Is it that hard to provide a proper for-loop where you don't have to
    spell out every single detail?

    You mean like in Algol 68 or maybe Simula? (Both are interesting.)

    Fortran managed it in the 1950s!

    I obviously don't recall FORTRAN good enough to have memorized any
    "good" feature. But as (mostly?) an anachronism it anyway doesn't
    matter any more (to me).

    WRT FORTRAN _loops_ I (faintly) only recall a syntax ambiguity "by
    design" (and jump labels); certainly not something to advocate.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to James Kuyper on Mon Apr 14 06:43:11 2025
    On 14.04.2025 03:03, James Kuyper wrote:
    On 4/13/25 15:14, Michael S wrote:
    ...
    Yes, in practice it is the main reason why I find absence of
    system-independent correspondence between [u]intn_t types and basic
    integer types a PITA. But there exist few other cases where it causes
    problems, e.g. using Intel intrinsic like _addcarry_u64() in code that
    have to be compiled on different 64-bit OSes.

    Well the basic integer types were intended to be system-specific, specifically to allow each implementation to choose whatever worked best
    for the target platform. That's one of the features that helped ensure
    that there's a fully conforming implementation of C for such a wide
    variety of platforms. The size-named types came later, and it is of
    course impossible for the correspondence between system-specific and size-named types to be system-independent.

    Honestly, this is an old, known argument that I could never fully
    understand. 'char' for characters, 'int' as a register sized entity,
    'short' and 'long' as, say, additions. So far so good. "For a wide
    variety of platforms" you cannot just use 'int' and hope that works
    on 8, 16, or 32 bit processors the same way. Switching to 'long' or
    'short' also doesn't provide any portability property since you've
    no guarantee whether the necessary ranges can be represented with
    them. That's why we had introduced types with size-guarantee (that
    later became part of the language for obvious reasons). Consequently
    we have always provided explicit (e.g. CPP controlled) conditional
    compiles of these types. And then there was the coinciding printf()
    format specifier issue; so there's again means necessary to address
    that (say, own low-level functions for explicitly determined types).
    In short; in practice these types did not help us WRT portability,
    or only in the more conservative application cases.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Mon Apr 14 08:44:34 2025
    On 13/04/2025 21:14, Michael S wrote:
    On Sun, 13 Apr 2025 20:53:03 +0200
    David Brown <david.brown@hesbynett.no> wrote:

    On 13/04/2025 19:57, Michael S wrote:
    On Fri, 11 Apr 2025 11:15:44 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    bart <bc@freeuk.com> writes:
    [...]
    8 A u64 type can be denoted as either 'uint64_t' OR as some
    combination of the tokens (long, long, unsigned, [int])

    "uint64_t" and "unsigned long long int" do not mean the same thing.


    And it's a PITA.


    There is only one thing I find a little bit annoying about the sized
    integer types in C - the printf specifiers.


    Yes, in practice it is the main reason why I find absence of system-independent correspondence between [u]intn_t types and basic
    integer types a PITA. But there exist few other cases where it causes problems, e.g. using Intel intrinsic like _addcarry_u64() in code that
    have to be compiled on different 64-bit OSes.

    I don't find that a PITA, because I don't have to write such code :-)

    (I appreciate that other people might have things they don't like about
    the sized integer types, or have code for which potential
    incompatibilities between types with the same size and representation
    can be annoying. I can only complain about the things I find annoying.)


    As to why you feel stronger than you about it, I'd guess it's because I
    write code that has to be compiled, preferably without warnings, on
    different platforms more often than you do. Most of 32-bit and 64-bit platforms are compatible to each other, but 64-bit Unix/Linus is at
    odds with the rest of them.


    My targets for C (and C++) are mostly 32-bit ARM these days, and the
    smaller microcontrollers I sometimes use are consistent with ARM in
    having "uint32_t" be "unsigned long int". I occasionally also target
    64-bit Linux, but I haven't had any issues there either - but that may
    be due to the type of code I have written.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Mon Apr 14 11:16:11 2025
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    Is it that hard to provide a proper for-loop where you don't have to
    spell out every single detail?

    You mean like in Algol 68 or maybe Simula? (Both are interesting.)

    I mean like pretty much every language that hasn't copied C's for-loop
    syntax. For example Lua:

    for i = a, b # iterate over a..b inclusive
    s1
    s2
    ...
    end


    Fortran managed it in the 1950s!

    I obviously don't recall FORTRAN good enough to have memorized any
    "good" feature. But as (mostly?) an anachronism it anyway doesn't
    matter any more (to me).

    Fortran's loops looked like this:

    do 100 i = a, b
    s1
    s2
    ...
    100 continue

    The C equivalant is this:

    for (i = a; i <= b; ++i)
    stmt

    Differences:

    * Fortran has an official loop index variable 'i'. C doesn't; a loop can
    look like this:

    for (x=0; y=1; z=2)

    * C needs you to provide the exact comparison op

    * C needs you to write the index 'i' three times (with no compiler check
    that they're all identical!)

    * C needs you to specify how to increment the loop index

    * Fortran allows an arbitrary number of statements in the loop body.
    C allows only one; multiple statements require a compound statement.



    WRT FORTRAN _loops_ I (faintly) only recall a syntax ambiguity "by
    design" (and jump labels); certainly not something to advocate.

    There was ambiguity due to spaces not being significant. Or rather,
    there was potential for certain typos not being detectable:

    do100i=1,10 # do-loop
    do100i=1.10 # assign 1.10 to 'do100i'

    Algol68 also ignores white space, at least within identifiers. That
    would have caused clashes with reserved words, so that 'stropping' had
    to be employed, resulting in ugly and fiddly-to-type source code.

    Of course, in printed material, reserved words simply used bold type,
    and it looked gorgeous. The reality on a computer was rather different.






    Janis


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From tTh@21:1/5 to bart on Mon Apr 14 12:51:11 2025
    On 4/14/25 12:16, bart wrote:
        do 100 i = a, b
            s1
            s2
            ...
    100 continue

    do i = a, b
    s1
    s2
    end do

    --
    ** **
    * tTh des Bourtoulots *
    * http://maison.tth.netlib.re/ *
    ** **

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to tTh on Mon Apr 14 12:12:15 2025
    On 14/04/2025 11:51, tTh wrote:
    On 4/14/25 12:16, bart wrote:
         do 100 i = a, b
             s1
             s2
             ...
    100 continue

         do i = a, b
            s1
            s2
         end do


    That's even better.

    However my earlier point was that Fortran (ie. FORTRAN) had a simple
    iterative loop even in the 1950s. Then you had to use those numeric labels.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Janis Papanagnou on Mon Apr 14 09:00:11 2025
    On 4/14/25 00:43, Janis Papanagnou wrote:
    ...
    Honestly, this is an old, known argument that I could never fully
    understand. 'char' for characters, 'int' as a register sized entity,
    'short' and 'long' as, say, additions. So far so good. "For a wide
    variety of platforms" you cannot just use 'int' and hope that works
    on 8, 16, or 32 bit processors the same way. Switching to 'long' or
    'short' also doesn't provide any portability property since you've
    no guarantee whether the necessary ranges can be represented with
    them.

    Huh? There's guarantees for every one of those types.

    Obviously, when interfacing with other software, I need to use the types
    used in that interface. and that is the only context in which I would
    use one of the exact-sized types. Whenever I'm free to choose the type
    of an integer variable, I normally prefer the fast size-named types,
    unless storage space is an issue, in which case I use the least
    size-named types. The guarantees associated with the older types make
    them roughly equivalent to the following size-named types:

    [un]signed char [u]int_least8_t
    [unsigned]short [u]int_least16_t
    [unsigned]int [u]int_fast16_t
    [unsigned]long [u]int_least32_t
    [unsigned]long long [u]int_least64_t

    Even before the size-named types came out, I always programmed with
    those types as if they were the corresponding size-named types listed
    above. Those types weren't ideal - too few of them can be described as corresponding to one of the fast size-named types. However, they were
    portable if used with due consideration of what guarantees went with
    each type.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Janis Papanagnou on Mon Apr 14 14:11:28 2025
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 13.04.2025 18:48, bart wrote:
    On 13/04/2025 15:54, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 13/04/2025 12:33, bart wrote:

    Algol68 fits the role of systems language;

    It somehow lost the word 'poorly'!

    That would suprise Burroughs/Unisys, where the operating
    system, database and utilites are all written in Algol.

    Algol68 or Algol60? The former is very different.

    I don't recall whether it was "Burroughs/Unisys" (that Scott mentioned)
    but I know that there were systems programmed in Algol 68.

    If you know Algol 60 you'd probably have recognized that it's unsuited
    for systems programming (as opposed to Algol 68). - At least IMO.

    Burroughs had several flavors of Algol, all with extensions to support
    the stack architecture. The MCP was written in a flavor called NEWP,
    data comm applications were written in DCALGOL. For more info,
    apply to comp.sys.unisys.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Mon Apr 14 23:12:20 2025
    On 2025-04-13, bart <bc@freeuk.com> wrote:
    On 13/04/2025 15:34, Kaz Kylheku wrote:
    On 2025-04-13, bart <bc@freeuk.com> wrote:
    On 13/04/2025 03:27, Janis Papanagnou wrote:
    On 12.04.2025 13:00, bart wrote:

    But I also 100% hate its syntax and various other bits and pieces. (OK, >>>>> about 80% then.)

    (I also don't like its syntax too much. I think I'm just complaining
    less than you about that. BTW, I've got the impression that all the
    shortcomings of "C" are well known by most regulars here; they just
    handle these facts in discussions differently than you.)

    The shortcomings are downplayed considerably. Especially in discussions
    involving me because they don't like it whenever someone states the obvious.

    But also, most here have to use it professionally, so have learned to
    work around it.

    There are lots of examples of people just liking C.

    C itself, or the things that C allowed you to do?

    Me, I like C. I use C in side projects. I will code in C no matter what
    I use at work.

    C is the only acceptable non-Lisp.

    Well, given Knuth's own language was MIX (assembly for a made-up
    machine), it is not surprising he prefers C.

    He wrote TeX in Pascal though. The Web system includes a Pascal to C translator. (I don't know the details.)

    C has spawned imitation in the form of "C like" languages, that all
    started as grenfield projects that could have chosen any syntax
    they wanted.

    Some of this is to be expected: if they started off using brace syntax,
    then their language will use braces. But some of the things they copy
    are odd, like this for-loop from JS:

    for(let i = 1; i <= 36; i++) {

    The first time I encountered a C for loop used for non-numbers
    was a watershed moment for me. I rubbed my eyes once or twice.

    "Wow, wait, you can do that?"

    It might have been in the source code of an IRC client I was
    compiling, where it had something like this:

    for (node = list; node; node = node->next)

    I realized, OMG, this is a great way of defining a for loop
    construct. This is why for is the way it is.

    So much better than the crap languages I used before which restricted a
    dummy variable into going from one number to another.

    That might have been the point after which I didn't look back.

    Later I learned that much of the cool stuff around control flow
    and expressions in C actually came from Lisp.

    - Ternary if: (if test then else).

    - Expressions having values, even assignments: (setq a (setq b (setq c 0)))

    - Loops working with arbitrary data types.

    Is it that hard to provide a proper for-loop where you don't have to
    spell out every single detail? Fortran managed it in the 1950s!

    No, it isn't, especially if you don't need once-only evaluation of the
    range points:

    #define for_range (type, var, from, to) \
    for (type var = from; var <= to; var++)

    Anyway, languages should be programmable so you're not stuck with
    the loop that is built into the parser.

    If I were to pick a non-C language for systems programming today, I
    would take a serious look at Thomas Mertes' Seed 7, probably.

    It lets you define new statement and such.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Tue Apr 15 01:35:22 2025
    On 15/04/2025 00:12, Kaz Kylheku wrote:
    On 2025-04-13, bart <bc@freeuk.com> wrote:

    The first time I encountered a C for loop used for non-numbers
    was a watershed moment for me. I rubbed my eyes once or twice.

    I first time I saw this:

    for(i=0; i<N; ++)

    was such a moment for me. I thought what crappy syntax is that? I'd been
    used to Algol and Pascal and even Fortran, and this looked prehistoric.

    This would have been in either a book or magazine. I don't think my
    opinions about C ever picked.

    (I see there's typo; I tend to leave those in to show the problems.)

    "Wow, wait, you can do that?"

    It might have been in the source code of an IRC client I was
    compiling, where it had something like this:

    for (node = list; node; node = node->next)

    I realized, OMG, this is a great way of defining a for loop
    construct. This is why for is the way it is.

    But it's not a for-loop is it? This is a perfect candidate for a
    while-loop: you are repeating some body of code /while/ some expression
    is true.

    Whereas 'for' implies a control variable which iterates over some bounds
    or values.

    What C calls 'for' is little more than a crass feature like this:

    KEYWORD(A; B; C) D;

    which is roughly transformed to:

    A;
    while (B) {
    {D}
    C;
    }

    It's what you might use in a macro-assembler to crudely emulate HLL
    features.


    So much better than the crap languages I used before which restricted a
    dummy variable into going from one number to another.

    I use these loops almost exclusively:

    Endless loop
    Repeat-N-times loop
    While loop
    Iterate over an integer range
    Iterate over a collection of values

    It is incredibly rate that I need anything else. However I do have some
    extra kinds of loops which are a combination:

    docase do case ... end end
    doswitch do switch ... end end
    doswitchu/x special forms used for fast dispatch loops in
    interpreters

    I can't see the attraction of trying to pack as much arbitrary junk into
    a for-loop header as possible, which just makes it harder to figure what
    the hell kind of loop it is.

    That might have been the point after which I didn't look back.

    Later I learned that much of the cool stuff around control flow
    and expressions in C actually came from Lisp.

    - Ternary if: (if test then else).

    - Expressions having values, even assignments: (setq a (setq b (setq c 0)))

    - Loops working with arbitrary data types.

    For me most such stuff came from Algol68. Did that get it from Lisp? I
    guess nobody knows.

    But let me ask you; in the presumably rare situations where you do
    actually want to iterate over 0 to N-1, what do feel about writing 13 or
    so tokens to express that instead of maybe 6?

    You can create some crummy macro for it, sure, but how do you then feel
    about NEEDING to implement a fundamental feature in a language? A
    million programmers would have to the same thing in a 1000 different ways.

    No, it isn't, especially if you don't need once-only evaluation of the
    range points:

    #define for_range (type, var, from, to) \
    for (type var = from; var <= to; var++)

    Anyway, languages should be programmable so you're not stuck with
    the loop that is built into the parser.

    Help! So for-loops aren't flexible enough, we need every programmer to
    devise their own whacky creations!


    If I were to pick a non-C language for systems programming today, I
    would take a serious look at Thomas Mertes' Seed 7, probably.

    It lets you define new statement and such.

    That is seriously restricted:

    * It doesn't have 'goto' for a start

    * It doesn't like using libraries other than those written as Seed7

    * It is anyway built on top of C, in that it depends on libraries
    written in C ...

    * ... and it compiles to C.

    Also, despite it allowing you to define new syntax, I don't think I've
    seen any Seed7 program look like anything other than Seed7.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to James Kuyper on Tue Apr 15 09:40:17 2025
    On 14.04.2025 15:00, James Kuyper wrote:
    On 4/14/25 00:43, Janis Papanagnou wrote:
    ...
    Honestly, this is an old, known argument that I could never fully
    understand. 'char' for characters, 'int' as a register sized entity,
    'short' and 'long' as, say, additions. So far so good. "For a wide
    variety of platforms" you cannot just use 'int' and hope that works
    on 8, 16, or 32 bit processors the same way. Switching to 'long' or
    'short' also doesn't provide any portability property since you've
    no guarantee whether the necessary ranges can be represented with
    them.

    Huh? There's guarantees for every one of those types.

    Has that changed? - I recall that there were only "compare to"
    relations defined, like |short| <= |int| <= |long|

    and there where systems where it was |short| == |int| == |long|
    and other systems with |short| < |int| == |long|
    or |short| < |int| < |long| or |short| == |int| < |long|


    Obviously, when interfacing with other software, I need to use the types
    used in that interface. and that is the only context in which I would
    use one of the exact-sized types.

    Yes.

    Whenever I'm free to choose the type
    of an integer variable, I normally prefer the fast size-named types,
    unless storage space is an issue, in which case I use the least
    size-named types.

    Yes.

    The guarantees associated with the older types make
    them roughly equivalent to the following size-named types:

    [un]signed char [u]int_least8_t
    [unsigned]short [u]int_least16_t
    [unsigned]int [u]int_fast16_t
    [unsigned]long [u]int_least32_t
    [unsigned]long long [u]int_least64_t

    And that is where I have a different experience. - AFAICT, these
    size equivalences were not a given.


    Even before the size-named types came out, I always programmed with
    those types as if they were the corresponding size-named types listed
    above. Those types weren't ideal - too few of them can be described as corresponding to one of the fast size-named types. However, they were portable if used with due consideration of what guarantees went with
    each type.

    Was your programming focused to systems where the sizes were (by
    accident) equal?

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Janis Papanagnou on Tue Apr 15 09:18:15 2025
    On 15/04/2025 08:40, Janis Papanagnou wrote:
    On 14.04.2025 15:00, James Kuyper wrote:
    On 4/14/25 00:43, Janis Papanagnou wrote:
    ...
    Honestly, this is an old, known argument that I could never fully
    understand. 'char' for characters, 'int' as a register sized entity,
    'short' and 'long' as, say, additions. So far so good. "For a wide
    variety of platforms" you cannot just use 'int' and hope that works
    on 8, 16, or 32 bit processors the same way. Switching to 'long' or
    'short' also doesn't provide any portability property since you've
    no guarantee whether the necessary ranges can be represented with
    them.

    Huh? There's guarantees for every one of those types.

    Has that changed?

    No. The guarantees go at least as far back as 1989.

    - I recall that there were only "compare to"
    relations defined, like |short| <= |int| <= |long|

    From back in the day:

    [quote from ANSI C89]

    2.2.4.2 Numerical limits

    A conforming implementation shall document all the limits
    specified in this section, which shall be specified in the
    headers <limits.h> and <float.h> .

    "Sizes of integral types <limits.h>"

    The values given below shall be replaced by constant
    expressions suitable for use in #if preprocessing directives.
    Their implementation-defined values shall be equal or greater in
    magnitude (absolute value) to those shown, with the same sign.

    [end quote]

    The Standard then dictates the minimum ranges that each numerical
    type must support.

    <snip>

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Tue Apr 15 14:05:46 2025
    bart <bc@freeuk.com> writes:
    On 15/04/2025 00:12, Kaz Kylheku wrote:
    On 2025-04-13, bart <bc@freeuk.com> wrote:

    The first time I encountered a C for loop used for non-numbers
    was a watershed moment for me. I rubbed my eyes once or twice.

    I first time I saw this:

    for(i=0; i<N; ++)

    was such a moment for me. I thought what crappy syntax is that

    It's not correct syntax at all, and wouldn't compile, so yes,
    it's is crappy syntax.

    for(i = 0; i < N; i++)

    on the other hand, is perfectly understandable and extremely
    flexible.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Janis Papanagnou on Tue Apr 15 10:39:42 2025
    On 4/15/25 03:40, Janis Papanagnou wrote:
    On 14.04.2025 15:00, James Kuyper wrote:
    On 4/14/25 00:43, Janis Papanagnou wrote:
    ...
    Honestly, this is an old, known argument that I could never fully
    understand. 'char' for characters, 'int' as a register sized entity,
    'short' and 'long' as, say, additions. So far so good. "For a wide
    variety of platforms" you cannot just use 'int' and hope that works
    on 8, 16, or 32 bit processors the same way. Switching to 'long' or
    'short' also doesn't provide any portability property since you've
    no guarantee whether the necessary ranges can be represented with
    them.

    Huh? There's guarantees for every one of those types.

    Has that changed?

    No, that has not changed since C was first standardized, except by the
    addition of _Bool and long long to the list. There are maximum permitted
    values for the *_MIN macros #defined in <limits.h>, and minimum
    permitted values for the *_MAX macros:

    #define BOOL_MAX 1
    #define CHAR_MAX UCHAR_MAX or SCHAR_MAX
    #define CHAR_MIN 0 or SCHAR_MIN
    #define UCHAR_MAX 255
    #define USHRT_MAX 65535
    #define SCHAR_MAX +127
    #define SCHAR_MIN -128
    #define SHRT_MAX +32767
    #define SHRT_MIN -32768
    #define INT_MAX +32767
    #define INT_MIN -32768
    #define UINT_MAX 65535
    #define LONG_MAX +2147483647
    #define LONG_MIN -2147483648
    #define LLONG_MAX +9223372036854775807
    #define LLONG_MIN -9223372036854775808
    #define ULONG_MAX 4294967295
    #define ULLONG_MAX 18446744073709551615

    ... - I recall that there were only "compare to"
    relations defined, like |short| <= |int| <= |long|

    and there where systems where it was |short| == |int| == |long|
    and other systems with |short| < |int| == |long|
    or |short| < |int| < |long| or |short| == |int| < |long|

    "For any two integer types with the same signedness and different
    integer conversion rank (see 6.3.1.1), the range of values of the type
    with smaller integer conversion rank is a subrange of the values of the
    other type." (6.2.5p10)
    "The range of nonnegative values of a signed integer type is a subrange
    of the corresponding unsigned integer type, ..." (6.2.5p11).

    Note, however, that this does not constrain the physical sizes of the
    types. A fully conforming implementation of C could have sizeof(short) > sizeof(long long), so long as a short int has a sufficiently large
    number of padding bits. You'd have a hard time convincing people that
    this was a good idea, but it wouldn't prevent such an implementation
    from conforming to the standard.

    The guarantees associated with the older types make
    them roughly equivalent to the following size-named types:

    [un]signed char [u]int_least8_t
    [unsigned]short [u]int_least16_t
    [unsigned]int [u]int_fast16_t
    [unsigned]long [u]int_least32_t
    [unsigned]long long [u]int_least64_t

    And that is where I have a different experience. - AFAICT, these
    size equivalences were not a given.

    They are implied by the limits I've listed above.

    Even before the size-named types came out, I always programmed with
    those types as if they were the corresponding size-named types listed
    above. Those types weren't ideal - too few of them can be described as
    corresponding to one of the fast size-named types. However, they were
    portable if used with due consideration of what guarantees went with
    each type.

    Was your programming focused to systems where the sizes were (by
    accident) equal?

    For something like 30 years of my career, I worked under rules that
    emphasized portability. If it was permitted for a conforming
    implementation of C to have two types to have the same size, I was not permitted to write code that assumed that they were different sizes. It
    it was permitted for them to be different sizes, I was not permitted to
    write code that assumed they were the same size. And of course, any
    assumptions about the actual sizes of the types were strictly forbidden.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Tue Apr 15 15:44:10 2025
    On 15/04/2025 15:05, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 00:12, Kaz Kylheku wrote:
    On 2025-04-13, bart <bc@freeuk.com> wrote:

    The first time I encountered a C for loop used for non-numbers
    was a watershed moment for me. I rubbed my eyes once or twice.

    I first time I saw this:

    for(i=0; i<N; ++)

    was such a moment for me. I thought what crappy syntax is that

    It's not correct syntax at all, and wouldn't compile, so yes,
    it's is crappy syntax.

    You snipped the bit where I acknowledge the omission.



    for(i = 0; i < N; i++)

    on the other hand, is perfectly understandable and extremely
    flexible.


    What about this one:

    for(i = 0; j < N; k++)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to David Brown on Tue Apr 15 15:44:14 2025
    David Brown <david.brown@hesbynett.no> wrote:

    There is no "import" or "export" in C - only "internal linkage" or
    "external linkage" - file local or program global, if you prefer. The combinations "declare with external linkage but do not define" and
    "declare with external linkage and define" are used to achieve import
    and export of identifiers.

    But its home module sees both of these, including the
    'extern' version, but here 'abc' is exported!

    Yes - "extern" does /not/ mean "export".


    That is counter-intuitive: how can a module both import a name (via
    'extern int') and export it (via 'int' without 'static')?

    If the keyword "extern" were written "export", I'd agree on it being counter-intuitive. But it is not written that way. The point of
    "extern" is that it indicates external linkage - program-wide sharing of
    the identifier in question. It is shared amongst the units that exports
    it (by defining it) and units that import it (by using it), usually
    achieved by having the same shared header included by the exporting unit
    and the importing units. This has a huge advantage compared to
    languages where importing units read some kind of interface import file
    but the exporting one does not - it is extremely easy in C to ensure
    that all your shared identifiers match up correctly by keeping all
    external declarations in shared headers and all definitions in C files.

    The only advantage of C rules is compatibility with linkers used
    in seventies. More precisely, better languages need to implement
    some mechanizm to propagate information between source files
    and in some cases also do part of linking (gcc has 'collect2'
    for such purposes).

    C header files work "good enough", but really have no advantages
    (except for backwards compatibility and ease of implementation)
    compared to proper module system.

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Tue Apr 15 15:31:22 2025
    bart <bc@freeuk.com> writes:
    On 15/04/2025 15:05, Scott Lurndal wrote:



    What about this one:

    for(i = 0; j < N; k++)

    Any fool can write bad code in any language, including yours.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Tue Apr 15 17:38:40 2025
    On 15/04/2025 16:31, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 15:05, Scott Lurndal wrote:



    What about this one:

    for(i = 0; j < N; k++)

    Any fool can write bad code in any language, including yours.


    It is impossible to write such a *FOR* loop in any language that
    actually implements it properly.

    C's 'FOR' loop is misnomer for a weird feature that is like 'while' but
    with three components. A feature where there is virtually no checking so
    that it can comprise any kind of nonsense.

    It doesn't have a dedicated feature for iterating a variable over a range.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mikko@21:1/5 to Thiago Adams on Fri Apr 18 10:30:10 2025
    On 2025-04-04 19:23:30 +0000, Thiago Adams said:

    What do you think of this control block?

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) quit; /*goes to else part*/

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) quit;
    }

    }
    else
    {
    /*some error*/
    }

    There should be a way to have multiple quits and way to selsct different
    "else" blocks depending on which quit was executed.

    But a new language feature is not necessary:

    int quit = 0;

    do
    {
    FILE f = fopen("file.txt", "r");

    if (f == NULL) { quit = 1; goto next; }

    /*success here*/
    for (int i =0; i < 10; i++){
    ...
    if (error) { quit = 2; goto next; }
    }

    }
    switch (quit) {
    {
    case 1: { /* no file */ } break:
    case 2: { /*some error*/ } break:
    }

    --
    Mikko

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Sun May 4 22:01:10 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    [...]

    I withdraw my earlier statement. Please leave me out of any
    future discussion of the subject.

    Do you mean that your earlier statement was incorrect (i.e., that
    the types are compatible), or do you merely wish to pretend you
    never said anything without taking a position on whether they're
    compatible, or do you refuse to say?

    I am specifically _not_ saying either that my earlier statement
    was right or that my earlier statement was wrong. My hope is
    that henceforth people will act as though the statement never
    entered the discussion. Does that clarify the matter for you?

    That answers precisely what I was asking, thank you.

    As often happens, I am mystified by your decision, but it is
    unquestionably yours.

    I'm sorry. I didn't mean it to be mystifying; just the opposite.

    I'll try not to include you in any further discussion, but I do
    not promise to try very hard.

    For reference my request to leave me out of any future discussion
    of the subject was meant primarily for the person to whose post
    I was responding. But thank you for your effort.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Mon May 5 16:12:12 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    bart <bc@freeuk.com> writes:
    [...]

    Someone, not anyone but the all-knowing Tim, said: "and those types
    are not compatible, because the two struct tags are different."

    Do you agree with that? Or is there something more to making two types
    be incompatible?

    I don't recall the exact discussion and I wouldn't try to speak
    for Tim, but I suspect he was saying that the fact that the two
    struct tags are different is enough to know that the types are
    not compatible. [...]

    Considering the circumstances, rather than focusing on what I
    (may have) meant, it seems better to focus on what is true,
    whether I meant it or not.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Mon May 5 17:01:28 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    bart <bc@freeuk.com> writes:
    [...]

    Someone, not anyone but the all-knowing Tim, said: "and those types
    are not compatible, because the two struct tags are different."

    Do you agree with that? Or is there something more to making two types >>>> be incompatible?

    I don't recall the exact discussion and I wouldn't try to speak
    for Tim, but I suspect he was saying that the fact that the two
    struct tags are different is enough to know that the types are
    not compatible. [...]

    Considering the circumstances, rather than focusing on what I
    (may have) meant, it seems better to focus on what is true,
    whether I meant it or not.

    Feel free to do so, rather than resurrecting a post from nearly a
    month ago to criticize me for what I chose to focus on

    My comment wasn't meant as a criticism, but only a suggested
    improvement. I'm sorry if it came across differently.

    Also the comment was not meant as a statement about you but about
    the style of the posting. It's about wording, not about you
    personally.

    and adding nothing to the actual discussion.

    The discussion died out weeks ago. Why would you resurrect it?

    I had no intention of resurrecting a discussion. I responded
    because I had something to say.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Wuns Haerst@21:1/5 to All on Wed May 7 06:56:12 2025
    Am 04.04.2025 um 22:58 schrieb Thiago Adams:
    Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:
    Thiago Adams <thiago.adams@gmail.com> writes:

       What do you think of this control block?

       do
       {
          FILE f = fopen("file.txt", "r");

          if (f == NULL) quit; /*goes to else part*/

          /*success here*/
          for (int i =0; i < 10; i++){
              ...
              if (error) quit;
          }

       }
       else
       {
          /*some error*/
       }

    I think it doesn't belong in comp.lang.c.

    I also think you have been participating in comp.lang.c
    long enough to know better.  Kindly take your language
    fantasies somewhere else.

    I think the only reason you're saying that is because it's not
    implemented in GCC, Clang, or maybe even MSVC. I've never seen you
    complain about any GCC extensions here.



    I think Thiago's idea is brilliant. He should become a
    member of the standardization committee. He's welcome
    to post suggestions like this here.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Wuns Haerst on Wed May 7 06:52:00 2025
    On 07/05/2025 05:56, Wuns Haerst wrote:
    I think Thiago's idea is brilliant. He should become a
    member of the  standardization committee. He's welcome
    to post suggestions like this here.

    Irony is always dangerous. Prepare for incoming.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Wuns Haerst@21:1/5 to All on Wed May 7 15:46:38 2025
    Am 07.05.2025 um 07:52 schrieb Richard Heathfield:
    On 07/05/2025 05:56, Wuns Haerst wrote:
    I think Thiago's idea is brilliant. He should become a
    member of the  standardization committee. He's welcome
    to post suggestions like this here.

    Irony is always dangerous. Prepare for incoming.

    There's no irony here, Thiago's idea is really good!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Wuns Haerst on Thu May 8 06:04:30 2025
    Wuns Haerst <Wuns.Haerst@wurstfabrik.at> writes:

    [...]

    I think Thiago's idea is brilliant. He should become a
    member of the standardization committee. He's welcome
    to post suggestions like this here.

    If someone wants to propose a revision or addition to the
    ISO C standard, the appropriate newsgroup in which to post
    it is comp.std.c, not comp.lang.c.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Bonita Montero on Fri May 9 15:38:58 2025
    On 09/05/2025 15:25, Bonita Montero wrote:
    Am 10.04.2025 um 00:07 schrieb Tim Rentsch:

    When someone is responding to a post, they are responding ONLY to
    the content in the posting they are responing to;  not to some
    earlier posting in the same thread, not to a different posting
    submitted two weeks ago, not to what you meant to say but didn't,
    not to thoughts in your head but that you didn't say, but ONLY TO
    WHAT IS SAID IN THE POSTING BEING RESPONDED TO.

    If you can learn to follow this simple rule everyone in the
    newsgroup will be better off, including you.

    You're constantly overwhelmed by what people write here. Both in
    terms of content and the nature of the discussion. Don't try to
    constantly set rules; that seems petty.

    Tim's not setting a draconian rule in stone. He's presenting a
    perfectly sensible rule of thumb that is based on his decades of
    experience of posting to this group. Usenet works best when you
    snip the bits you're not replying to, and reply only within the
    context you have retained. Nearly all the leading experts in this
    group nearly always observe this rule of thumb, because it's
    simple common sense so to do.

    On what basis do you justify laying down your law for Tim to follow?

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bonita Montero on Fri May 9 15:01:45 2025
    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 06.04.2025 um 17:14 schrieb Tim Rentsch:

    My impression was that "defer", or something very much like
    it, is being considered for inclusion in a future C standard. ...

    With C++ you can have defer without extending the language.

    This, however is comp.lang.c.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Bonita Montero on Fri May 9 15:31:34 2025
    On 2025-05-09, Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 06.04.2025 um 17:14 schrieb Tim Rentsch:

    My impression was that "defer", or something very much like
    it, is being considered for inclusion in a future C standard. ...

    With C++ you can have defer without extending the language.

    Nope. First some dude called Bjarne has to take C and
    extend it into "C With Classes". That sets into motion a voracious language-extending machine which, some forty years later,
    finally allows your proosed code to work.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Fri May 9 17:43:27 2025
    On 09/05/2025 16:42, Bonita Montero wrote:
    Am 09.05.2025 um 16:38 schrieb Richard Heathfield:

    Tim's not setting a draconian rule in stone. He's presenting a
    perfectly sensible rule of thumb that is based on his decades of
    experience of posting to this group. ...

    No, he's just annoyed. It is perfectly normal to
    go from one topic to another in such a deep thread

    He was not annoyed at people jumping topics. (Well, he might well have
    been annoyed at that too - I don't claim to know Tim's mind, just his
    posts.) He was frustrated by another poster making comments that
    referred to details in another post. Occasionally that might make
    sense, to avoid repetition, but often it fragments the conversation and
    makes it hard for people to know what the poster is talking about.

    Thus Tim's suggestion is generally a good rule, but as Richard says, it
    is not set in stone, and of course Tim is perfectly aware that he can
    write rules, but has no authority to enforce them.

    I posted a rule of my own recently - do not reply to posts that are over
    a week old in dead threads unless you have something very significant or interesting to say. I hope you learn to follow that one too.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Bonita Montero on Fri May 9 16:26:03 2025
    On 09/05/2025 16:04, Bonita Montero wrote:
    Am 09.05.2025 um 17:01 schrieb Scott Lurndal:
    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 06.04.2025 um 17:14 schrieb Tim Rentsch:

    My impression was that "defer", or something very much like
    it, is being considered for inclusion in a future C standard.
    ...

    With C++ you can have defer without extending the language.

    This, however is comp.lang.c.

    I'm just trying to make it clear that C lacks convenience
    and  productivity on every level.

    Then use something convenient and productive. But please confine
    your discussions of your chosen alternative to comp.lang.your.chosen.alternative instead of dragging them into
    comp.lang.c, where we discuss C.

    C folks simply don't want
    to abandon their minimalism paradigm, which continues to
    make the language very difficult to use.

    Then do by all means use something easier. But please confine
    your discussions of your chosen alternative to comp.lang.your.chosen.alternative instead of dragging them into
    comp.lang.c, where we discuss C.

    You don't get to pick the group's topic any more than I do.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Richard Heathfield on Fri May 9 17:54:26 2025
    On 09.05.2025 17:26, Richard Heathfield wrote:
    On 09/05/2025 16:04, Bonita Montero wrote:
    Am 09.05.2025 um 17:01 schrieb Scott Lurndal:
    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 06.04.2025 um 17:14 schrieb Tim Rentsch:

    My impression was that "defer", or something very much like
    it, is being considered for inclusion in a future C standard. ...

    With C++ you can have defer without extending the language.

    This, however is comp.lang.c.

    I'm just trying to make it clear that C lacks convenience
    and productivity on every level.

    Then use something convenient and productive. But please confine your discussions of your chosen alternative to
    comp.lang.your.chosen.alternative instead of dragging them into
    comp.lang.c, where we discuss C.

    C folks simply don't want
    to abandon their minimalism paradigm, which continues to
    make the language very difficult to use.

    Then do by all means use something easier. But please confine your discussions of your chosen alternative to
    comp.lang.your.chosen.alternative instead of dragging them into
    comp.lang.c, where we discuss C.

    (That post sounds and is written like a mantra. Gee!)

    Since some folks feel comfortable in their "C" bubble I understand
    that these people might feel annoyed by such posts.

    But showing deficiencies (in "C") and providing counter-examples or alternatives from other languages [as done here] should be welcome.
    (IMO. YMMV, of course.)

    (Note: I'm not saying that the previous post's content is correct,
    just that it was obviously meant as an improvement, which could or
    not affect evolution of "C" if considered; a point for discussion
    [for those who think it's worth].)

    But of course no one forces these annoyed people to read all posts;
    suggestions had already been given to just skip those inconvenient
    threads or subhreads.

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Richard Heathfield on Fri May 9 17:07:26 2025
    Richard Heathfield <rjh@cpax.org.uk> writes:
    On 09/05/2025 16:54, Janis Papanagnou wrote:

    <snip>


    Since some folks feel comfortable in their "C" bubble I understand
    that these people might feel annoyed by such posts.

    Each newsgroup has a topic. I subscribe to no fewer than ten
    newsgroups, because I am interested in those ten topics. If you
    are interested in C++, you can subscribe to comp.lang.c++ and
    chat about it all day long and nobody will bat an eyelid. I have
    no doubt that many comp.lang.c subscribers are also subscribed to >comp.lang.c++. Why not join their number, and keep the salt in
    the salt pot and the pepper in the pepper pot?


    But showing deficiencies (in "C") and providing counter-examples or
    alternatives from other languages [as done here] should be welcome.

    Why?

    Four important ways that C scores over other languages are:

    * Speed
    * Simplicity
    * Size
    * Portability

    The more you add, the more likely you are to slow it down, the
    more complex you make it, the bigger it gets, and the harder it
    is to port.

    To be fair to C++ (not to C++ fanatics, however), it is
    worth pointing out that one doesn't need to use all the
    C++ crapola to leverage some of the good features of
    C++ (C with classes, basically) and obtain the same four
    important characteristics you raise above.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Janis Papanagnou on Fri May 9 17:26:02 2025
    On 09/05/2025 16:54, Janis Papanagnou wrote:

    <snip>


    Since some folks feel comfortable in their "C" bubble I understand
    that these people might feel annoyed by such posts.

    Each newsgroup has a topic. I subscribe to no fewer than ten
    newsgroups, because I am interested in those ten topics. If you
    are interested in C++, you can subscribe to comp.lang.c++ and
    chat about it all day long and nobody will bat an eyelid. I have
    no doubt that many comp.lang.c subscribers are also subscribed to comp.lang.c++. Why not join their number, and keep the salt in
    the salt pot and the pepper in the pepper pot?


    But showing deficiencies (in "C") and providing counter-examples or alternatives from other languages [as done here] should be welcome.

    Why?

    Four important ways that C scores over other languages are:

    * Speed
    * Simplicity
    * Size
    * Portability

    The more you add, the more likely you are to slow it down, the
    more complex you make it, the bigger it gets, and the harder it
    is to port.

    If you want C++, you know where to find it.

    But of course no one forces these annoyed people to read all posts; suggestions had already been given to just skip those inconvenient
    threads or subhreads.

    I've got a better idea. Let's hold those C++ discussions in a
    group where C++ is topical.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Janis Papanagnou on Fri May 9 19:09:38 2025
    On 09/05/2025 17:54, Janis Papanagnou wrote:
    On 09.05.2025 17:26, Richard Heathfield wrote:
    On 09/05/2025 16:04, Bonita Montero wrote:
    Am 09.05.2025 um 17:01 schrieb Scott Lurndal:
    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 06.04.2025 um 17:14 schrieb Tim Rentsch:

    My impression was that "defer", or something very much like
    it, is being considered for inclusion in a future C standard. ...

    With C++ you can have defer without extending the language.

    This, however is comp.lang.c.

    I'm just trying to make it clear that C lacks convenience
    and productivity on every level.

    Then use something convenient and productive. But please confine your
    discussions of your chosen alternative to
    comp.lang.your.chosen.alternative instead of dragging them into
    comp.lang.c, where we discuss C.

    C folks simply don't want
    to abandon their minimalism paradigm, which continues to
    make the language very difficult to use.

    Then do by all means use something easier. But please confine your
    discussions of your chosen alternative to
    comp.lang.your.chosen.alternative instead of dragging them into
    comp.lang.c, where we discuss C.

    (That post sounds and is written like a mantra. Gee!)

    Since some folks feel comfortable in their "C" bubble I understand
    that these people might feel annoyed by such posts.

    But showing deficiencies (in "C") and providing counter-examples or alternatives from other languages [as done here] should be welcome.
    (IMO. YMMV, of course.)


    Comparisons between C and other languages can certainly be on-topic for
    a C group. And deficiencies of C are as topical as the language's good
    points.

    However, Bonita's post here - like almost all Bonita's posts in this
    group - are not helpful or topical, but merely trolls of "C++ is vastly
    better than C - look at this line noise to see what you can do in C++".

    Consider this about Bonita's post :

    1. It was full of code in a non-topical language.

    2. The code could not compile without additional headers, so is specific
    to the poster's machine.

    3. No one asked for or showed any interest in having C++ code for a
    "defer" feature. (Posting non-C code can be appropriate if other people
    want to see it.)

    4. Everyone familiar with or interested in C++ will already know that
    you can make a "defer" feature in C++. Any reasonably competent C++
    programmer could make such a template class.

    5. Everyone familiar with C already knows of the existence of C++, and
    knows where to find out more about it if it is of interest.

    6. The post was about a "defer" feature, which was not in any way the
    topic of the thread.

    7. The post was a reply to a month-old dead thread.

    8. The poster has made vast numbers of such posts in this group, and has consequently been killfilled by many regulars here.


    It is not at all surprising that people find Bonita's posts in
    comp.lang.c annoying, and would be happier if they were restricted to comp.lang.c++. Most people just ignore them, others use killfiles, and
    some people optimistically try to persuade Bonita not to write such
    posts. I'd be surprised if there was anyone who actually thought they
    were a positive contribution to the group.


    As a general principle, I agree with you that languages other than C can
    at times be relevant and interesting in this group - but in this
    specific case, I see no value in Bonita's post.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Fri May 9 19:18:12 2025
    On 09/05/2025 19:11, Bonita Montero wrote:
    Am 09.05.2025 um 19:09 schrieb David Brown:

    4. Everyone familiar with or interested in C++ will already know that
    you can make a "defer" feature in C++.  Any reasonably competent C++
    programmer could make such a template class.

    The defer-class is rather simple, but the xdefer-class is rather tricky because it is a concatenation of structures of different types.



    This is the wrong newsgroup, and the wrong thread. If you want to post
    that kind of thing, feel free to do so in comp.lang.c++. Someone there
    might find it interesting.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Scott Lurndal on Fri May 9 19:11:40 2025
    On 09/05/2025 18:07, Scott Lurndal wrote:
    Richard Heathfield <rjh@cpax.org.uk> writes:

    <snip>

    Four important ways that C scores over other languages are:

    * Speed
    * Simplicity
    * Size
    * Portability

    The more you add, the more likely you are to slow it down, the
    more complex you make it, the bigger it gets, and the harder it
    is to port.

    To be fair to C++ (not to C++ fanatics, however), it is
    worth pointing out that one doesn't need to use all the
    C++ crapola to leverage some of the good features of
    C++ (C with classes, basically) and obtain the same four
    important characteristics you raise above.

    Sure. On the other hand, C++ already has classes.

    If I want to tighten a nut, I use an adjustable spanner. If I
    want a hole, I don't pick up a bit in the spanner's jaws and do a
    cack-handed job; I pick up a drill. Tools don't compete... or
    shouldn't.

    I have classes at my fingertips whenever I want them, I don't
    have to wait 20 years for the ISO guys to change C, and C gets to
    stay light and tight.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Bonita Montero on Fri May 9 19:29:23 2025
    On 09/05/2025 18:09, Bonita Montero wrote:
    Am 09.05.2025 um 18:26 schrieb Richard Heathfield:

    * Speed
    * Simplicity
    * Size
    * Portability

    The same can be said about C++, but the simplicity in C++
    is on a different level.

    I know. I have used C++ a fair bit over the years. If ever I wish
    to discuss that language, there is a newsgroup for that purpose.
    This newsgroup, however, is for discussing C.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Bonita Montero on Fri May 9 19:35:08 2025
    On 09/05/2025 19:21, Bonita Montero wrote:
    Am 09.05.2025 um 20:11 schrieb Richard Heathfield:

    I have classes at my fingertips whenever I want them, I don't
    have to wait 20 years for the ISO guys to change C, and C gets
    to stay light and tight.

    With C the language is light and compact, with C++ the written
    code is light and compact.

    Fortunately, Thunderbird has an excellent killfile facility.

    Bye now.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Sun May 11 19:05:41 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Fri, 11 Apr 2025 17:22:37 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wrote:

    On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:

    On Thu, 10 Apr 2025 17:59:15 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    An understanding of what "compatible types" means.

    Bart didn't say that types are compatible or non-compatible.
    He said that they are 'compatible enough'. That is not terminology
    of C Standard, but terminology of his own. And he seems to
    understand it.

    In my own translation, 'compatible enough' means that when these
    structs are accessed then any sane or even semi-sane compiler will
    generate code that will have the same effect as in case of access
    through structures with literally identical declarations.

    so struct { long x; } and struct { int x; } are compatible enough,
    in situations that are portable enough.

    I wish they would be, but according to C Standard they are not,
    ene when both represent 32-bt signed integer. That's because of
    misfeature called 'strong aliasing rules'.
    IMO, C would become better without this misfeature.

    I think this reaction is rather shortsighted. Making this change
    would incur several downsides, and offers no significant upside
    that I can see.

    First it would greatly complicate the language semantics.
    Whether a program is meaningful, and if so what the meaning is,
    would be much harder to state than it is now.

    Second it would imply that whether a program is well-defined is a
    lot more dependent on implementation-specific choices than it is
    now.

    Third, as a consequence of that, it would be harder to write
    program verification tools, because they would need to take these
    more extensive implementation dependencies into consideration.

    Fourth, there would be consequences for program optimization, and
    it is hard to dismiss those. Some people may not care about the
    optimizations losses, but certainly many people want the benefits
    of those optimizations.

    Fifth, related to the previous point, as a practical matter it would
    make getting the optimization benefits back again be nearly
    impossible. As things are now, it's easy to have a compiler option
    to disable the consequences of strong typing rules, and the result
    can still be a conforming implementation. But if the C standard
    would prescribe the semantics of cross-type access, then any option
    to ignore the implications of that prescription would necessarily
    make using said option result in a non-conforming implementation.

    To say the last point another way, with things as they are now
    developers can choose whether they want to observe the cross-type
    access restrictions, or ignore them, and still get a C compiler.
    If the effective type rules were discarded, there is no way to
    choose the more-optimizing path without getting something that
    is not a C compiler.

    Given that you can always get what you want either by choosing
    an appropriate compiler option (if available) or by using one of
    the well-known legal workarounds, I think it's hard to make a
    case that getting rid of the effective type restrictions is a
    good idea.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Mon May 12 01:30:05 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [...]

    Read what people write, not what you think they meant.

    This rule is a good one for other people too.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Tim Rentsch on Mon May 12 16:37:36 2025
    On 12/05/2025 04:05, Tim Rentsch wrote:
    Michael S <already5chosen@yahoo.com> writes:

    On Fri, 11 Apr 2025 17:22:37 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wrote:

    On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:

    On Thu, 10 Apr 2025 17:59:15 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    An understanding of what "compatible types" means.

    Bart didn't say that types are compatible or non-compatible.
    He said that they are 'compatible enough'. That is not terminology
    of C Standard, but terminology of his own. And he seems to
    understand it.

    In my own translation, 'compatible enough' means that when these
    structs are accessed then any sane or even semi-sane compiler will
    generate code that will have the same effect as in case of access
    through structures with literally identical declarations.

    so struct { long x; } and struct { int x; } are compatible enough,
    in situations that are portable enough.

    I wish they would be, but according to C Standard they are not,
    ene when both represent 32-bt signed integer. That's because of
    misfeature called 'strong aliasing rules'.
    IMO, C would become better without this misfeature.

    I am in two minds about this. I think there are good reasons for
    wanting compatibility between different integer types of the same size.
    But I prefer stronger separation between user-defined types - structs in C.

    In particular, I think it would be a big step backwards if independent
    struct types with the same fields were compatible - that would mean
    variables of those types could be assigned to each other, or used as
    parameters to functions, or pointers to those types could be intermixed.
    C does not make it convenient to have strong types, in comparison to
    many other languages - reducing the protections they give would make it
    far easier for coding errors to slip through.

    For plain integer types, however, I think the argument for making
    equal-sized types compatible is a lot stronger. Some compilers
    specifically say that they allow aliasing between such types (MSVC,
    according to what I have read, have said they never intend to support
    "strict aliasing" optimisations). Many software projects (such as
    Linux) use "-fno-strict-aliasing". And countless C programmers
    mistakenly believe that identically sized integer types are compatible
    (though I am not advocating for a weaker language simply because some
    users misunderstand the rules).


    I think this reaction is rather shortsighted. Making this change
    would incur several downsides, and offers no significant upside
    that I can see.

    First it would greatly complicate the language semantics.
    Whether a program is meaningful, and if so what the meaning is,
    would be much harder to state than it is now.

    The semantics I would recommend are extremely simple - arithmetic types
    which have identical sizes, values, and representations, should be
    compatible.

    As an alternative wording, I think it would be fine to leave the type compatibility rules as they are and make this change to the "effective
    type" rules in 6.5p7.


    Second it would imply that whether a program is well-defined is a
    lot more dependent on implementation-specific choices than it is
    now.

    It would make some programs that are currently incorrect, correct. And
    yes, it would mean that if code mixes up types and pointers, code may
    not then be portable - for example, code that passed the address of an
    "int" to a function requesting a "pointer to long" would compile on
    64-bit Windows and not on 64-bit Linux. But a lot of code is already non-portable, and I do not think this suggestion would make the
    situation significantly different.

    In particular, in situations where this change would allow code that
    previously had a constraint error, the code would now work as expected.
    The alternative solution currently used in many cases where the
    programmer knows that the type sizes are the same even though they are incompatible, is to use a cast - that will "keep the compiler happy" but
    will often not actually be well-defined behaviour. Making identically
    sized and represented integer types compatible would mean the compiler
    is already happy, and the code is well-defined.

    One place where it would help, however, is for code that uses fixed-size integer types. Whether "int32_t" is compatible with "int", "long", or
    other types, is already implementation-specific and the situation is
    often surprising to developers. It seems "obvious" that "int32_t" would
    be compatible with "int" on a 32-bit target - but on some targets, that
    is not the case.


    Third, as a consequence of that, it would be harder to write
    program verification tools, because they would need to take these
    more extensive implementation dependencies into consideration.

    I cannot see a basis for that. Compilers and other code analysis and verification tools can add whatever extra checks and controls they want.
    And I suspect it will be easier to check that code is correct
    according to the suggested updated rules than to spot some kinds of
    subtle mistakes using the existing rules.


    Fourth, there would be consequences for program optimization, and
    it is hard to dismiss those. Some people may not care about the optimizations losses, but certainly many people want the benefits
    of those optimizations.

    It is certainly the case that there are some optimisation opportunities
    due to the "strict aliasing" rules - the compiler knows that an "int *"
    pointer and a "long *" pointer do not point to the same data even if
    "int" and "long" are the same size on that platform. Analysis (I have
    read reports on this, but do not have references for them) of code
    generation by compilers with "strict aliasing" optimisation has,
    however, shown that it is rare that such optimisations make much
    difference - and often you would much better results from using
    "restrict". Also, with my suggested changes, compilers would retain the knowledge of no aliasing between integer types and floating point types,
    or between struct types.


    Fifth, related to the previous point, as a practical matter it would
    make getting the optimization benefits back again be nearly
    impossible. As things are now, it's easy to have a compiler option
    to disable the consequences of strong typing rules, and the result
    can still be a conforming implementation. But if the C standard
    would prescribe the semantics of cross-type access, then any option
    to ignore the implications of that prescription would necessarily
    make using said option result in a non-conforming implementation.


    Almost anyone interested in serious optimisation is already going to be
    using non-portable and compiler or target specific features. That
    objection is a complete non-issue.

    To say the last point another way, with things as they are now
    developers can choose whether they want to observe the cross-type
    access restrictions, or ignore them, and still get a C compiler.
    If the effective type rules were discarded, there is no way to
    choose the more-optimizing path without getting something that
    is not a C compiler.

    Given that you can always get what you want either by choosing
    an appropriate compiler option (if available) or by using one of
    the well-known legal workarounds, I think it's hard to make a
    case that getting rid of the effective type restrictions is a
    good idea.

    I have now made a case for a limited change to the aliasing rules
    (whether the change is made by type compatibility rules, constraints on assignment, or "effective type" rules). I did not think it was
    particularly hard to do so.

    Of course opinions will differ as to how good such arguments are, and
    any real changes would be based on far more serious thoughts and
    discussions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Janis Papanagnou on Mon May 12 11:44:29 2025
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:

    On 09.05.2025 17:26, Richard Heathfield wrote:

    On 09/05/2025 16:04, Bonita Montero wrote:

    Am 09.05.2025 um 17:01 schrieb Scott Lurndal:

    Bonita Montero <Bonita.Montero@gmail.com> writes:

    Am 06.04.2025 um 17:14 schrieb Tim Rentsch:

    My impression was that "defer", or something very much like
    it, is being considered for inclusion in a future C standard. ...

    With C++ you can have defer without extending the language.

    This, however is comp.lang.c.

    I'm just trying to make it clear that C lacks convenience
    and productivity on every level.

    Then use something convenient and productive. But please confine your
    discussions of your chosen alternative to
    comp.lang.your.chosen.alternative instead of dragging them into
    comp.lang.c, where we discuss C.

    [...]

    Since some folks feel comfortable in their "C" bubble I understand
    that these people might feel annoyed by such posts.

    But showing deficiencies (in "C") and providing counter-examples or alternatives from other languages [as done here] should be welcome.
    (IMO. YMMV, of course.) [...]

    But of course no one forces these annoyed people to read all posts; suggestions had already been given to just skip those inconvenient
    threads or subhreads.

    This comment sounds like hearing from a neighbor that I shouldn't
    mind if his dog shits on my lawn, because I can easily step over
    the shit. Except that here there is a notable difference, in
    that it isn't the dog but the dog's owner doing the shitting.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Keith Thompson on Tue May 13 11:40:58 2025
    On 12/05/2025 22:25, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    For plain integer types, however, I think the argument for making
    equal-sized types compatible is a lot stronger. Some compilers
    specifically say that they allow aliasing between such types (MSVC,
    according to what I have read, have said they never intend to support
    "strict aliasing" optimisations). Many software projects (such as
    Linux) use "-fno-strict-aliasing". And countless C programmers
    mistakenly believe that identically sized integer types are compatible
    (though I am not advocating for a weaker language simply because some
    users misunderstand the rules).

    I think that a lot of C programmers misunderstand what "compatible
    types" means. Many seem to think that two types are compatible if
    they have the same representation and can be assigned without a cast.


    Yes. Basically, most C programmers are not particularly aware of the
    technical definitions of some of the terms in C standards where they
    differ from common usage. The word "compatible" in English means that
    the things in question can work together or fit together. Thus there
    are a number of ways to view types as "compatible" in C in normal
    English, but only one definition of "compatible type" as a specific term
    in the C standard. (This sort of thing is, I think, inevitable in a
    language standard unless you want to invent new terms without a normal
    language meaning - such as "lvalue".)


    In fact type compatibility is a much stricter concept than that.
    Two types are compatible if they are *the same type*, and in a few
    other circumstances. For example, char, signed char, and unsigned
    char are all incompatible with each other, even though two of them
    are guaranteed to have the same representation.

    A good way to think about it is that pointers to two types can be
    assigned without a cast if and only if the two types are compatible.
    For example, int and long objects can be assigned to each other
    without a cast, but int* and long* objects cannot.


    Yes. That is also a good way for people to check if types are
    compatible, if they want to use "try it on a compiler and see" as an aid.

    And changing the language to make int and long conditionally
    compatible would (a) make it too easy to write code that's valid
    in one implementation but violates a constraint in another, and (b)
    would break existing code.

    Speaking as someone who uses the fixed-size types often, and sees it in
    other code, there is already a lot of such code that is valid in one implementation or target and not on others, primarily because "int32_t"
    may be typedef'ed to "int" or "long", and "int64_t" may be "long" or
    "long long". But I can see that making "long" compatible to either
    "int" or "long long", according to implementation, might cause more issues.

    I think a better change to consider is not changing the rules of type compatibility, but slightly loosening the rules for what types of lvalue expressions can be used to access objects in 6.5p7. (It is possible
    this could be done by changing the "effective type" rules in 6.5p6, but
    that might be more complicated.) Basically, we retain the restriction
    that an int* and a long* (for 32-bit int and long) cannot be assigned to
    each other without a cast, but that an int* lvalue /can/ be used to
    access a long object, and vice versa. The same would apply to any pairs
    of scalar types that have identical values and representations. I
    believe that change would not break any existing code, but would
    certainly fix some existing broken code. And it would allow compilers
    to continue to use most "strict aliasing" optimisations.

    For example, a generic selection cannot
    have two associations with compatible types. _Generic with "int:"
    and "long:" would become invalid for implementations that make int
    and long compatible.


    While that is true, I suspect that _Generic is used so little in
    practice that few if any would notice it!

    (I wouldn't mind seeing a new form of generic association that
    selects the *first* matching type, but that's another can of worms.)


    If I were looking to improve _Generic, I'd want a way to add new types
    to an existing _Generic macro (for new overloads). This could easily by
    done if the preprocessor had a #redefine directive that let you give a
    new definition of a macro name while using the old definition when
    expanding the new macro. That would be a whole barrel of worms :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to David Brown on Tue May 13 14:54:15 2025
    On 09.05.2025 19:09, David Brown wrote:
    On 09/05/2025 17:54, Janis Papanagnou wrote:
    [...]

    Comparisons between C and other languages can certainly be on-topic for
    a C group. And deficiencies of C are as topical as the language's good points.

    However, Bonita's post here - like almost all Bonita's posts in this
    group - are not helpful or topical, but merely trolls of "C++ is vastly better than C - look at this line noise to see what you can do in C++".

    Yes, I understand your dislike. And in this case it's specifically easy
    for folks who dislike specific persons or dislike what they say what
    they can or should do about that. (And below in your post you formulate
    some personal options one may take to not see those people or their contributions any more.)


    Consider this about Bonita's post :
    [ farraginous list snipped ]

    Sure. - But there was no need to analyze or list all that (for me at
    least); you may have noticed my statement (and read between the lines;
    if it's not obvious I may have formulated that better, I admit.)

    (Note: I'm not saying that the previous post's content is correct,
    just that it was obviously meant as an improvement, which could or
    not affect evolution of "C" if considered; a point for discussion
    [for those who think it's worth].)


    It is not at all surprising that people find Bonita's posts in
    comp.lang.c annoying, and would be happier if they were restricted to comp.lang.c++. Most people just ignore them, others use killfiles, and
    some people optimistically try to persuade Bonita not to write such
    posts. I'd be surprised if there was anyone who actually thought they
    were a positive contribution to the group.

    Sure. (I have also a [small] killfile where there's mostly people
    listed that show [occasionally or regularly] sociopathic behavior
    (that annoys me more than aberrant posts or errant content.)

    As a general principle, I agree with you that languages other than C can
    at times be relevant and interesting in this group - but in this
    specific case, I see no value in Bonita's post.

    Yes. But note that we're now mixing arguments on two or three levels;
    it started with topicality, continued with quality/appropriateness,
    and ended with, um.., "known types of people [beyond all hope]".

    I think with a good grain of serenity we could also spare us those
    longish threads. Let's individually pick and choose what we like.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Tim Rentsch on Tue May 13 15:13:04 2025
    On 12.05.2025 20:44, Tim Rentsch wrote:
    [...]

    But of course no one forces these annoyed people to read all posts;
    suggestions had already been given to just skip those inconvenient
    threads or subhreads.

    This comment sounds like hearing from a neighbor that I shouldn't
    mind if his dog shits on my lawn, because I can easily step over
    the shit.

    This comparison says, unfortunately, a lot more about you than
    about anything else.

    Except that here there is a notable difference, in
    that it isn't the dog but the dog's owner doing the shitting.

    I see you're redirecting your [strawman] comparison to a personal
    defamation. - I know that other poster's posts, I have my opinion
    about the posts (and about him), but that comparison is beyond all
    decency.

    Janis

    PS (@David): With this example you may now better understand what
    I had meant about criteria for my killfile entries. Some people
    write non-topical contents, some write nonsense or are uninformed,
    and some show (to various degrees) sociapathic behavior. - That's
    the Internet.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Richard Heathfield on Tue May 13 14:55:02 2025
    On 09.05.2025 18:26, Richard Heathfield wrote:
    On 09/05/2025 16:54, Janis Papanagnou wrote:
    <snip>


    Since some folks feel comfortable in their "C" bubble I understand
    that these people might feel annoyed by such posts.

    Each newsgroup has a topic. I subscribe to no fewer than ten newsgroups, because I am interested in those ten topics. If you are interested in
    C++, you can subscribe to comp.lang.c++ and chat about it all day long
    and nobody will bat an eyelid. I have no doubt that many comp.lang.c subscribers are also subscribed to comp.lang.c++. Why not join their
    number, and keep the salt in the salt pot and the pepper in the pepper pot?

    (You seem to have missed the point; see below.)


    But showing deficiencies (in "C") and providing counter-examples or
    alternatives from other languages [as done here] should be welcome.

    Why?

    Four important ways that C scores over other languages are:

    * Speed
    * Simplicity
    * Size
    * Portability

    The more you add, the more likely you are to slow it down, the more
    complex you make it, the bigger it gets, and the harder it is to port.

    See; now you're discussing (in a very principle way) why the other
    poster's suggestion makes no sense [to you]. - That was the point.

    (And you can always skip questions or suggestions or discussions
    you are not interested in.)

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Janis Papanagnou on Tue May 13 14:35:43 2025
    On 13/05/2025 13:55, Janis Papanagnou wrote:
    On 09.05.2025 18:26, Richard Heathfield wrote:
    On 09/05/2025 16:54, Janis Papanagnou wrote:
    <snip>


    Since some folks feel comfortable in their "C" bubble I understand
    that these people might feel annoyed by such posts.

    Each newsgroup has a topic. I subscribe to no fewer than ten newsgroups,
    because I am interested in those ten topics. If you are interested in
    C++, you can subscribe to comp.lang.c++ and chat about it all day long
    and nobody will bat an eyelid. I have no doubt that many comp.lang.c
    subscribers are also subscribed to comp.lang.c++. Why not join their
    number, and keep the salt in the salt pot and the pepper in the pepper pot?

    (You seem to have missed the point; see below.)

    I know what /my/ point is, and I assure you I haven't missed it.

    But showing deficiencies (in "C") and providing counter-examples or
    alternatives from other languages [as done here] should be welcome.

    Why?

    Four important ways that C scores over other languages are:

    * Speed
    * Simplicity
    * Size
    * Portability

    The more you add, the more likely you are to slow it down, the more
    complex you make it, the bigger it gets, and the harder it is to port.

    See; now you're discussing

    ....a discussion that has been done to death far too often over
    at least the last quarter-century.

    (in a very principle way) why the other
    poster's suggestion makes no sense [to you]. - That was the point.

    No. The point is that if you want C++, you know where to find it,
    and it isn't here.

    (And you can always skip questions or suggestions or discussions
    you are not interested in.)

    And if someone urinates in your beer, you can always spit it out,
    right?

    We have topics for a reason.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Janis Papanagnou on Tue May 13 15:36:03 2025
    On 13/05/2025 14:54, Janis Papanagnou wrote:
    On 09.05.2025 19:09, David Brown wrote:
    On 09/05/2025 17:54, Janis Papanagnou wrote:
    [...]

    Comparisons between C and other languages can certainly be on-topic for
    a C group. And deficiencies of C are as topical as the language's good
    points.

    However, Bonita's post here - like almost all Bonita's posts in this
    group - are not helpful or topical, but merely trolls of "C++ is vastly
    better than C - look at this line noise to see what you can do in C++".

    Yes, I understand your dislike. And in this case it's specifically easy
    for folks who dislike specific persons or dislike what they say what
    they can or should do about that. (And below in your post you formulate
    some personal options one may take to not see those people or their contributions any more.)


    Consider this about Bonita's post :
    [ farraginous list snipped ]

    Sure. - But there was no need to analyze or list all that (for me at
    least); you may have noticed my statement (and read between the lines;
    if it's not obvious I may have formulated that better, I admit.)

    I am trying to make it clear to you why your argument - that it is
    appropriate to talk in this newsgroup about C's failings, and that it
    can be appropriate in this newsgroup to compare to other languages -
    does not apply in this particular case. I am having difficulty
    understanding why you think Bonita's post was appropriate, or why you
    disliked Richard's response.

    I agree with your basic principles - for the most part, if one person
    does not like the posts of another person, they can ignore those posts
    either automatically (with killfiles, filters, etc.) or "manually".

    However, those of us who see this group as a resource, or a just a place
    to hang out and chat about C, have a responsibility to try to keep the
    group tidy. That means occasionally responding to inappropriate posts
    and asking the poster to be more considerate to the group.


    I think with a good grain of serenity we could also spare us those
    longish threads. Let's individually pick and choose what we like.


    No, let's not. Let's - at least occasionally - take some responsibility
    and not ignore inappropriate behaviour. I don't want to drag this out,
    or overreact - Bonita's posts are not /that/ bad. But be clear on this:
    it was not Richard's post berating Bonita that made a long thread branch
    about topicality, it was /your/ post complaining about his post.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Janis Papanagnou on Tue May 13 14:46:09 2025
    On 13/05/2025 14:13, Janis Papanagnou wrote:
    On 12.05.2025 20:44, Tim Rentsch wrote:
    [...]

    But of course no one forces these annoyed people to read all posts;
    suggestions had already been given to just skip those inconvenient
    threads or subhreads.

    This comment sounds like hearing from a neighbor that I shouldn't
    mind if his dog shits on my lawn, because I can easily step over
    the shit.

    This comparison says, unfortunately, a lot more about you than
    about anything else.

    On the contrary, it says a lot more about you who choose to put
    your own agenda above the group dynamic because other people's
    opinions don't matter to you.

    It was a while back now, but there was a time when I lobbied in
    this group for a slight relaxing of topicality rules - not by
    breaching those rules, but by inviting discussion, cavassing
    opinions, and collating them into a show of hands. By an
    overwhelming majority the group turned me down. I didn't tell
    them 'to hell with you, I'll discuss what I damn well want to,
    and if you don't like it, tough cheese'; I accepted the group's
    decision.

    There may well be some subscribers here who remember that
    discussion and might be prepared to corroborate the above.

    Nobody can stop you posting whatever the hell you like here...
    except you. So the question comes down to whether you are an
    adult with the capacity for self-control and the will to
    participate in a way that observes the customs of the people
    whose company you have sought, or whether you are just a spoiled
    teenager in an adult's body.

    The choice is entirely yours.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Richard Heathfield on Tue May 13 16:07:06 2025
    On 13/05/2025 15:46, Richard Heathfield wrote:

    It was a while back now, but there was a time when I lobbied in this
    group for a slight relaxing of topicality rules - not by breaching those rules, but by inviting discussion, cavassing opinions, and collating
    them into a show of hands. By an overwhelming majority the group turned
    me down. I didn't tell them 'to hell with you, I'll discuss what I damn
    well want to, and if you don't like it, tough cheese'; I accepted the
    group's decision.

    There may well be some subscribers here who remember that discussion and might be prepared to corroborate the above.


    It rings a bell, if that's enough corroboration for you.

    Perhaps enough has been said by all parties in this little branch -
    anything more is likely to be repetitive, or more heated than we might
    like. I would hate for animosity in a thread branch about topicality to
    spill over into the topical threads. Let's reserve the fire and passion
    for discussing C :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to David Brown on Tue May 13 20:17:05 2025
    On 5/13/25 05:40, David Brown wrote:
    On 12/05/2025 22:25, Keith Thompson wrote:
    ...
    I think that a lot of C programmers misunderstand what "compatible
    types" means. Many seem to think that two types are compatible if
    they have the same representation and can be assigned without a cast.


    Yes. Basically, most C programmers are not particularly aware of the technical definitions of some of the terms in C standards where they
    differ from common usage. The word "compatible" in English means that
    the things in question can work together or fit together.

    That's pretty much what it means in C. Two C types are compatible in C
    if the C standard *guarantees* that they can work together - that you
    can use the types interchangeably. The tricky part is the definition of
    which pairs of types the C standard makes those guarantees for.
    The key point is that the undefined behavior of code which treats
    incompatible types as if they were compatible could also be that they
    work together, too, depending upon the implementation.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to James Kuyper on Tue May 13 18:15:17 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    On 5/13/25 05:40, David Brown wrote:

    On 12/05/2025 22:25, Keith Thompson wrote:

    ...

    I think that a lot of C programmers misunderstand what "compatible
    types" means. Many seem to think that two types are compatible if
    they have the same representation and can be assigned without a cast.

    Yes. Basically, most C programmers are not particularly aware of the
    technical definitions of some of the terms in C standards where they
    differ from common usage. The word "compatible" in English means that
    the things in question can work together or fit together.

    That's pretty much what it means in C. Two C types are compatible
    in C if the C standard *guarantees* that they can work together -
    that you can use the types interchangeably. [...]

    This description isn't exactly right, because the relationship of
    being compatible is not an equivalence relation. It is possible
    that given types A, B, and C, A is compatible with B, and B is
    compatible with C, but A is not compatible with C.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Keith Thompson on Tue May 13 22:23:48 2025
    On 5/13/25 20:51, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 5/13/25 05:40, David Brown wrote:
    ...
    Yes. Basically, most C programmers are not particularly aware of the
    technical definitions of some of the terms in C standards where they
    differ from common usage. The word "compatible" in English means that
    the things in question can work together or fit together.

    That's pretty much what it means in C. Two C types are compatible in C
    if the C standard *guarantees* that they can work together - that you
    can use the types interchangeably. The tricky part is the definition of
    which pairs of types the C standard makes those guarantees for.
    The key point is that the undefined behavior of code which treats
    incompatible types as if they were compatible could also be that they
    work together, too, depending upon the implementation.

    I suggest that the phrase "work together" is too vague.

    I was trying to match the wording of the text I was responding to. What
    I meant can be made far more precise: the C standard guarantees that two compatible types will work together, in the sense that every case where
    the C standard mandates that two types must be compatible in order for something to work, it will work for them.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Richard Heathfield on Tue May 13 19:34:11 2025
    Richard Heathfield <rjh@cpax.org.uk> writes:

    On 09/05/2025 15:25, Bonita Montero wrote:

    Am 10.04.2025 um 00:07 schrieb Tim Rentsch:

    When someone is responding to a post, they are responding ONLY to
    the content in the posting they are responing to; not to some
    earlier posting in the same thread, not to a different posting
    submitted two weeks ago, not to what you meant to say but didn't,
    not to thoughts in your head but that you didn't say, but ONLY TO
    WHAT IS SAID IN THE POSTING BEING RESPONDED TO.

    If you can learn to follow this simple rule everyone in the
    newsgroup will be better off, including you.

    You're constantly overwhelmed by what people write here. Both in
    terms of content and the nature of the discussion. Don't try to
    constantly set rules; that seems petty.

    Tim's not setting a draconian rule in stone. He's presenting a
    perfectly sensible rule of thumb that is based on his decades of
    experience of posting to this group. Usenet works best when you snip
    the bits you're not replying to, and reply only within the context you
    have retained. Nearly all the leading experts in this group nearly
    always observe this rule of thumb, because it's simple common sense so
    to do.

    Note that my remarks did not direct anyone to do anything. The
    first paragraph gives an observation -- which I think agrees with
    the behavior of most posters in most cases -- about how responders
    actually act. The second paragraph gives a statement of opinion
    (or perhaps a prediction, depending on how the paragraph is
    interpreted) about what will happen if someone adopts the view
    explained in the first paragraph. There was no attempt to set
    rules.

    On what basis do you justify laying down your law for Tim to follow?

    I see no reason to care what Bonita Montero thinks. ISTM that the
    most common reaction among other responders is to say postings not
    topical to comp.lang.c should be posted elsewhere. So I don't
    think there is much danger of my reaction being in the minority.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to James Kuyper on Wed May 14 11:07:47 2025
    On 14/05/2025 04:23, James Kuyper wrote:
    On 5/13/25 20:51, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 5/13/25 05:40, David Brown wrote:
    ...
    Yes. Basically, most C programmers are not particularly aware of the
    technical definitions of some of the terms in C standards where they
    differ from common usage. The word "compatible" in English means that
    the things in question can work together or fit together.

    That's pretty much what it means in C. Two C types are compatible in C
    if the C standard *guarantees* that they can work together - that you
    can use the types interchangeably. The tricky part is the definition of
    which pairs of types the C standard makes those guarantees for.
    The key point is that the undefined behavior of code which treats
    incompatible types as if they were compatible could also be that they
    work together, too, depending upon the implementation.

    I suggest that the phrase "work together" is too vague.

    I was trying to match the wording of the text I was responding to. What
    I meant can be made far more precise: the C standard guarantees that two compatible types will work together, in the sense that every case where
    the C standard mandates that two types must be compatible in order for something to work, it will work for them.


    That's a tautology - the C standard guarantees that two compatible types
    will work together in situations where the C standard requires that the
    types are compatible.

    I appreciate that it is difficult to give precise meanings to vague
    concepts, but I don't think that rephrasing helps!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to David Brown on Wed May 14 11:19:33 2025
    On 13.05.2025 15:36, David Brown wrote:
    On 13/05/2025 14:54, Janis Papanagnou wrote:
    [...]

    I think with a good grain of serenity we could also spare us those
    longish threads. Let's individually pick and choose what we like.


    No, let's not. Let's - at least occasionally - take some responsibility
    and not ignore inappropriate behaviour. I don't want to drag this out,
    or overreact - Bonita's posts are not /that/ bad. But be clear on this:
    it was not Richard's post berating Bonita that made a long thread branch about topicality, it was /your/ post complaining about his post.

    Erm, no. I wasn't complaining, just giving a suggestion. That's
    something completely different in my book. A suggestion can be
    dismissed or be helpful. The posters decide.

    WRT who made the thread branch become long; every meta discussion
    contributes a bit, and it becomes long if we latch on posts and
    meta-topics - as we two currently seem to start. This was not my
    intention which merely was to suggest just a bit more serenity
    (and not discuss too deeply what's "appropriate or inappropriate
    behavior").

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Keith Thompson on Wed May 14 11:22:35 2025
    On 14/05/2025 02:51, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 5/13/25 05:40, David Brown wrote:
    On 12/05/2025 22:25, Keith Thompson wrote:
    ...
    I think that a lot of C programmers misunderstand what "compatible
    types" means. Many seem to think that two types are compatible if
    they have the same representation and can be assigned without a cast.

    Yes. Basically, most C programmers are not particularly aware of the
    technical definitions of some of the terms in C standards where they
    differ from common usage. The word "compatible" in English means that
    the things in question can work together or fit together.

    That's pretty much what it means in C. Two C types are compatible in C
    if the C standard *guarantees* that they can work together - that you
    can use the types interchangeably. The tricky part is the definition of
    which pairs of types the C standard makes those guarantees for.
    The key point is that the undefined behavior of code which treats
    incompatible types as if they were compatible could also be that they
    work together, too, depending upon the implementation.

    I suggest that the phrase "work together" is too vague. It's
    perfectly reasonable to say that two types that can be assigned to
    each other without casts can "work together", and I might even call
    them "compatible" if the standard didn't already define the term.


    Yes, exactly. If the C standard did not use the word "compatible", then programmers might consider two types to be "compatible" for a whole
    range of situations. That could include "can be assigned to each
    other", "can be assigned, possibly with casts", "can be converted back
    and forth to get back the original value", "can be mixed with each
    other's pointer types", "can be used to access each other", "can be used
    in the same code", and no doubt many others.

    So the term "compatible types" in C does not mean the same as it does in English, nor does it mean "types that work together" - precisely because
    those phrases in English are much vaguer and more general, and can mean different things to different people.

    To a first approximation, two types are compatible if they're the
    same type. The standard's section on compatible types points to
    additional rules for some cases. IMHO the English word "compatible"
    suggests a much looser relationship, but we're stuck with the
    standard's terminology (and I'm not sure what would be better).


    I think the solution for this kind of thing would be hyphenated terms - "pointer-compatible", "assignment-compatible", and the like. That
    would, IMHO, make it a clearer and there would be no risk of mixup
    between normal English language usage and technical terms. (For some
    technical terms, made-up works like "lvalue" are appropriate, but not in
    this case I think.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Richard Heathfield on Wed May 14 11:22:56 2025
    On 13.05.2025 15:35, Richard Heathfield wrote:
    On 13/05/2025 13:55, Janis Papanagnou wrote:
    (And you can always skip questions or suggestions or discussions
    you are not interested in.)

    And if someone urinates in your beer, you can always spit it out, right?

    You seem to like (as Tim in another post) disgusting, inappropriate and misleading comparisons.

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Richard Heathfield on Wed May 14 11:31:57 2025
    On 13.05.2025 15:46, Richard Heathfield wrote:
    On 13/05/2025 14:13, Janis Papanagnou wrote:
    On 12.05.2025 20:44, Tim Rentsch wrote:
    [...]

    But of course no one forces these annoyed people to read all posts;
    suggestions had already been given to just skip those inconvenient
    threads or subhreads.

    This comment sounds like hearing from a neighbor that I shouldn't
    mind if his dog shits on my lawn, because I can easily step over
    the shit.

    This comparison says, unfortunately, a lot more about you than
    about anything else.

    On the contrary, it says a lot more about you who choose to put your own agenda above the group dynamic because other people's opinions don't
    matter to you.

    I have no agenda, so I dismiss your imputation. I gave a suggestion on
    the raised attack against a poster that you may, as any suggestions,
    dismiss or consider. - The choice is entirely yours. (As you say below.)

    Janis

    [...]

    Nobody can stop you posting whatever the hell you like here... except
    you. So the question comes down to whether you are an adult with the
    capacity for self-control and the will to participate in a way that
    observes the customs of the people whose company you have sought, or
    whether you are just a spoiled teenager in an adult's body.

    The choice is entirely yours.


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Janis Papanagnou on Wed May 14 10:34:52 2025
    On 14/05/2025 10:22, Janis Papanagnou wrote:
    On 13.05.2025 15:35, Richard Heathfield wrote:
    On 13/05/2025 13:55, Janis Papanagnou wrote:
    (And you can always skip questions or suggestions or discussions
    you are not interested in.)

    And if someone urinates in your beer, you can always spit it out, right?

    You seem to like (as Tim in another post) disgusting, inappropriate and misleading comparisons.

    I actually find them rather distasteful. The comparison is indeed
    disgusting, but it's apposite and not remotely misleading.

    I tried nice. You replied with scorn for the group.

    Now I've tried colourful, and you're still showing your contempt
    for the group.

    I should plonk you now, but because I'm inordinately patient I'll
    stay my hand for the third and last time.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Janis Papanagnou on Wed May 14 10:37:15 2025
    On 14/05/2025 10:31, Janis Papanagnou wrote:
    On 13.05.2025 15:46, Richard Heathfield wrote:
    On 13/05/2025 14:13, Janis Papanagnou wrote:
    On 12.05.2025 20:44, Tim Rentsch wrote:
    [...]

    But of course no one forces these annoyed people to read all posts;
    suggestions had already been given to just skip those inconvenient
    threads or subhreads.

    This comment sounds like hearing from a neighbor that I shouldn't
    mind if his dog shits on my lawn, because I can easily step over
    the shit.

    This comparison says, unfortunately, a lot more about you than
    about anything else.

    On the contrary, it says a lot more about you who choose to put your own
    agenda above the group dynamic because other people's opinions don't
    matter to you.

    I have no agenda

    Other than weakening the topicality mores in comp.lang.c, that is.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to David Brown on Wed May 14 15:03:12 2025
    On 2025-05-14, David Brown <david.brown@hesbynett.no> wrote:
    On 14/05/2025 04:23, James Kuyper wrote:
    On 5/13/25 20:51, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 5/13/25 05:40, David Brown wrote:
    ...
    Yes. Basically, most C programmers are not particularly aware of the >>>>> technical definitions of some of the terms in C standards where they >>>>> differ from common usage. The word "compatible" in English means that >>>>> the things in question can work together or fit together.

    That's pretty much what it means in C. Two C types are compatible in C >>>> if the C standard *guarantees* that they can work together - that you
    can use the types interchangeably. The tricky part is the definition of >>>> which pairs of types the C standard makes those guarantees for.
    The key point is that the undefined behavior of code which treats
    incompatible types as if they were compatible could also be that they
    work together, too, depending upon the implementation.

    I suggest that the phrase "work together" is too vague.

    I was trying to match the wording of the text I was responding to. What
    I meant can be made far more precise: the C standard guarantees that two
    compatible types will work together, in the sense that every case where
    the C standard mandates that two types must be compatible in order for
    something to work, it will work for them.


    That's a tautology - the C standard guarantees that two compatible types
    will work together in situations where the C standard requires that the
    types are compatible.

    Moreover, signed and unsigned char work together, yet are incompatible.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to David Brown on Wed May 14 23:17:47 2025
    On 5/14/25 05:07, David Brown wrote:
    On 14/05/2025 04:23, James Kuyper wrote:
    ...
    I was trying to match the wording of the text I was responding to. What
    I meant can be made far more precise: the C standard guarantees that two
    compatible types will work together, in the sense that every case where
    the C standard mandates that two types must be compatible in order for
    something to work, it will work for them.


    That's a tautology - the C standard guarantees that two compatible
    types will work together in situations where the C standard requires
    that the types are compatible.

    It's not a tautology, it's a recipe for generating a much longer and
    more detailed specification by searching for relevant clauses from the
    standard and extracting the relevant words from those sections, which I
    had no particular desire to generate. My point was that it could be
    generated, and would, when generated constitute a definition of what
    "work together" means in this context.

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