• acquire + sleep + async

    From fir@3:633/10 to All on Wednesday, June 10, 2026 13:53:59
    im not experienced with multithreading programing (though i learned a
    bit of it 20 years ago i decided it is not nice for me enough to do it)

    i only tend to do things that seem reasonable to me and i have some doubts

    hovever in my small view on things i may say that

    I.
    sleep() function
    (who puts cpu core on sleep given miliseconds (or microseconds)
    (by put on sleep i also thing it just chnges the context of execution
    to anuther thread for given time eventually) I FIND REASONABLE
    (i see no problem with that)

    II.
    async call of function (it is a call to some function that spawns a
    thread, so main thread continues but the second spawned on that function executes also until it find some of async end when its job is done
    I ALSO FIND reasoneble (no problem with that)

    III.

    there is a third thing...i name it acquire ..it is some kind os assembly instruction or pair of assembly instustions with some guarantees

    i mean acquire(x) should work if(x==0) x=TID (thread id or something
    like that) so its like conditional move mov eax, tid; movz x, eax;
    (where movz would mean here mov if x is 0 if not set a cpu flag)

    and this should be proof of core crashes on this acces i mean only one
    can acquire (im not sure if present cpu have it - that probably should
    have - becouse it makes such operation very cheap then)

    NOTE im meybe even less sura about this acquire becouse theoretically
    probably such acquireless (and maybe even mostly sleepless) programming
    is possible but im not sure if it wouldnt be handy too


    THOSE 3 "PRIMITIVES" imo are quite A SET to make multithreaded
    programming "by hand".i also think it should be most lightweight,
    i mean async call should be very light probbly (and probbaly it is its a metter of line of assembly or two i hope)...same with sleep (as in fact
    sleep and async call are close things

    so i would hope that should be just maybe a set of few assebly opcodes
    (if i not mislooked and something heavvier is needed)

    conclusion is what i already said it seem that those 3 thing
    (primitives) allows to do a lot of multithreading without bloated
    libraries i hope

    eventually correct me if im wrong

    (also not to say they are best way of doing multithreading but if they
    are lightweight it is at least minimally reasonable in some way it seems)


    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From fir@3:633/10 to All on Wednesday, June 10, 2026 16:03:28
    fir pisze:
    im not experienced with multithreading programing (though i learned a
    bit of it 20 years ago i decided it is not nice for me enough to do it)

    i only tend to do things that seem reasonable to me and i have some doubts

    hovever in my small view on things i may say that

    I.
    ˙sleep() function
    (who puts cpu core on sleep given miliseconds (or microseconds)
    (by put on sleep i also thing it just chnges the context of execution
    to anuther thread for given time eventually) I FIND REASONABLE
    (i see no problem with that)

    II.
    async call of function (it is a call to some function that spawns a
    thread, so main thread continues but the second spawned on that function executes also until it find some of async end when its job is done
    I ALSO FIND reasoneble (no problem with that)

    III.

    there is a third thing...i name it acquire ..it is some kind os assembly instruction or pair of assembly instustions with some guarantees

    i mean acquire(x) should work if(x==0) x=TID (thread id or something
    like that) so its like conditional move˙˙ mov eax, tid; movz x, eax;
    (where movz would mean here mov if x is 0 if not set a cpu flag)

    and this should be proof of core crashes on this acces i mean only one
    can acquire (im not sure if present cpu have it - that probably should
    have - becouse it makes such operation very cheap then)

    NOTE im meybe even less sura about this acquire becouse theoretically probably such acquireless (and maybe even mostly sleepless) programming
    is possible but im not sure if it wouldnt be handy too


    THOSE 3 "PRIMITIVES" imo are quite A SET to make multithreaded
    programming "by hand".i also think it should be most lightweight,
    i mean async call should be very light probbly (and probbaly it is its a metter of line of assembly or two i hope)...same with sleep (as in fact sleep and async call are close things

    so i would hope that should be just maybe a set of few assebly opcodes
    (if i not mislooked and something heavvier is needed)

    conclusion is what i already said it seem that those 3 thing
    (primitives) allows to do a lot of multithreading without bloated
    libraries i hope

    eventually correct me if im wrong

    (also not to say they are best way of doing multithreading but if they
    are lightweight it is at least minimally reasonable in some way it seems)


    btw if some would like to implement some common pattern


    if(acquire(x)) //or acquire(x) {} else {}

    {
    //do something
    release(x);
    }
    else
    {
    sleep(0.01);
    continue;
    }

    then a need for "continue" appears - which i find rather okay

    imo this

    if(x<10)
    {
    x++; continue;
    }

    probably looks better than while()
    (though word "continue" is not most fortunate maybe it should be more
    like repeat
    (though it all should be rethinked meybe there is opportunity to born
    beter form of loop here at all

    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Thursday, June 11, 2026 04:40:50
    On Wed, 10 Jun 2026 13:53:59 +0200, fir wrote:

    im not experienced with multithreading programing ...

    It does tend to be error-prone.

    That?s why it is best reserved for CPU-intensive tasks that can
    benefit from running a bunch of cores at once.

    For cases where the bottleneck is in the I/O or the network connection
    (which is a lot of them), threading is typically unnecessary. Instead,
    the popular approach nowadays is to use coroutines.

    <https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing>
    <https://docs.python.org/3/library/asyncio.html>

    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Thursday, June 11, 2026 07:20:18
    Am 11.06.2026 um 06:40 schrieb Lawrence D?Oliveiro:

    That?s why it is best reserved for CPU-intensive tasks that can
    benefit from running a bunch of cores at once.

    Or you have to deal with blocking calls but you want to
    have a higher througput.

    For cases where the bottleneck is in the I/O or the network connection
    (which is a lot of them), threading is typically unnecessary. Instead,
    the popular approach nowadays is to use coroutines. <https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing>
    <https://docs.python.org/3/library/asyncio.html>

    There are no coroutines in C.

    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Thursday, June 11, 2026 06:28:33
    On Thu, 11 Jun 2026 07:20:18 +0200, Bonita Montero wrote:

    There are no coroutines in C.

    Yes, C is getting left behind in this regard ...

    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Thursday, June 11, 2026 09:21:13
    Am 11.06.2026 um 08:28 schrieb Lawrence D?Oliveiro:

    On Thu, 11 Jun 2026 07:20:18 +0200, Bonita Montero wrote:

    There are no coroutines in C.

    Yes, C is getting left behind in this regard ...

    C hasn't been improved much since 1973.
    You still stick with the same lowlevel view.


    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Thursday, June 11, 2026 07:45:23
    On Thu, 11 Jun 2026 09:21:13 +0200, Bonita Montero wrote:

    C hasn't been improved much since 1973. You still stick with the
    same lowlevel view.

    Actually, just as you can use threading APIs with C, you can use
    stackful coroutine libraries as well.

    Stackless ones are another matter.

    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From David Brown@3:633/10 to All on Thursday, June 11, 2026 09:52:08
    On 11/06/2026 09:21, Bonita Montero wrote:
    Am 11.06.2026 um 08:28 schrieb Lawrence D?Oliveiro:

    On Thu, 11 Jun 2026 07:20:18 +0200, Bonita Montero wrote:

    There are no coroutines in C.

    There are no coroutines in the C standard. There are a wide variety of coroutine implementations in C, with different mixtures of features, limitations, efficiencies, portability and requirements. For
    coroutines, it is most definitely not the case that one solution fits
    all needs - having it part of a language or standard is not necessarily
    a good idea (though some language support can be helpful).


    Yes, C is getting left behind in this regard ...

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.


    You still stick with the same lowlevel view.



    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Thursday, June 11, 2026 10:28:55
    Am 11.06.2026 um 09:52 schrieb David Brown:

    There are no coroutines in the C standard.˙ There are a wide variety
    of coroutine implementations in C, with different mixtures of features, limitations, efficiencies, portability and requirements.˙...

    Real coroutines aren't possible with C since with native coroutines you
    need functions that can be suspended and resumed.

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    Compared to C++ that's true.

    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From fir@3:633/10 to All on Thursday, June 11, 2026 10:34:21
    David Brown pisze:
    On 11/06/2026 09:21, Bonita Montero wrote:
    Am 11.06.2026 um 08:28 schrieb Lawrence D?Oliveiro:

    On Thu, 11 Jun 2026 07:20:18 +0200, Bonita Montero wrote:

    There are no coroutines in C.

    There are no coroutines in the C standard.˙ There are a wide variety of coroutine implementations in C, with different mixtures of features, limitations, efficiencies, portability and requirements.˙ For
    coroutines, it is most definitely not the case that one solution fits
    all needs - having it part of a language or standard is not necessarily
    a good idea (though some language support can be helpful).


    Yes, C is getting left behind in this regard ...

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.


    its not ignorant its obvious...

    as to coroutines i interested in them about 10 yers ago but forget
    what it is

    imo c is above what was called structural (?) programming and possibly
    left behind (or left below) some possibly interesting things

    maybe i will yet try to focus on it some times later

    You still stick with the same lowlevel view.




    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From fir@3:633/10 to All on Thursday, June 11, 2026 10:44:27
    Bonita Montero pisze:
    Am 11.06.2026 um 09:52 schrieb David Brown:

    There are no coroutines in the C standard.˙ There are a wide variety
    of coroutine implementations in C, with different mixtures of
    features, limitations, efficiencies, portability and requirements.˙...

    Real coroutines aren't possible with C since with native coroutines you
    need functions that can be suspended and resumed.


    c lasks some low lewel core management imo -it is more visible in
    multicore times..but even in old times there was something like
    interrupts - who allowed theoretically but probably also practically
    freeze a branch and resume it - so somemechanics of multthreading
    was even on 1core machines - i remember it was in 8-bit c64 really

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    Compared to C++ that's true.


    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Thursday, June 11, 2026 11:36:12
    Am 11.06.2026 um 10:44 schrieb fir:

    Bonita Montero pisze:

    Real coroutines aren't possible with C since with native coroutines you
    need functions that can be suspended and resumed.

    c lasks some low lewel core management imo -it is more visible in
    multicore times..but even in old times there was something like
    interrupts - who allowed theoretically but probably also practically
    freeze a branch and resume it - so somemechanics of multthreading
    was even on 1core machines - i remember it was in 8-bit c64 really

    Coroutines have nothing to do with multithreaded programming,
    but they can be used to have sth. more lightweight than threading.


    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Thursday, June 11, 2026 11:38:23
    Am 11.06.2026 um 10:34 schrieb fir:

    as to coroutines i interested in them about 10 yers ago but forget
    what it is

    Coroutines are the most elegant way to handle finite state machines.
    They need explicit language support and can't be handled exclsuively
    with libraries. In C++ they're basing partitially on the language
    level and on the library level.


    --- PyGate Linux v1.5.15
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From David Brown@3:633/10 to All on Thursday, June 11, 2026 13:39:08
    On 11/06/2026 10:28, Bonita Montero wrote:
    Am 11.06.2026 um 09:52 schrieb David Brown:

    There are no coroutines in the C standard.˙ There are a wide variety
    of coroutine implementations in C, with different mixtures of
    features, limitations, efficiencies, portability and requirements.˙...

    Real coroutines aren't possible with C since with native coroutines you
    need functions that can be suspended and resumed.

    You are apparently talking from a position of total ignorance.

    There are stackless coroutine libraries for C that work entirely from
    the pre-processor, with similar limitations to the C++ coroutines (like
    not being able to yield from normal functions called from the
    coroutine). There are also stackful coroutine libraries, which are more flexible but have higher overhead.

    C coroutine solutions require more manual coding than C++ for tracking
    local variables that must be preserved between calls/yields, but on the
    other hand they don't require the dog's breakfast of boilerplate classes
    and code that C++ coroutines need.


    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    Compared to C++ that's true.

    It is still an astoundingly ignorant claim. If you had said C had not
    changed much since 1999, it would be reasonable - though C23 has quite a number of new features. And even then it would only be in reference to
    the C standards - the C ecosystem has changed enormously.

    It is certainly true that the C++ standards, language and standard
    library, have changed far more. How much they have /improved/ is a
    different matter. IMHO there have definitely been many improvements,
    but also many absurd complications that only exist because of
    limitations in the language in the first place.


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Thursday, June 11, 2026 16:44:46
    Am 11.06.2026 um 13:39 schrieb David Brown:

    There are stackless coroutine libraries for C that work entirely from
    the pre-processor, with similar limitations to the C++ coroutines (like
    not being able to yield from normal functions called from the
    coroutine).˙ There are also stackful coroutine libraries, which are more flexible but have higher overhead.

    Yes, ... from the pre-processor; how comfortable is the debugging with
    that ? Forget it.

    C coroutine solutions require more manual coding than C++ for tracking
    local variables that must be preserved between calls/yields, but on the other hand they don't require the dog's breakfast of boilerplate classes
    and code that C++ coroutines need.

    In the end it's less work in C++ and the debugging is comfortable at
    least with VC++, i.e. you can inspect the coroutine frame when the
    coroutine is not running (CLion can't do that).

    It is still an astoundingly ignorant claim.˙ If you had said C had not changed much since 1999, it would be reasonable - though C23 has quite a number of new features.˙ And even then it would only be in reference to
    the C standards - the C ecosystem has changed enormously.

    It nearly hasn't changed if you compare that to the evolution of C++.


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Janis Papanagnou@3:633/10 to All on Thursday, June 11, 2026 18:50:47
    On 2026-06-11 09:52, David Brown wrote:
    On 11/06/2026 09:21, Bonita Montero wrote:
    Am 11.06.2026 um 08:28 schrieb Lawrence D?Oliveiro:
    On Thu, 11 Jun 2026 07:20:18 +0200, Bonita Montero wrote:

    There are no coroutines in C.

    There are no coroutines in the C standard.˙ There are a wide variety of coroutine implementations in C, with different mixtures of features, limitations, efficiencies, portability and requirements.˙ For
    coroutines, it is most definitely not the case that one solution fits
    all needs - having it part of a language or standard is not necessarily
    a good idea (though some language support can be helpful).

    Frankly, lately I haven't followed the evolution of C++ in general
    or know anything of C++'s co-routines, or how they are integrated
    in the language, what changes they need in the memory model, etc.
    Neither do I know about accepted (quasi-standard?) C-libraries.

    Just flanging external libraries might not suffice (or may result
    in clumsy solutions or inherent principal restrictions), though.

    Simula (the first OO language with classes, inheritance, etc.) has
    also an inherent co-routine functionality that fits very well with
    its other supported concepts; simulation and "living objects" (sort
    of). Created objects may have code executed (their "life"), and may
    temporarily detach themselves or resume other objects. Its builtin
    and more powerful simulation features also rely on that underlying
    co-routine functionality.

    I'd be curious about what "C" (or C++) actually provides when they
    speak about co-routines (whether it's libraries or built-ins).


    Yes, C is getting left behind in this regard ...

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    I certainly wouldn't call her claim ignorant; I think it depends on
    the abstraction level one has, but also on the expectations, about
    what's possible, and what one knows from other languages or areas.

    In the stone-age era a club might have been considered a good tool.

    Being a very subjective matter I suggest to abandon that subtopic.

    Janis


    You still stick with the same lowlevel view.



    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Thursday, June 11, 2026 14:18:09
    On 6/10/2026 9:40 PM, Lawrence D?Oliveiro wrote:
    On Wed, 10 Jun 2026 13:53:59 +0200, fir wrote:

    im not experienced with multithreading programing ...

    It does tend to be error-prone.

    That?s why it is best reserved for CPU-intensive tasks that can
    benefit from running a bunch of cores at once.

    For cases where the bottleneck is in the I/O or the network connection
    (which is a lot of them), threading is typically unnecessary. Instead,
    the popular approach nowadays is to use coroutines.

    Not sure why you say that. Threads work perfectly fine with I/O, network connections, ect... Do you think sync between processes is easier?




    <https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing>
    <https://docs.python.org/3/library/asyncio.html>


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Thursday, June 11, 2026 15:56:20
    On 6/11/2026 12:45 AM, Lawrence D?Oliveiro wrote:
    On Thu, 11 Jun 2026 09:21:13 +0200, Bonita Montero wrote:

    C hasn't been improved much since 1973. You still stick with the
    same lowlevel view.

    Actually, just as you can use threading APIs with C, you can use
    stackful coroutine libraries as well.

    Stackless ones are another matter.

    Want to go to the fiber level? I have been there done that. Fibers
    riding threads... Fine, but you have to know what you are doing.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Thursday, June 11, 2026 16:01:47
    On 6/11/2026 1:44 AM, fir wrote:
    Bonita Montero pisze:
    Am 11.06.2026 um 09:52 schrieb David Brown:

    There are no coroutines in the C standard.˙ There are a wide variety
    of coroutine implementations in C, with different mixtures of
    features, limitations, efficiencies, portability and requirements.˙...

    Real coroutines aren't possible with C since with native coroutines you
    need functions that can be suspended and resumed.


    c lasks some low lewel core management imo -it is more visible in
    multicore times..but even in old times there was something like
    interrupts - who allowed theoretically but probably also practically
    freeze a branch and resume it - so somemechanics of multthreading
    was even on 1core machines - i remember it was in 8-bit c64 really

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    Compared to C++ that's true.


    Wrt per-core, well, in user mode we can try to use affinity masks for
    that. But! Its not guaranteed. So, per thread is pretty low level, per
    fibers on threads is a, well, kind of a different story.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, June 12, 2026 00:12:48
    On Thu, 11 Jun 2026 14:18:09 -0700, Chris M. Thomasson wrote:

    On 6/10/2026 9:40 PM, Lawrence D?Oliveiro wrote:

    For cases where the bottleneck is in the I/O or the network
    connection (which is a lot of them), threading is typically
    unnecessary. Instead, the popular approach nowadays is to use
    coroutines.

    Not sure why you say that.

    It does tend to be error-prone.

    That?s why it is best reserved for CPU-intensive tasks that can
    benefit from running a bunch of cores at once.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, June 12, 2026 00:13:38
    On Thu, 11 Jun 2026 11:38:23 +0200, Bonita Montero wrote:

    Coroutines are the most elegant way to handle finite state machines.
    They need explicit language support and can't be handled exclsuively
    with libraries.

    Stackful coroutines ... I don?t see why not.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, June 12, 2026 00:14:08
    On Thu, 11 Jun 2026 10:28:55 +0200, Bonita Montero wrote:

    Real coroutines aren't possible with C since with native coroutines
    you need functions that can be suspended and resumed.

    Just think of them as non-preemptive threads.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, June 12, 2026 01:32:35
    On Thu, 11 Jun 2026 11:36:12 +0200, Bonita Montero wrote:

    Coroutines have nothing to do with multithreaded programming, but
    they can be used to have sth. more lightweight than threading.

    I don?t know what?s ?heavyweight? about threading, beyond the stack allocations. You have exactly the same thing in (stackful) coroutines.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, June 12, 2026 01:33:39
    On Thu, 11 Jun 2026 16:01:47 -0700, Chris M. Thomasson wrote:

    ... per fibers on threads is a, well, kind of a different story.

    Are these ?fibre? things just some kind of runtime abstraction built
    on top of OS threads?

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Thursday, June 11, 2026 21:05:29
    On 6/11/2026 6:33 PM, Lawrence D?Oliveiro wrote:
    On Thu, 11 Jun 2026 16:01:47 -0700, Chris M. Thomasson wrote:

    ... per fibers on threads is a, well, kind of a different story.

    Are these ?fibre? things just some kind of runtime abstraction built
    on top of OS threads?

    Basically. You need to make your own scheduler for the fiber on the
    threads. Fwiw:

    https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfiberex

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Thursday, June 11, 2026 21:06:08
    On 6/11/2026 5:12 PM, Lawrence D?Oliveiro wrote:
    On Thu, 11 Jun 2026 14:18:09 -0700, Chris M. Thomasson wrote:

    On 6/10/2026 9:40 PM, Lawrence D?Oliveiro wrote:

    For cases where the bottleneck is in the I/O or the network
    connection (which is a lot of them), threading is typically
    unnecessary. Instead, the popular approach nowadays is to use
    coroutines.

    Not sure why you say that.

    It does tend to be error-prone.

    Well, shit happens. :^)



    That?s why it is best reserved for CPU-intensive tasks that can
    benefit from running a bunch of cores at once.



    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Thursday, June 11, 2026 21:11:13
    On 6/11/2026 4:39 AM, David Brown wrote:
    [...]
    C coroutine solutions require more manual coding than C++ for tracking
    local variables that must be preserved between calls/yields, but on the other hand they don't require the dog's breakfast of boilerplate classes
    and code that C++ coroutines need.
    [...]

    FWIW, check this shit out. Coroutines can be emulated even in BASIC.
    This is a recursive stack here. Its all manual... :^)


    100 REM ct_vfield_applesoft_basic
    110 HOME
    120 HGR: HCOLOR = 3: VTAB 22
    130 PRINT "ct_vfield_applesoft_basic"
    140 GOSUB 1000
    150 GOSUB 3000
    160 SP = 0
    170 RS(SP, 0) = 0
    180 RS(SP, 1) = -1
    190 RS(SP, 2) = 0
    200 RS(SP, 3) = 1
    210 RS(SP, 4) = 0
    220 GOSUB 8000
    230 V1(1) = 0: V1(2) = 0: V1(3) = 1: V1(4) = 128
    240 GOSUB 6000
    245 PRINT "Chris Thomasson's Koch Complete!"
    250 END

    1000 REM ct_init
    1010 PRINT "ct_init"
    1020 DIM A0(6)
    1030 DIM V0(4)
    1040 DIM V1(4)
    1050 DIM V2(4)
    1060 DIM V3(4)
    1070 DIM V4(4)
    1080 DIM V5(4)
    1090 RN = 3
    1100 DIM RS(RN, 16)
    1110 GOSUB 2000
    1120 RETURN

    2000 REM ct_init_plane
    2010 PRINT "ct_init_plane"
    2020 A0(1) = 279: REM m_plane.m_width
    2030 A0(2) = 191: REM m_plane.m_height
    2040 A0(3) = 0.0126106: REM m_plane.m_xstep
    2050 A0(4) = 0.0126316: REM m_plane.m_ystep
    2060 A0(5) = -1.75288: REM m_plane.m_axes.m_xmin
    2070 A0(6) = 1.2: REM m_plane.m_axes.m_ymax
    2080 RETURN

    3000 REM ct_display_plane
    3010 PRINT "ct_display_plane"
    3020 FOR I0 = 1 TO 6
    3030 PRINT "A0("; I0; ") = " A0(I0)
    3040 NEXT I0
    3050 RETURN

    4000 REM ct_project_point
    4010 REM PRINT "ct_project_point"
    4020 V0(3) = (V0(1) - A0(5)) / A0(3)
    4030 V0(4) = (A0(6) - V0(2)) / A0(4)
    4040 IF V0(3) < 0 THEN V0(3) = INT(V0(3) - .5)
    4050 IF V0(3) >= 0 THEN V0(3) = INT(V0(3) + .5)
    4060 IF V0(4) < 0 THEN V0(4) = INT(V0(4) - .5)
    4070 IF V0(4) >= 0 THEN V0(4) = INT(V0(4) + .5)
    4080 RETURN

    5000 REM ct_plot_point
    5010 REM PRINT "ct_plot_point"
    5020 GOSUB 4000
    5030 IF V0(3) > -1 AND V0(3) <= A0(1) AND V0(4) > -1 AND V0(4) <=
    A0(2) THEN HPLOT V0(3), V0(4)
    5040 RETURN

    6000 REM ct_plot_circle
    6010 PRINT "ct_plot_circle"
    6020 AB = 6.28318 / V1(4)
    6030 FOR I1 = 0 TO 6.28318 STEP AB
    6040 V0(1) = V1(1) + COS(I1) * V1(3)
    6050 V0(2) = V1(2) + SIN(I1) * V1(3)
    6060 GOSUB 5000
    6070 NEXT I1
    6080 RETURN

    7000 REM ct_plot_line
    7010 PRINT "ct_plot_line"
    7020 V0(1) = V5(1): V0(2) = V5(2)
    7030 GOSUB 4000
    7040 IF V0(3) < 0 THEN V0(3) = 0
    7050 IF V0(3) > A0(1) THEN V0(3) = A0(1)
    7060 IF V0(4) < 0 THEN V0(4) = 0
    7070 IF V0(4) > A0(2) THEN V0(4) = A0(2)
    7080 HPLOT V0(3), V0(4)
    7090 V0(1) = V5(3): V0(2) = V5(4)
    7100 GOSUB 4000
    7110 IF V0(3) < 0 THEN V0(3) = 0
    7120 IF V0(3) > A0(1) THEN V0(3) = A0(1)
    7130 IF V0(4) < 0 THEN V0(4) = 0
    7140 IF V0(4) > A0(2) THEN V0(4) = A0(2)
    7150 HPLOT TO V0(3), V0(4)
    7160 RETURN

    8000 REM ct_koch
    8010 IF RS(SP, 0) >= RN THEN RETURN
    8020 PRINT "ct_koch = "; RS(SP, 0); " "; RS(SP, 1); " "; RS(SP, 2);
    " "; RS(SP, 3); " "; RS(SP, 4)"
    8030 RS(SP, 5) = RS(SP, 3) - RS(SP, 1) : REM difx
    8040 RS(SP, 6) = RS(SP, 4) - RS(SP, 2) : REM dify
    8050 RS(SP, 7) = RS(SP, 1) + RS(SP, 5) / 2 : REM dify
    8060 RS(SP, 8) = RS(SP, 2) + RS(SP, 6) / 2 : REM dify
    8070 RS(SP, 9) = -RS(SP, 6) : REM perpx
    8080 RS(SP, 10) = RS(SP, 5) : REM perpy
    8090 RS(SP, 11) = RS(SP, 7) + RS(SP, 9) / 3 : REM tipx
    8100 RS(SP, 12) = RS(SP, 8) + RS(SP, 10) / 3 : REM tipy
    8110 RS(SP, 13) = RS(SP, 1) + RS(SP, 5) / 3 : REM k0x
    8120 RS(SP, 14) = RS(SP, 2) + RS(SP, 6) / 3 : REM k0y
    8130 RS(SP, 15) = RS(SP, 3) - RS(SP, 5) / 3 : REM k1x
    8140 RS(SP, 16) = RS(SP, 4) - RS(SP, 6) / 3 : REM k1y

    8145 IF RS(SP, 0) < RN - 1 GOTO 8230
    8150 V5(1) = RS(SP, 1): V5(2) = RS(SP, 2): V5(3) = RS(SP, 13): V5(4)
    = RS(SP, 14)
    8160 GOSUB 7000
    8170 V5(1) = RS(SP, 13): V5(2) = RS(SP, 14): V5(3) = RS(SP, 11):
    V5(4) = RS(SP, 12)
    8180 GOSUB 7000
    8190 V5(1) = RS(SP, 11): V5(2) = RS(SP, 12): V5(3) = RS(SP, 15):
    V5(4) = RS(SP, 16)
    8200 GOSUB 7000
    8210 V5(1) = RS(SP, 15): V5(2) = RS(SP, 16): V5(3) = RS(SP, 3):
    V5(4) = RS(SP, 4)
    8220 GOSUB 7000

    8230 REM line 0
    8240 SP = SP + 1
    8250 RS(SP, 0) = RS(SP - 1, 0) + 1
    8260 RS(SP, 1) = RS(SP - 1, 1)
    8270 RS(SP, 2) = RS(SP - 1, 2)
    8280 RS(SP, 3) = RS(SP - 1, 13)
    8290 RS(SP, 4) = RS(SP - 1, 14)
    8300 GOSUB 8000
    8310 SP = SP - 1
    8320 REM line 1
    8330 SP = SP + 1
    8340 RS(SP, 0) = RS(SP - 1, 0) + 1
    8350 RS(SP, 1) = RS(SP - 1, 13)
    8360 RS(SP, 2) = RS(SP - 1, 14)
    8370 RS(SP, 3) = RS(SP - 1, 11)
    8380 RS(SP, 4) = RS(SP - 1, 12)
    8390 GOSUB 8000
    8400 SP = SP - 1
    8410 REM line 2
    8420 SP = SP + 1
    8430 RS(SP, 0) = RS(SP - 1, 0) + 1
    8440 RS(SP, 1) = RS(SP - 1, 11)
    8450 RS(SP, 2) = RS(SP - 1, 12)
    8460 RS(SP, 3) = RS(SP - 1, 15)
    8470 RS(SP, 4) = RS(SP - 1, 16)
    8480 GOSUB 8000
    8490 SP = SP - 1
    8500 REM line 3
    8510 SP = SP + 1
    8520 RS(SP, 0) = RS(SP - 1, 0) + 1
    8530 RS(SP, 1) = RS(SP - 1, 15)
    8540 RS(SP, 2) = RS(SP - 1, 16)
    8550 RS(SP, 3) = RS(SP - 1, 3)
    8560 RS(SP, 4) = RS(SP - 1, 4)
    8570 GOSUB 8000
    8580 SP = SP - 1
    8590 RETURN

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Friday, June 12, 2026 06:16:42
    Am 12.06.2026 um 03:32 schrieb Lawrence D?Oliveiro:

    I don?t know what?s ?heavyweight? about threading, beyond the stack allocations. ...

    Yes, the allocation of the stack is very expensive. And the
    context-switch between threads is a magnitudes more expensive
    than switching between two coroutine conexts.


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Thursday, June 11, 2026 21:16:48
    On 6/11/2026 5:14 PM, Lawrence D?Oliveiro wrote:
    On Thu, 11 Jun 2026 10:28:55 +0200, Bonita Montero wrote:

    Real coroutines aren't possible with C since with native coroutines
    you need functions that can be suspended and resumed.

    Just think of them as non-preemptive threads.

    windows has a fairly nice way to get at them, that is if you want them
    at all...

    https://learn.microsoft.com/en-us/windows/win32/procthread/fibers

    https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfiberex

    https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-convertthreadtofiberex



    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Thursday, June 11, 2026 21:19:45
    On 6/11/2026 9:16 PM, Bonita Montero wrote:
    Am 12.06.2026 um 03:32 schrieb Lawrence D?Oliveiro:

    I don?t know what?s ?heavyweight? about threading, beyond the stack
    allocations. ...

    Yes, the allocation of the stack is very expensive. And the
    context-switch between threads is a magnitudes more expensive
    than switching between two coroutine conexts.


    The fibers float along the threads... ;^)

    Anyway, its been a while since I used them. Iiic it was for a sorting algo.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From David Brown@3:633/10 to All on Friday, June 12, 2026 12:42:23
    On 11/06/2026 18:50, Janis Papanagnou wrote:
    On 2026-06-11 09:52, David Brown wrote:
    On 11/06/2026 09:21, Bonita Montero wrote:
    Am 11.06.2026 um 08:28 schrieb Lawrence D?Oliveiro:
    On Thu, 11 Jun 2026 07:20:18 +0200, Bonita Montero wrote:

    There are no coroutines in C.

    There are no coroutines in the C standard.˙ There are a wide variety
    of coroutine implementations in C, with different mixtures of
    features, limitations, efficiencies, portability and requirements.
    For coroutines, it is most definitely not the case that one solution
    fits all needs - having it part of a language or standard is not
    necessarily a good idea (though some language support can be helpful).

    Frankly, lately I haven't followed the evolution of C++ in general
    or know anything of C++'s co-routines, or how they are integrated
    in the language, what changes they need in the memory model, etc.
    Neither do I know about accepted (quasi-standard?) C-libraries.

    Just flanging external libraries might not suffice (or may result
    in clumsy solutions or inherent principal restrictions), though.

    Simula (the first OO language with classes, inheritance, etc.) has
    also an inherent co-routine functionality that fits very well with
    its other supported concepts; simulation and "living objects" (sort
    of). Created objects may have code executed (their "life"), and may temporarily detach themselves or resume other objects. Its builtin
    and more powerful simulation features also rely on that underlying
    co-routine functionality.

    I'd be curious about what "C" (or C++) actually provides when they
    speak about co-routines (whether it's libraries or built-ins).

    C does not have any direct co-routine support in the language and
    standard library, other than setjmp/longjmp that can be used for implementation.

    A popular (relatively speaking) way to do stackless co-routines in C is basically macro wrappers around a switch statement. Your coroutine has
    a parameter that is used by the switch to jump to the current entry
    point. Your "await" and "yield" operations (macros) make a "case" label
    with a new entry point, and returns that from the function or passes it
    on to the next co-routine. Any local variables that you want to keep
    between invocations need to be manually saved i some way, such as inside
    a static or heap-allocated struct. The "Protothreads" implementation of
    this has been used on very small microcontrollers.

    More sophisticated solutions involve longjmp and setjmp, which are more flexible and do more automatically, but are quite a lot more costly in
    runtime speed (but still much lighter than OS threads). These libraries
    may be stackless or stackfull, with limited portability.

    C++20 gained stackless co-routines in the language, with keywords and
    standard library functions. Not all tools implement them, and while
    they can automate some parts of using co-routines, they also involve a
    lot of boiler-plate code and type mess, making them much uglier and more
    error prone than in languages with clearer support for co-routines (like Python or Go).



    Yes, C is getting left behind in this regard ...

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    I certainly wouldn't call her claim ignorant; I think it depends on
    the abstraction level one has, but also on the expectations, about
    what's possible, and what one knows from other languages or areas.

    In the stone-age era a club might have been considered a good tool.

    In 1973, C was very new and primitive, and was quickly followed by a
    number of diverging and inconsistent versions. K&R C, the language from
    "The C Programming Language", was a huge improvement and standardisation compared to 1973 C. ANSI C / C89 / C90 was another massive step
    forward, as was C99.

    To suggest that C hasn't improved much since 1973 is either totally
    ignorant of the history of the language, or a deliberate lie. I choose
    to give Bonita the benefit of the doubt and assume ignorance.

    Being a very subjective matter I suggest to abandon that subtopic.


    I had not intended to reply to Bonita here - replying to Bonita is
    seldom useful IME, especially in c.l.c. But I am happy to reply to your posts!


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Friday, June 12, 2026 13:15:59
    Am 12.06.2026 um 06:19 schrieb Chris M. Thomasson:

    The fibers float along the threads... ;^)

    If you have as many fibres as you otherwise would have coroutines
    and the number is lage you waste a lot of memory.
    The only difference is that with fibers you can switch the context
    from any function.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Friday, June 12, 2026 13:18:00
    Am 12.06.2026 um 12:42 schrieb David Brown:

    More sophisticated solutions involve longjmp and setjmp, which are more flexible and do more automatically, but are quite a lot more costly in runtime speed (but still much lighter than OS threads).˙ These libraries
    may be stackless or stackfull, with limited portability.

    With setjmp() and longjmp() you can jump out of a function,
    but not back inside.

    C++20 gained stackless co-routines in the language, with keywords and standard library functions.˙ Not all tools implement them, and while
    they can automate some parts of using co-routines, they also involve a
    lot of boiler-plate code and type mess, making them much uglier and more error prone than in languages with clearer support for co-routines (like Python or Go).

    The boilerplate code is < 50 lines; so not much.


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From David Brown@3:633/10 to All on Friday, June 12, 2026 13:59:38
    On 12/06/2026 13:18, Bonita Montero wrote:
    Am 12.06.2026 um 12:42 schrieb David Brown:

    More sophisticated solutions involve longjmp and setjmp, which are
    more flexible and do more automatically, but are quite a lot more
    costly in runtime speed (but still much lighter than OS threads).
    These libraries may be stackless or stackfull, with limited portability.

    With setjmp() and longjmp() you can jump out of a function,
    but not back inside.

    Of course you can jump back - longjmp() jumps to where you had
    previously called setjmp(), and you have a new setjmp() just before the longjmp() so that you can jump back.


    C++20 gained stackless co-routines in the language, with keywords and
    standard library functions.˙ Not all tools implement them, and while
    they can automate some parts of using co-routines, they also involve a
    lot of boiler-plate code and type mess, making them much uglier and
    more error prone than in languages with clearer support for co-
    routines (like Python or Go).

    The boilerplate code is < 50 lines; so not much.


    The source boilerplate code overhead for Protothreads is about a tenth
    of that. The overhead for other C coroutine libraries (or coroutines in languages with real support) is basically nothing.


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bart@3:633/10 to All on Friday, June 12, 2026 14:51:00
    On 12/06/2026 11:42, David Brown wrote:
    On 11/06/2026 18:50, Janis Papanagnou wrote:
    On 2026-06-11 09:52, David Brown wrote:
    On 11/06/2026 09:21, Bonita Montero wrote:

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    I certainly wouldn't call her claim ignorant; I think it depends on
    the abstraction level one has, but also on the expectations, about
    what's possible, and what one knows from other languages or areas.

    In the stone-age era a club might have been considered a good tool.

    In 1973, C was very new and primitive, and was quickly followed by a
    number of diverging and inconsistent versions.˙ K&R C, the language from "The C Programming Language", was a huge improvement and standardisation compared to 1973 C.˙ ANSI C / C89 / C90 was another massive step
    forward, as was C99.

    It's still quite primitive.

    Some bits have been more standardised. Some 'improvements' have been
    done crudely and without touching the core language, for example by
    bolting on stuff via extra headers.

    Many changes have been low-key and dull, but then there have been others
    that are over-ambitious for the language, such as VLAs and BitInt. Or
    are just plain ugly, such as compound literals (see below).

    Meanwhile most of the quirks and poor design aspects are still there.

    It seems that there are two approaches commonly used to get around its shortcomings:

    * Use the macro processor, either via standard headers, or by everyone
    rolling their own mini-solutions

    * Putting a huge amount of effort into tools that can help detect or get
    around problems, rather than actually fixing the language. But here,
    those solutions are specific to the tool

    This is not to say that C should have ended up looking like C++. That's
    got its own problems, as well as inheriting many of C's.



    To suggest that C hasn't improved much since 1973 is either totally
    ignorant of the history of the language, or a deliberate lie.˙ I choose
    to give Bonita the benefit of the doubt and assume ignorance.

    BM doesn't like C because it doesn't have all the toys that C++ provides
    and which they have become dependent on (and which strangely, always
    seem to result in more complicated solutions than in C!).

    -------

    Regarding compound literals, why is one necessary when assigning to 'q'
    here:

    typedef struct {double x, y;} Point;

    Point p = {10, 20};
    Point q;
    q = (Point){30, 40};

    The initialisation of 'p' doesn't need it, so can't you just do this:

    q = {30, 40};





    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From David Brown@3:633/10 to All on Friday, June 12, 2026 16:04:09
    On 12/06/2026 15:51, Bart wrote:
    On 12/06/2026 11:42, David Brown wrote:
    On 11/06/2026 18:50, Janis Papanagnou wrote:
    On 2026-06-11 09:52, David Brown wrote:
    On 11/06/2026 09:21, Bonita Montero wrote:

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    I certainly wouldn't call her claim ignorant; I think it depends on
    the abstraction level one has, but also on the expectations, about
    what's possible, and what one knows from other languages or areas.

    In the stone-age era a club might have been considered a good tool.

    In 1973, C was very new and primitive, and was quickly followed by a
    number of diverging and inconsistent versions.˙ K&R C, the language
    from "The C Programming Language", was a huge improvement and
    standardisation compared to 1973 C.˙ ANSI C / C89 / C90 was another
    massive step forward, as was C99.

    It's still quite primitive.

    Compared to many modern languages, it is small and simple. Its heritage
    goes back 50 years, but it has improved greatly since then.

    You don't like C - we know that. There's no need to put the broken
    record on repeat.



    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From fir@3:633/10 to All on Friday, June 12, 2026 16:25:22
    Bart pisze:
    On 12/06/2026 11:42, David Brown wrote:
    On 11/06/2026 18:50, Janis Papanagnou wrote:
    On 2026-06-11 09:52, David Brown wrote:
    On 11/06/2026 09:21, Bonita Montero wrote:

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    I certainly wouldn't call her claim ignorant; I think it depends on
    the abstraction level one has, but also on the expectations, about
    what's possible, and what one knows from other languages or areas.

    In the stone-age era a club might have been considered a good tool.

    In 1973, C was very new and primitive, and was quickly followed by a
    number of diverging and inconsistent versions.˙ K&R C, the language
    from "The C Programming Language", was a huge improvement and
    standardisation compared to 1973 C.˙ ANSI C / C89 / C90 was another
    massive step forward, as was C99.

    It's still quite primitive.

    Some bits have been more standardised. Some 'improvements' have been
    done crudely and without touching the core language, for example by
    bolting on stuff via extra headers.

    Many changes have been low-key and dull, but then there have been others that are over-ambitious for the language, such as VLAs and BitInt. Or
    are just plain ugly, such as compound literals (see below).

    Meanwhile most of the quirks and poor design aspects are still there.


    they not want to break c codes (and this is obviously right)


    BUT it opens a question - it is possibility to
    add c extensions as a form of compile flags
    whose you could turn on or off...

    it would then result in a situation when
    some more new codes would use them and
    the wuestion is if it is right way or no

    i think that some really handy robably could be added
    - like this -see-below i mentioned (makin symbols be visible not only up
    in code but also down in code) OR that handy unsigned c ='shgshs' thing
    which i would like to use

    they could even add resizable rrays in fact

    int tab[10];

    foo()
    {
    tab.size*=1.5;
    }

    this is no problem in that (table is implemented
    on heap, thise syntax just calls reallocks)

    and that at least would be big change

    ALSO they could add some things to standard c lib
    (like this fopen for socket-like internet connections)
    and possibly typeslike float3 and basic arithmetic
    for them


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From fir@3:633/10 to All on Friday, June 12, 2026 16:28:00
    fir pisze:
    Bart pisze:
    On 12/06/2026 11:42, David Brown wrote:
    On 11/06/2026 18:50, Janis Papanagnou wrote:
    On 2026-06-11 09:52, David Brown wrote:
    On 11/06/2026 09:21, Bonita Montero wrote:

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    I certainly wouldn't call her claim ignorant; I think it depends on
    the abstraction level one has, but also on the expectations, about
    what's possible, and what one knows from other languages or areas.

    In the stone-age era a club might have been considered a good tool.

    In 1973, C was very new and primitive, and was quickly followed by a
    number of diverging and inconsistent versions.˙ K&R C, the language
    from "The C Programming Language", was a huge improvement and
    standardisation compared to 1973 C.˙ ANSI C / C89 / C90 was another
    massive step forward, as was C99.

    It's still quite primitive.

    Some bits have been more standardised. Some 'improvements' have been
    done crudely and without touching the core language, for example by
    bolting on stuff via extra headers.

    Many changes have been low-key and dull, but then there have been
    others that are over-ambitious for the language, such as VLAs and
    BitInt. Or are just plain ugly, such as compound literals (see below).

    Meanwhile most of the quirks and poor design aspects are still there.


    they not want to break c codes (and this is obviously right)


    BUT it opens a question - it is possibility to
    add c extensions as a form of compile flags
    whose you could turn on or off...

    it would then result in a situation when
    some more new codes would use them and
    the wuestion is if it is right way or no

    i think that some really handy robably could be added
    - like this -see-below i mentioned (makin symbols be visible not only up
    in code but also down in code) OR that handy unsigned c ='shgshs'˙ thing which i would like to use

    they could even add resizable rrays in fact

    int tab[10];

    foo()
    {
    ˙ tab.size*=1.5;
    }


    those resizable arrays (exact that) are imo absolute must in modern times c


    this is no problem in that (table is implemented
    on heap, thise syntax just calls reallocks)

    and that at least would be big change

    ALSO they could add some things to standard c lib
    (like this fopen for socket-like internet connections)
    and possibly typeslike float3 and basic arithmetic
    for them



    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bart@3:633/10 to All on Friday, June 12, 2026 16:16:15
    On 12/06/2026 15:04, David Brown wrote:
    On 12/06/2026 15:51, Bart wrote:
    On 12/06/2026 11:42, David Brown wrote:
    On 11/06/2026 18:50, Janis Papanagnou wrote:
    On 2026-06-11 09:52, David Brown wrote:
    On 11/06/2026 09:21, Bonita Montero wrote:

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    I certainly wouldn't call her claim ignorant; I think it depends on
    the abstraction level one has, but also on the expectations, about
    what's possible, and what one knows from other languages or areas.

    In the stone-age era a club might have been considered a good tool.

    In 1973, C was very new and primitive, and was quickly followed by a
    number of diverging and inconsistent versions.˙ K&R C, the language
    from "The C Programming Language", was a huge improvement and
    standardisation compared to 1973 C.˙ ANSI C / C89 / C90 was another
    massive step forward, as was C99.

    It's still quite primitive.

    Compared to many modern languages, it is small and simple.˙ Its heritage goes back 50 years, but it has improved greatly since then.

    You don't like C - we know that.˙ There's no need to put the broken
    record on repeat.


    I was responding to the claims that C has improved significantly.

    You used 'huge improvement', 'massive step forward' and now 'improved greatly'.

    I don't see it, sorry.

    I'm also suggesting that what you are seeing are the /tools/ used to
    work with it. Try using a small C compiler and see if you get the same experience. Remember the language is the same!





    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From David Brown@3:633/10 to All on Friday, June 12, 2026 17:31:22
    On 12/06/2026 17:16, Bart wrote:
    On 12/06/2026 15:04, David Brown wrote:
    On 12/06/2026 15:51, Bart wrote:
    On 12/06/2026 11:42, David Brown wrote:
    On 11/06/2026 18:50, Janis Papanagnou wrote:
    On 2026-06-11 09:52, David Brown wrote:
    On 11/06/2026 09:21, Bonita Montero wrote:

    C hasn't been improved much since 1973.

    What an astoundingly ignorant claim.

    I certainly wouldn't call her claim ignorant; I think it depends on
    the abstraction level one has, but also on the expectations, about
    what's possible, and what one knows from other languages or areas.

    In the stone-age era a club might have been considered a good tool.

    In 1973, C was very new and primitive, and was quickly followed by a
    number of diverging and inconsistent versions.˙ K&R C, the language
    from "The C Programming Language", was a huge improvement and
    standardisation compared to 1973 C.˙ ANSI C / C89 / C90 was another
    massive step forward, as was C99.

    It's still quite primitive.

    Compared to many modern languages, it is small and simple.˙ Its
    heritage goes back 50 years, but it has improved greatly since then.

    You don't like C - we know that.˙ There's no need to put the broken
    record on repeat.


    I was responding to the claims that C has improved significantly.

    You used 'huge improvement', 'massive step forward' and now 'improved greatly'.


    Yes.

    I don't see it, sorry.

    I don't consider your opinions here to be of particular relevance - your hatred of everything related to C blinds you. You are so obsessed with
    what you perceive (and you have the right to your subjective opinions,
    likes and dislikes) as flaws in C that you are unable to see the
    improvements in the language over the years.

    I am not claiming C is in any sense "perfect" - merely that it has
    improved greatly since its conception.

    (I am aware that "improvements" are also subjective - if a programmer
    thinks implicit int, lack of function prototypes, lack of
    standardisation, etc., are all good things, then they might feel C has
    gone downhill since 1973.)


    I'm also suggesting that what you are seeing are the /tools/ used to
    work with it. Try using a small C compiler and see if you get the same experience. Remember the language is the same!


    Your suggestion is incorrect.

    I /do/ think that tools for C have also improved massively, but that is
    in addition to improvements in the language.

    And I do not care how primitive small C compilers are, other than to
    note that if a small C compiler does not support newer C standards then
    it is of no relevance when discussing how the C language has been improved.



    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Friday, June 12, 2026 18:42:02
    On Fri, 12 Jun 2026 13:59:38 +0200
    David Brown <david.brown@hesbynett.no> wrote:

    On 12/06/2026 13:18, Bonita Montero wrote:
    Am 12.06.2026 um 12:42 schrieb David Brown:

    More sophisticated solutions involve longjmp and setjmp, which are
    more flexible and do more automatically, but are quite a lot more
    costly in runtime speed (but still much lighter than OS threads).
    These libraries may be stackless or stackfull, with limited
    portability.

    With setjmp() and longjmp() you can jump out of a function,
    but not back inside.

    Of course you can jump back - longjmp() jumps to where you had
    previously called setjmp(), and you have a new setjmp() just before
    the longjmp() so that you can jump back.


    C++20 gained stackless co-routines in the language, with keywords
    and standard library functions.? Not all tools implement them, and
    while they can automate some parts of using co-routines, they also
    involve a lot of boiler-plate code and type mess, making them much
    uglier and more error prone than in languages with clearer support
    for co- routines (like Python or Go).

    The boilerplate code is < 50 lines; so not much.


    The source boilerplate code overhead for Protothreads is about a
    tenth of that. The overhead for other C coroutine libraries (or
    coroutines in languages with real support) is basically nothing.


    Big part of inconvenience of C++ co-routines is because of need to
    support constructors, destructors, including virtual ones and, worst
    of all, exceptions.
    C has none of those, so potentially similar stackless co-routines could
    have been added more naturally. But there is one critical part of the
    puzzle lacking - C++ style co-routines depend on heap. In C++ heap is a
    part of the core language, so there are no difficulties. In C, on the
    other hand, heap management belongs to Standard Library rather than to
    core language. In free-standing C implementation heap management can
    be completely absent. Last year I tried (not vary hard) to find
    solution to that problem, but language design is not really my cup of
    tee, so I was unable to invent anything satisfactory.

    At the end I came to conclusion, that for sort of jobs (in memory
    constrained embedded environment) where I would not mind having
    stackless co-routines, they are not necessarily the best
    technical solution.
    It's quite possible that normal co-routines, a.k.a. fibers, are better solution. And fibers don't have to be part of core language or even of
    Standard Library. However, fibers have one problem for which I would
    prefer language support - sometimes, when running in slim fiber, I want
    to call a "heavy" function, like sprintf or such, sort of function that
    in worst case needs a lot of stack space. Today in such case I have to
    provide a space for such function on stack of each and any fiber that
    can potentially use it. If I have dozens of fibers, that would be quite
    a lot wasted memory - instead of ~200 byte per fiber, or may be even
    less, I'd have to allocate few KB. That's where enhancement in core
    language code be handy - I want an ability to call a function not at
    current stack, but on some sort of common stack, shared by all fibers
    of the program. Or in case of multithreaded program, shared by all
    fibers of particular thread. Of course, in theory that sort of
    trampoline call/return could be implemented as a 3rd party library
    function as well, but somehow I fill that it belongs to language, at
    least as much as setjmp/lonjmp belongs to it, but preferably even in
    more integrated manner,



    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Janis Papanagnou@3:633/10 to All on Friday, June 12, 2026 18:14:11
    On 2026-06-12 12:42, David Brown wrote:
    [ coroutines; C++, C, Go, Python ]

    Thanks for the descriptions. - It's probably worth (and useful to
    better understand the various designs) to have some sample code.
    You certainly made me curious, and on occasion I'll inspect those
    languages in more detail concerning their designs of co-routines.


    [ about substantial progress in C-language evolution ]

    Well, I don't think this addressed the "personal abstraction" view
    I mentioned to explain subjectively differing valuations, but since
    my intention was anyway to not foster that subjective sub-topic, I
    leave it here as it is. ;-)


    I had not intended to reply to Bonita here - replying to Bonita is
    seldom useful IME, especially in c.l.c.˙ But I am happy to reply to your posts!

    Thanks for that appreciation. :-)

    Janis


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From David Brown@3:633/10 to All on Friday, June 12, 2026 18:20:41
    On 12/06/2026 17:42, Michael S wrote:
    On Fri, 12 Jun 2026 13:59:38 +0200
    David Brown <david.brown@hesbynett.no> wrote:

    On 12/06/2026 13:18, Bonita Montero wrote:
    Am 12.06.2026 um 12:42 schrieb David Brown:

    More sophisticated solutions involve longjmp and setjmp, which are
    more flexible and do more automatically, but are quite a lot more
    costly in runtime speed (but still much lighter than OS threads).
    These libraries may be stackless or stackfull, with limited
    portability.

    With setjmp() and longjmp() you can jump out of a function,
    but not back inside.

    Of course you can jump back - longjmp() jumps to where you had
    previously called setjmp(), and you have a new setjmp() just before
    the longjmp() so that you can jump back.


    C++20 gained stackless co-routines in the language, with keywords
    and standard library functions.˙ Not all tools implement them, and
    while they can automate some parts of using co-routines, they also
    involve a lot of boiler-plate code and type mess, making them much
    uglier and more error prone than in languages with clearer support
    for co- routines (like Python or Go).

    The boilerplate code is < 50 lines; so not much.


    The source boilerplate code overhead for Protothreads is about a
    tenth of that. The overhead for other C coroutine libraries (or
    coroutines in languages with real support) is basically nothing.


    Big part of inconvenience of C++ co-routines is because of need to
    support constructors, destructors, including virtual ones and, worst
    of all, exceptions.

    Good point, thanks.

    C has none of those, so potentially similar stackless co-routines could
    have been added more naturally. But there is one critical part of the
    puzzle lacking - C++ style co-routines depend on heap.

    Heap-allocated storage is sometimes used with coroutines in C too, but
    the user has the choice. With Protothreads, you need to put your local variables somewhere if you want them to retain values across calls -
    typically you hold them in a struct. You choose if that is a static
    struct - fast, reliable, but not re-entrant - or in a heap allocation to
    allow re-entrant functions. I believe C++ coroutines always put the
    local frame on the heap.

    In C++ heap is a
    part of the core language, so there are no difficulties. In C, on the
    other hand, heap management belongs to Standard Library rather than to
    core language. In free-standing C implementation heap management can
    be completely absent.

    You can certainly use C++ with little or no heap usage (I do that
    regularly), but you need to avoid many parts of the standard library.
    (Though it is possible to use custom allocators for some things.)

    Last year I tried (not vary hard) to find
    solution to that problem, but language design is not really my cup of
    tee, so I was unable to invent anything satisfactory.

    At the end I came to conclusion, that for sort of jobs (in memory
    constrained embedded environment) where I would not mind having
    stackless co-routines, they are not necessarily the best
    technical solution.
    It's quite possible that normal co-routines, a.k.a. fibers, are better solution. And fibers don't have to be part of core language or even of Standard Library. However, fibers have one problem for which I would
    prefer language support - sometimes, when running in slim fiber, I want
    to call a "heavy" function, like sprintf or such, sort of function that
    in worst case needs a lot of stack space. Today in such case I have to provide a space for such function on stack of each and any fiber that
    can potentially use it. If I have dozens of fibers, that would be quite
    a lot wasted memory - instead of ~200 byte per fiber, or may be even
    less, I'd have to allocate few KB. That's where enhancement in core
    language code be handy - I want an ability to call a function not at
    current stack, but on some sort of common stack, shared by all fibers
    of the program. Or in case of multithreaded program, shared by all
    fibers of particular thread. Of course, in theory that sort of
    trampoline call/return could be implemented as a 3rd party library
    function as well, but somehow I fill that it belongs to language, at
    least as much as setjmp/lonjmp belongs to it, but preferably even in
    more integrated manner,



    You are describing very familiar issues. I am increasingly convinced
    that to have an "ideal" language for constrained embedded systems, you
    need something significantly different from either C or C++ models.
    (And no, Rust is not any better.) But that would be well outside
    c.l.c., and I have not figured out the details of what would be needed.

    In the meantime, I just try to use microcontrollers with a bit more
    memory and speed overhead, and give my RTOS threads a bit more stack
    space. It feels like an inefficient solution, but it's a tradeoff of developer time to runtime resources - and the price of microcontrollers
    with a little more RAM drops faster than the cost of developers!




    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Friday, June 12, 2026 18:58:59
    Am 12.06.2026 um 13:59 schrieb David Brown:

    Of course you can jump back - longjmp() ...

    No, the stackframe of the function you've jumped out of is very
    likely to be overitten.

    The source boilerplate code overhead for Protothreads is about a tenth
    of that.

    This macro-hell sucks and isn't easy to be debugged.
    C sucks at all.

    The overhead for other C coroutine libraries (or coroutines in languages with real support) is basically nothing.

    Resuming a coroutine in C++ also nearly costs nothing.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Janis Papanagnou@3:633/10 to All on Friday, June 12, 2026 19:13:18
    On 2026-06-12 15:51, Bart wrote:
    On 12/06/2026 11:42, David Brown wrote:
    [ C-language ]

    It's still quite primitive.

    Some bits have been more standardised. Some 'improvements' have been
    done crudely and without touching the core language, for example by
    bolting on stuff via extra headers.

    Many changes have been low-key and dull, but then there have been others that are over-ambitious for the language, such as VLAs and BitInt. Or
    are just plain ugly, such as compound literals (see below).

    Meanwhile most of the quirks and poor design aspects are still there.

    While I seem to share some aspects of your opinion I'm not as convinced
    as you seem to be concerning sensible progress where you are hinting on
    VLA and BitInt.

    I think "C", as designed, cannot really evolve to something substantial "better". That's why I _accept_ "C" as what it is, for its application
    areas that undeniably are there!

    It seems that there are two approaches commonly used to get around its shortcomings:

    * Use the macro processor, either via standard headers, or by everyone
    ˙ rolling their own mini-solutions

    That, Cpp, never appeared to me as anything solving any inherent flaw.


    * Putting a huge amount of effort into tools that can help detect or get
    ˙ around problems, rather than actually fixing the language. But here,
    ˙ those solutions are specific to the tool

    I think you cannot really "fix" the language. It is what it is. And it
    won't substantially change, I'd guess, given its evolution during the
    past decades.


    *** warning *** below this point there's mostly only C++ stuff ***


    This is not to say that C should have ended up looking like C++. That's
    got its own problems, as well as inheriting many of C's.

    [...]

    BM doesn't like C because it doesn't have all the toys that C++ provides

    What "toys"?

    and which they have become dependent on (and which strangely,

    You mean, like STL, as *standard* part of the language? - Or what?

    always seem to result in more complicated solutions than in C!).

    I suggest to use simple means for simple things (in "C" and in C++).

    For complex things you have much better structuring means than in "C",
    so for non-trivial things you gain clarity and simplicity with C++.
    (The latter is what I understand was also Bonita trying to convey.)


    -------

    Regarding compound literals, why is one necessary when assigning to 'q' here:

    ˙˙˙ typedef struct {double x, y;} Point;

    ˙˙˙ Point p = {10, 20};
    ˙˙˙ Point q;
    ˙˙˙˙˙˙˙˙˙ q = (Point){30, 40};

    The initialisation of 'p' doesn't need it, so can't you just do this:

    ˙˙˙˙˙˙˙˙˙ q = {30, 40};


    I'm not sure what that convoluted C-syntax is supposed to explain.
    Your brain seems so used to old "C" patterns that you missed the
    possibilities that other higher-level languages like C++ provide.
    The C++ syntax is just: struct Point { ... };
    Or, if you want "access control": class Point { ... };


    Point appears to me to be a "fundamental" type, and so I'd certainly
    have a class defined, so that I can do sensible operations on Point
    objects.

    My C++ days are long history, but I certainly had Point declarations
    in code that could be used as in

    Point p (10, 30);
    Point q;
    q = Point (30, 40);
    Point r;
    r = { 20, 70 }; // if you feel more comfortable with that syntax

    Line s (p, q); // just an extension to show how nicely it extends

    and so on.

    The point is that (for non-toy code!) it pays to design classes and
    then make use of clean and consistent expressions as I depicted above.

    For above to work you only need to define the usual constructors, i.e.
    instead of

    struct Point { int x, y; };

    you declare it with two sensible any typical constructors for Point

    struct Point { int x, y;
    Point (int _x, int _y) : x(_x), y(_y) {};
    Point (void) : x(0), y(0) {};
    };

    and you can then make use of the clear syntax I showed above.

    Those Constructors may look strange to the uninitiated C-user; you
    certainly have to _learn_ the language - as you should learn "C"!

    Janis


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Friday, June 12, 2026 13:45:44
    Bart <bc@freeuk.com> writes:
    [...]
    It's still quite primitive.

    Some bits have been more standardised. Some 'improvements' have been
    done crudely and without touching the core language, for example by
    bolting on stuff via extra headers.

    What you call "crude", I call taking advantage of existing language
    features to add new functionality without having to change the
    core language.

    The uint32_t et al types could have been added as keywords
    (even, as you would no doubt have preferred, with different
    names), but it wasn't necessary to do so. Defining them in
    a header made it possible to duplicate the functionality for
    use with pre-C99 compilers; see for example Doug Gwyn's q8, <https://www.lysator.liu.se/c/q8/index.html>. (And if you think the fixed-width types are in some sense more fundamental than short,
    int, long et al, and the former should be keywords and the latter
    should be typedefs, that's a valid opinion, but C isn't going to
    make that particular change.)

    When C added complex number support, it was done as a core language
    feature because the language didn't provide the facilities to define
    it in a header. C++ did it in a header, because it was possible
    to do so.

    [...]

    Regarding compound literals, why is one necessary when assigning to
    'q' here:

    typedef struct {double x, y;} Point;

    Point p = {10, 20};
    Point q;
    q = (Point){30, 40};

    The initialisation of 'p' doesn't need it, so can't you just do this:

    q = {30, 40};

    Because an initializer is evaluated in a context that depends on the
    type of the object being initialized, but an expression, even if it's
    the RHS of an assignment, is not.

    In almost all cases, the type and semantics of an expression (even if
    it's a subexpression) are fully determined by the expression itself,
    not by the context in which it appears. 42 is of type int, even when
    it's assigned to a floating-point object; the assignment imposes a
    conversion.

    In `Point p = {10, 20};`, the initializer is evaluated in a context
    where the compiler knows that the result type is Point.

    In `p = {10, 20};`, if it weren't a syntax error, the compiler
    would not (be required to) know that {10, 20} is being assigned
    to an object of type Point. It could be some other struct type,
    or an array.

    There are languages that work differently. In Ada, for example, the
    equivalent `P := (10, 20);` is valid, because the RHS is evaluated
    in a context that takes the type of the LHS into account. (10, 20)
    is a valid expression in Ada, and its type depends on its context.
    (Ada doesn't have expression statements, so there always a context.)

    When compound literals were added to the language, there were several
    options:

    1. Rework expression evaluation so that the type of an expression
    depends on its context. Specify that a braced-initializer is a
    kind of expression. Write several pages of standardese specifying
    exactly when and how this happens. Then `p = {10, 20};` is
    valid, and `{10, 20}` is of type Point. Presumably an expression
    statement `{10, 20};` would be a constraint violation, because
    there's no context to determine its type. Decide whether
    `ptr = &{10, 20};` determines the type of `{10, 20}` or not.
    Argue for years about whether this breaks existing code, and
    how much of a problem that is.

    2. A special-case version of the above, where a braced initializer
    is an expression, and its type is determined by its context.
    Write several pages of standardese specifying exactly how
    the context determines the type and the cases where the type
    can't be determined and therefore a constraint is violated.
    Contexts include the RHS of an assignment, a function argument,
    and so on. Specify that a braced initializer that is, or
    is part of, an initializer is *not* an expression (otherwise
    `int arr[2] = {10, 20};` would become invalid) -- but maybe
    a parenthesized braced-initializer expression can be used
    in an initializer? Argue for years about that.

    3. Make the syntax of a compound literal just a little more
    explicit, consisting of a parenthesized type name followed a
    braced initializer, so the type must be specified rather than
    inferred.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Friday, June 12, 2026 13:48:27
    Bart <bc@freeuk.com> writes:
    [...]
    I was responding to the claims that C has improved significantly.

    You used 'huge improvement', 'massive step forward' and now 'improved greatly'.

    I don't see it, sorry.
    [...]

    Yes, let's debate the meanings "huge improvement" and "massive step
    forward", and whether the changes in C are huge, large, or minor.
    Such debates are always interesting, productive, and illuminating.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, June 12, 2026 23:52:32
    On Fri, 12 Jun 2026 06:16:42 +0200, Bonita Montero wrote:

    Am 12.06.2026 um 03:32 schrieb Lawrence D?Oliveiro:

    I don?t know what?s ?heavyweight? about threading, beyond the stack
    allocations. ...

    Yes, the allocation of the stack is very expensive. And the
    context-switch between threads is a magnitudes more expensive than
    switching between two coroutine conexts.

    Why should that be? What extra overhead is there in context-switching
    between preemptive threads, versus non-preemptive ones?

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, June 12, 2026 23:54:57
    On Thu, 11 Jun 2026 21:05:29 -0700, Chris M. Thomasson wrote:

    On 6/11/2026 6:33 PM, Lawrence D?Oliveiro wrote: > > Are these
    ?fibre? things just some kind of runtime abstraction > built on top
    of OS threads? Basically. You need to make your own scheduler for the
    fiber on the threads.

    Been there, done that. Actually, the OS concerned (VAX/VMS) didn?t
    even support threads at the time: but it had asynchronous I/O and
    timer completion routines, and I was able to build a fully-preemptive
    threading model on top of that.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Saturday, June 13, 2026 00:01:21
    On Thu, 11 Jun 2026 21:11:13 -0700, Chris M. Thomasson wrote:

    FWIW, check this shit out. Coroutines can be emulated even in BASIC.
    This is a recursive stack here. Its all manual... :^)

    [code omitted]


    I see a lot of ?GOSUB 8000? within the subroutine starting at line
    8000, so that?s a lot of recursion, not coroutines. Plus you?ve got
    the explicit RS array stack for assembling the components of the
    curve. Normally you would either have either recursion or an explicit
    stack, since each one subsumes the functions of the other, so there
    shouldn?t be a need for both.

    In other words, I think you?ve got the worst of both worlds? Recursion
    that isn?t enough to solve the problem purely recursively, plus an
    explicit stack that isn?t enough to keep track of the entire stack
    state?

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bart@3:633/10 to All on Saturday, June 13, 2026 01:03:26
    On 12/06/2026 21:45, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    [...]
    It's still quite primitive.

    Some bits have been more standardised. Some 'improvements' have been
    done crudely and without touching the core language, for example by
    bolting on stuff via extra headers.

    What you call "crude", I call taking advantage of existing language
    features to add new functionality without having to change the
    core language.

    The uint32_t et al types could have been added as keywords
    (even, as you would no doubt have preferred, with different
    names), but it wasn't necessary to do so.

    It's a poor approach:

    * Those types don't exist unless stdint.h is present. That means anyone
    could define their own non-compatible versions

    * Even if stdint.h is used, people could still shadow the names for
    their own purposes

    * Whether a particular stdint type is exactly compatible with a built-in
    type can vary between implementations, causing problems with _Generic
    for example

    * There are problems with literals for such types, and printf support,
    necessitating an auxiliary intypes.h header with lots of ugly macros.

    So, yeah it's crude. I also don't see the advantage of not changing the
    core language. Such changes were needed in C99 anyway in order to
    support VLA, variable modified types, compound literals, designated initialiser, probably some other stuff.

    Building in those types was arguably simpler than most of those. And
    advantage could have been taken to introduce a built-in way of getting
    integer limits (say _Minvalue(T) and _Maxvalue(T)), or even _Minvalue(X)
    etc), instead of dedicated macros for every conceivable type.

    And this is just one feature.


    Defining them in
    a header made it possible to duplicate the functionality for
    use with pre-C99 compilers; see for example Doug Gwyn's q8, <https://www.lysator.liu.se/c/q8/index.html>.

    Everyone made their arrangements anyway. Many still do.

    (And if you think the

    Regarding compound literals, why is one necessary when assigning to
    'q' here:

    typedef struct {double x, y;} Point;

    Point p = {10, 20};
    Point q;
    q = (Point){30, 40};

    The initialisation of 'p' doesn't need it, so can't you just do this:

    q = {30, 40};

    Because an initializer is evaluated in a context that depends on the
    type of the object being initialized, but an expression, even if it's
    the RHS of an assignment, is not.

    In almost all cases, the type and semantics of an expression (even if
    it's a subexpression) are fully determined by the expression itself,
    not by the context in which it appears. 42 is of type int, even when
    it's assigned to a floating-point object; the assignment imposes a conversion.

    In `Point p = {10, 20};`, the initializer is evaluated in a context
    where the compiler knows that the result type is Point.

    In `p = {10, 20};`, if it weren't a syntax error,

    It wouldn't be if allowed.

    the compiler
    would not (be required to) know that {10, 20} is being assigned
    to an object of type Point. It could be some other struct type,
    or an array.

    And?

    I use the term 'closed' for an expression that occurs in a known
    context: something will be done with it and the type is known (pass to a function, assign to a variable, cast it to T etc).

    And 'open' for an expression that is not used for anything and so there
    is no final type to conform too. Here:

    q = {30, 40};

    The RHS is closed. By itself, it's some generic constructor, but it is
    being assigned to 'q', so it knows it is supposed to be a Point type.

    There are languages that work differently. In Ada, for example, the equivalent `P := (10, 20);` is valid, because the RHS is evaluated
    in a context that takes the type of the LHS into account. (10, 20)
    is a valid expression in Ada, and its type depends on its context.
    (Ada doesn't have expression statements, so there always a context.)

    When compound literals were added to the language, there were several options:

    1. Rework expression evaluation so that the type of an expression
    depends on its context.
    ? Specify that a braced-initializer is a
    kind of expression. Write several pages of standardese specifying
    exactly when and how this happens. Then `p = {10, 20};` is
    valid, and `{10, 20}` is of type Point. Presumably an expression
    statement `{10, 20};` would be a constraint violation, because
    there's no context to determine its type. Decide whether
    `ptr = &{10, 20};` determines the type of `{10, 20}` or not.
    Argue for years about whether this breaks existing code, and
    how much of a problem that is.

    2. A special-case version of the above, where a braced initializer
    is an expression, and its type is determined by its context.
    Write several pages of standardese specifying exactly how
    the context determines the type and the cases where the type
    can't be determined and therefore a constraint is violated.

    This need not be as hard as you make out.

    {...} used for initialising is already different.

    There is a possible ambiguity where {...} is used for a compound
    statement, but it could also be a data constructor. But I think that can
    be solved because {...} used for data happens in value-returning contexts.

    Contexts include the RHS of an assignment, a function argument,
    and so on. Specify that a braced initializer that is, or
    is part of, an initializer is *not* an expression (otherwise
    `int arr[2] = {10, 20};` would become invalid) -- but maybe
    a parenthesized braced-initializer expression can be used
    in an initializer?


    I use parentheses (see below); it seems to work. One small issue is when
    there is only one data element, then I need to write (10,) instead of
    (10), which looks like a scalar expression.

    That could probably be fixed, but it wouldn't happen with {10}.

    ------------------------------
    record point = (real x, y)

    point p := (10, 20)
    point q
    q := (30, 40)


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Saturday, June 13, 2026 00:04:20
    On Fri, 12 Jun 2026 13:18:00 +0200, Bonita Montero wrote:

    With setjmp() and longjmp() you can jump out of a function, but not
    back inside.

    Now you?re talking continuations!

    These are quite an interesting control abstraction, since they can be
    used to implement only those control constructs that could be
    considered well-structured. This covers quite a range (e.g. loops,
    exceptions, coroutines) but manages to rule out arbitrary gotos.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Friday, June 12, 2026 17:50:07
    Bart <bc@freeuk.com> writes:
    On 12/06/2026 21:45, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    [...]
    It's still quite primitive.

    Some bits have been more standardised. Some 'improvements' have been
    done crudely and without touching the core language, for example by
    bolting on stuff via extra headers.
    What you call "crude", I call taking advantage of existing language
    features to add new functionality without having to change the
    core language.
    The uint32_t et al types could have been added as keywords
    (even, as you would no doubt have preferred, with different
    names), but it wasn't necessary to do so.

    It's a poor approach:

    * Those types don't exist unless stdint.h is present. That means anyone
    could define their own non-compatible versions

    "Doctor, it hurts when I do this."

    * Even if stdint.h is used, people could still shadow the names for
    their own purposes

    "Doctor, it hurts when I do this."

    Even if int32_t where a keyword (only on implementations with 32-bit integers?), you could redefine it as a macro. So don't do that.

    Yes, there are some inconvenient issues. We've been dealing with them successfully for decades.

    [SNIP]

    Regarding compound literals, why is one necessary when assigning to
    'q' here:

    typedef struct {double x, y;} Point;

    Point p = {10, 20};
    Point q;
    q = (Point){30, 40};

    The initialisation of 'p' doesn't need it, so can't you just do this:

    q = {30, 40};
    Because an initializer is evaluated in a context that depends on the
    type of the object being initialized, but an expression, even if it's
    the RHS of an assignment, is not.

    In almost all cases, the type and semantics of an expression (even if
    it's a subexpression) are fully determined by the expression itself,
    not by the context in which it appears. 42 is of type int, even when
    it's assigned to a floating-point object; the assignment imposes a
    conversion.
    In `Point p = {10, 20};`, the initializer is evaluated in a context
    where the compiler knows that the result type is Point.
    In `p = {10, 20};`, if it weren't a syntax error,

    It wouldn't be if allowed.

    No kidding.

    the compiler
    would not (be required to) know that {10, 20} is being assigned
    to an object of type Point. It could be some other struct type,
    or an array.

    And?

    And ... you should read what I wrote if you want to understand it?

    I use the term 'closed' for an expression that occurs in a known
    context: something will be done with it and the type is known (pass to
    a function, assign to a variable, cast it to T etc).

    And 'open' for an expression that is not used for anything and so
    there is no final type to conform too. Here:

    q = {30, 40};

    The RHS is closed. By itself, it's some generic constructor, but it is
    being assigned to 'q', so it knows it is supposed to be a Point type.

    That's nice.

    As I said, in some languages the type and semantics of an expression
    depend on its context. C is not such a language. You advocate a
    radical change to the way C compilers handle expressions because
    you find the syntax of compound literals (which works perfectly
    well) icky.

    No.

    There are languages that work differently. In Ada, for example, the
    equivalent `P := (10, 20);` is valid, because the RHS is evaluated
    in a context that takes the type of the LHS into account. (10, 20)
    is a valid expression in Ada, and its type depends on its context.
    (Ada doesn't have expression statements, so there always a context.)
    When compound literals were added to the language, there were
    several
    options:
    1. Rework expression evaluation so that the type of an expression
    depends on its context.
    ? Specify that a braced-initializer is a
    kind of expression. Write several pages of standardese specifying
    exactly when and how this happens. Then `p = {10, 20};` is
    valid, and `{10, 20}` is of type Point. Presumably an expression
    statement `{10, 20};` would be a constraint violation, because
    there's no context to determine its type. Decide whether
    `ptr = &{10, 20};` determines the type of `{10, 20}` or not.
    Argue for years about whether this breaks existing code, and
    how much of a problem that is.
    2. A special-case version of the above, where a braced initializer
    is an expression, and its type is determined by its context.
    Write several pages of standardese specifying exactly how
    the context determines the type and the cases where the type
    can't be determined and therefore a constraint is violated.

    This need not be as hard as you make out.

    It wasn't that hard, because the committee went with option 3,
    the one you snipped. (Which is not to suggest that they actually
    considered option 1 or 2.)

    {...} used for initialising is already different.

    Yes, of course it's different. {...} is not an expression.

    There is a possible ambiguity where {...} is used for a compound
    statement, but it could also be a data constructor. But I think that
    can be solved because {...} used for data happens in value-returning contexts.

    Fortunately, we didn't have to solve that problem, because the
    actual syntax for compound literals is unambiguous.

    [...]

    record point = (real x, y)

    point p := (10, 20)
    point q
    q := (30, 40)

    Not C. Don't care.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Saturday, June 13, 2026 05:05:23
    Am 13.06.2026 um 01:52 schrieb Lawrence D?Oliveiro:

    On Fri, 12 Jun 2026 06:16:42 +0200, Bonita Montero wrote:

    Yes, the allocation of the stack is very expensive. And the
    context-switch between threads is a magnitudes more expensive than
    switching between two coroutine conexts.

    Why should that be? What extra overhead is there in context-switching
    between preemptive threads, versus non-preemptive ones?

    Because with threading the context-switch happens inside the kernel.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bart@3:633/10 to All on Saturday, June 13, 2026 11:03:01
    On 13/06/2026 01:50, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    On 12/06/2026 21:45, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    [...]
    It's still quite primitive.

    Some bits have been more standardised. Some 'improvements' have been
    done crudely and without touching the core language, for example by
    bolting on stuff via extra headers.
    What you call "crude", I call taking advantage of existing language
    features to add new functionality without having to change the
    core language.
    The uint32_t et al types could have been added as keywords
    (even, as you would no doubt have preferred, with different
    names), but it wasn't necessary to do so.

    It's a poor approach:

    * Those types don't exist unless stdint.h is present. That means anyone
    could define their own non-compatible versions

    "Doctor, it hurts when I do this."


    * Even if stdint.h is used, people could still shadow the names for
    their own purposes

    "Doctor, it hurts when I do this."

    Seriously? You have a language where you can literally do this:

    #include <stdint.h>
    int32_t int32_t;
    int32_t = 0;

    and that is just fine; just "don't do it"! In that case, we might as
    well allow:

    int int;

    Can you understand how crazy the above looks from outside?


    As I said, in some languages the type and semantics of an expression
    depend on its context. C is not such a language. You advocate a
    radical change to the way C compilers handle expressions because
    you find the syntax of compound literals (which works perfectly
    well) icky.

    But it woud be nicer if they didn't need that cast, yes? So having to
    write it is less desirable.

    {...} used for initialising is already different.

    Yes, of course it's different. {...} is not an expression.

    Maybe that was the problem.

    There is a possible ambiguity where {...} is used for a compound
    statement, but it could also be a data constructor. But I think that
    can be solved because {...} used for data happens in value-returning
    contexts.

    Fortunately, we didn't have to solve that problem, because the
    actual syntax for compound literals is unambiguous.

    Sure:

    int a;
    a = (int){123.45};
    a = (int)(123.45);

    Nothing to see here.


    [...]

    record point = (real x, y)

    point p := (10, 20)
    point q
    q := (30, 40)

    Not C. Don't care.


    And yet you said this:

    "In Ada, for example, the equivalent `P := (10, 20);` is valid, because
    the RHS is evaluated...".

    My language is much closer to C, and it doesn't have much problem with
    it. I was merely asking why you have to write:

    DrawLine((Point){x1, y1}, (Point){x2, y2});

    rather than:

    DrawLine({x1, y1}, {x2, y2});

    I know the {} are necessary in part because of the 'comma' operator,
    which stops you being able to use (x1, y1) here, or A[i, j] for 2D indexing.


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From tTh@3:633/10 to All on Saturday, June 13, 2026 12:14:15
    On 6/13/26 12:03, Bart wrote:

    Seriously? You have a language where you can literally do this:

    ˙ #include <stdint.h>
    ˙ int32_t int32_t;
    ˙ int32_t = 0;

    and that is just fine; just "don't do it"! In that case, we might as
    well allow:

    ˙ int int;

    Can you understand how crazy the above looks from outside?

    In our technical jargon, we have the perfect acronym to
    describe this kind of programming: GIGO. Look at wikipedia
    for an astounding description of that syndrom.

    https://en.wikipedia.org/wiki/Garbage_in,_garbage_out

    --
    ** **
    * tTh des Bourtoulots *
    * http://maison.tth.netlib.re/ *
    ** **

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Saturday, June 13, 2026 03:48:21
    Bart <bc@freeuk.com> writes:
    [...]
    My language is much closer to C, and it doesn't have much problem with
    it. I was merely asking why you have to write:

    DrawLine((Point){x1, y1}, (Point){x2, y2});

    rather than:

    DrawLine({x1, y1}, {x2, y2});

    You asked. I answered.

    [...]

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Janis Papanagnou@3:633/10 to All on Saturday, June 13, 2026 14:35:50
    On 2026-06-13 12:14, tTh wrote:
    On 6/13/26 12:03, Bart wrote:

    Seriously? You have a language where you can literally do this:

    ˙˙ #include <stdint.h>
    ˙˙ int32_t int32_t;
    ˙˙ int32_t = 0;

    and that is just fine; just "don't do it"! In that case, we might as
    well allow:

    ˙˙ int int;

    Can you understand how crazy the above looks from outside?

    Yes. (And I suppose everyone here understands that!)

    Languages have various possibilities to define their lexical rules,
    their syntax, and their semantics.

    It's certainly quite common to have _reserved words_ that may only
    be used in certain syntactical contexts. But there's also languages
    that allow context-depending placement of names that happen to be
    also tokens of the language.

    Consider, for example, in shell: for for in in do ; do : ; done

    Such pieces of code are a result of a programmer's sick brain and
    not the problem of a language.

    Keith already noted: "Doctor, it hurts when I do this."

    And tTh said:

    ˙˙ In our technical jargon, we have the perfect acronym to
    ˙˙ describe this kind of programming: GIGO. Look at wikipedia
    ˙˙ for an astounding description of that syndrom.

    ˙˙ https://en.wikipedia.org/wiki/Garbage_in,_garbage_out

    Bart, do you understand these hints? When will you recognize that
    "the problem" is your personal thing? (That's all just rhetorical;
    we know the answer: "Never!")

    Janis


    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bart@3:633/10 to All on Saturday, June 13, 2026 14:38:05
    On 13/06/2026 13:35, Janis Papanagnou wrote:
    On 2026-06-13 12:14, tTh wrote:
    On 6/13/26 12:03, Bart wrote:

    Seriously? You have a language where you can literally do this:

    ˙˙ #include <stdint.h>
    ˙˙ int32_t int32_t;
    ˙˙ int32_t = 0;

    and that is just fine; just "don't do it"! In that case, we might as
    well allow:

    ˙˙ int int;

    Can you understand how crazy the above looks from outside?

    Yes. (And I suppose everyone here understands that!)

    Thank you for at least acknowledging that.

    Languages have various possibilities to define their lexical rules,
    their syntax, and their semantics.

    It's certainly quite common to have _reserved words_ that may only
    be used in certain syntactical contexts. But there's also languages
    that allow context-depending placement of names that happen to be
    also tokens of the language.

    Consider, for example, in shell:˙˙ for for in in do ; do : ; done

    In the case of 'int32_t' this is supposedly a core C type but it is
    quite unknown to the language until you include a particular header.

    But my example highlighted the fact that you can do this:

    Point Point;

    provided the first Point is a user-defined type defined in an outer
    scope. Further:

    Point typedef Point; // new scope starts at that 'typedef'
    {Point Point;}

    Such pieces of code are a result of a programmer's sick brain and
    not the problem of a language.
    Such pieces of code are 100% *enabled* by the language so, yes, you can
    blame the language. These examples are not possible in mine for example,
    due to different scoping rules.

    So someone using my product /has/ to write:

    type newPoint = Point

    'type' has to be on the left, and the alias has to have a different name.

    Quite draconian, I know! A programmer can still do 'crazy' stuff, but
    they have to work harder.

    The attitude here seems to be, if you can write nonsense in any language anyway, then why bother making it harder to do so? Let's have fewer
    rules and make it easier!

    Keith already noted: "Doctor, it hurts when I do this."

    And tTh said:

    ˙˙˙ In our technical jargon, we have the perfect acronym to
    ˙˙˙ describe this kind of programming: GIGO. Look at wikipedia
    ˙˙˙ for an astounding description of that syndrom.

    ˙˙˙ https://en.wikipedia.org/wiki/Garbage_in,_garbage_out

    Bart, do you understand these hints? When will you recognize that
    "the problem" is your personal thing? (That's all just rhetorical;
    we know the answer: "Never!")


    What problem are we talking about?

    I'd merely commented that some of the 'huge improvements' made to C were
    done very crudely. And actually it was Keith who brought up stdint.h types.





    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Scott Lurndal@3:633/10 to All on Saturday, June 13, 2026 14:52:31
    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 13.06.2026 um 01:52 schrieb Lawrence D?Oliveiro:

    On Fri, 12 Jun 2026 06:16:42 +0200, Bonita Montero wrote:

    Yes, the allocation of the stack is very expensive. And the
    context-switch between threads is a magnitudes more expensive than
    switching between two coroutine conexts.

    Why should that be? What extra overhead is there in context-switching
    between preemptive threads, versus non-preemptive ones?

    Because with threading the context-switch happens inside the kernel.

    Some implementations of threading context-switch in the kernel. That's
    not true of all implementations.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Saturday, June 13, 2026 13:46:55
    On 6/12/2026 5:01 PM, Lawrence D?Oliveiro wrote:
    On Thu, 11 Jun 2026 21:11:13 -0700, Chris M. Thomasson wrote:

    FWIW, check this shit out. Coroutines can be emulated even in BASIC.
    This is a recursive stack here. Its all manual... :^)

    [code omitted]


    I see a lot of ?GOSUB 8000? within the subroutine starting at line
    8000, so that?s a lot of recursion, not coroutines. Plus you?ve got
    the explicit RS array stack for assembling the components of the
    curve. Normally you would either have either recursion or an explicit
    stack, since each one subsumes the functions of the other, so there
    shouldn?t be a need for both.

    In other words, I think you?ve got the worst of both worlds? Recursion
    that isn?t enough to solve the problem purely recursively, plus an
    explicit stack that isn?t enough to keep track of the entire stack
    state?

    Its a recursive koch fractal using AppleSoft basic. Run it on an
    emulator. Say, https://www.calormen.com/jsbasic/ ?

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Saturday, June 13, 2026 14:13:55
    On 6/12/2026 1:48 PM, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    [...]
    I was responding to the claims that C has improved significantly.

    You used 'huge improvement', 'massive step forward' and now 'improved
    greatly'.

    I don't see it, sorry.
    [...]

    Yes, let's debate the meanings "huge improvement" and "massive step
    forward", and whether the changes in C are huge, large, or minor.
    Such debates are always interesting, productive, and illuminating.


    C11 is pretty huge for me. Added threads and memory barriers.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Saturday, June 13, 2026 16:46:10
    Bart <bc@freeuk.com> writes:
    On 13/06/2026 13:35, Janis Papanagnou wrote:
    On 2026-06-13 12:14, tTh wrote:
    On 6/13/26 12:03, Bart wrote:
    Seriously? You have a language where you can literally do this:

    ˙˙ #include <stdint.h>
    ˙˙ int32_t int32_t;
    ˙˙ int32_t = 0;

    and that is just fine; just "don't do it"! In that case, we might
    as well allow:

    ˙˙ int int;

    Can you understand how crazy the above looks from outside?
    Yes. (And I suppose everyone here understands that!)

    Thank you for at least acknowledging that.

    You seem think that acknowledgement is important. Upthread, you
    asked a question. I spent substantial time and effort answering
    it. You have not acknowledged that. I don't think you've ever
    acnowledged it when I've answered one of your questions. Why is
    that?

    (I don't expect acknowledgement from you. I enjoyed writing the
    explanation, and I hope that others might benefit from it, or at
    least find it interesting.)

    [...]

    In the case of 'int32_t' this is supposedly a core C type but it is
    quite unknown to the language until you include a particular header.

    Who said it was a "core C type"? What does "core C type" even mean?
    (It's not mentioned in 6.2.3, "Types".)

    Not all implementations necessarily even define int32_t.

    Yes, it's defined in a header. Everyone knows that. And everyone
    knows that you don't like it.

    But my example highlighted the fact that you can do this:

    Point Point;

    provided the first Point is a user-defined type defined in an outer
    scope. Further:

    Point typedef Point; // new scope starts at that 'typedef'
    {Point Point;}

    Yet again, "Doctor, it hurts when I do this."

    No language makes it impossible to write ugly code.

    Perhaps C has some features that make it easier to write ugly code
    in some cases. "Fixing" those features would make the language more complicated and break existing code, including code that isn't ugly
    at all.

    [...]

    The attitude here seems to be, if you can write nonsense in any
    language anyway, then why bother making it harder to do so? Let's have
    fewer rules and make it easier!

    No, that's what the attitude here seems *to you* to be. As usual,
    you've misunderstood what everyone else here thinks.

    [...]

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bart@3:633/10 to All on Sunday, June 14, 2026 01:25:39
    On 14/06/2026 00:46, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    On 13/06/2026 13:35, Janis Papanagnou wrote:
    On 2026-06-13 12:14, tTh wrote:
    On 6/13/26 12:03, Bart wrote:
    Seriously? You have a language where you can literally do this:

    ˙˙ #include <stdint.h>
    ˙˙ int32_t int32_t;
    ˙˙ int32_t = 0;

    and that is just fine; just "don't do it"! In that case, we might
    as well allow:

    ˙˙ int int;

    Can you understand how crazy the above looks from outside?
    Yes. (And I suppose everyone here understands that!)

    Thank you for at least acknowledging that.

    You seem think that acknowledgement is important. Upthread, you
    asked a question. I spent substantial time and effort answering
    it. You have not acknowledged that. I don't think you've ever
    acnowledged it when I've answered one of your questions. Why is
    that?

    You seem touchy about this. Sometimes I write considerable amounts only
    for people to complete ignore the content, or just snip it. It happens.
    I can't remember anyone thanking me for anything.

    Regarding your comments about why compound literals look like they do,
    it sounded like speculation on your part. Not much for me to say about
    it other than putting another POV on some parts.

    It still came across as excuses for something that you clearly think is
    a trivial matter. I consider cleaner, less cluttered code important.


    (I don't expect acknowledgement from you. I enjoyed writing the
    explanation, and I hope that others might benefit from it, or at
    least find it interesting.)

    [...]

    In the case of 'int32_t' this is supposedly a core C type but it is
    quite unknown to the language until you include a particular header.

    Who said it was a "core C type"? What does "core C type" even mean?
    (It's not mentioned in 6.2.3, "Types".)

    It came up in a thread last year where it was suggested that stdint
    types were pretty much of the same rank as 'char short int long' etc.
    I'm not going to trawl through of posts to try and find it.

    Of course I don't agree that they are a core type; they are usually
    typedefs around 'char short' etc.

    But my example highlighted the fact that you can do this:

    Point Point;

    provided the first Point is a user-defined type defined in an outer
    scope. Further:

    Point typedef Point; // new scope starts at that 'typedef'
    {Point Point;}

    Yet again, "Doctor, it hurts when I do this."

    And yet again on my part, why allow it in the first place?

    C uses declarations where the type comes first. Now it is more
    fashionable for the type to come after the identifier being defined.
    Then my example changes from:

    Point [type] Point [var]; // [] annotations added

    to:

    Point [var] : Point [type];

    In the first, the scope for 'Point [var] starts just before that and
    shadows Point [type]. But in the second, it doesn't work: Point [var]
    shadows the other, then has to swap back for one token to allow Point
    [type] to be visible.

    It suggests the concept is flawed if scope relies on a particular
    ordering of type/var.


    The attitude here seems to be, if you can write nonsense in any
    language anyway, then why bother making it harder to do so? Let's have
    fewer rules and make it easier!

    No, that's what the attitude here seems *to you* to be. As usual,
    you've misunderstood what everyone else here thinks.

    Countless posts here that people have made suggested exactly that.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Sunday, June 14, 2026 00:32:40
    On Sat, 13 Jun 2026 13:46:55 -0700, Chris M. Thomasson wrote:

    Its a recursive koch fractal using AppleSoft basic.

    Yes, that was pretty clear. As was the fact that you were able to get
    it working, not *because of* your choice of BASIC to write it in, but
    *in spite of* that.

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Saturday, June 13, 2026 18:26:54
    Bart <bc@freeuk.com> writes:
    On 14/06/2026 00:46, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:
    On 13/06/2026 13:35, Janis Papanagnou wrote:
    On 2026-06-13 12:14, tTh wrote:
    On 6/13/26 12:03, Bart wrote:
    Seriously? You have a language where you can literally do this:

    ˙˙ #include <stdint.h>
    ˙˙ int32_t int32_t;
    ˙˙ int32_t = 0;

    and that is just fine; just "don't do it"! In that case, we might
    as well allow:

    ˙˙ int int;

    Can you understand how crazy the above looks from outside?
    Yes. (And I suppose everyone here understands that!)

    Thank you for at least acknowledging that.
    You seem think that acknowledgement is important. Upthread, you
    asked a question. I spent substantial time and effort answering
    it. You have not acknowledged that. I don't think you've ever
    acnowledged it when I've answered one of your questions. Why is
    that?

    You seem touchy about this. Sometimes I write considerable amounts
    only for people to complete ignore the content, or just snip it. It
    happens. I can't remember anyone thanking me for anything.

    Not the same thing.

    I said "acknowledged", not "thanked". And I wrote what I wrote in
    direct response to a question that you asked.

    Here's what you wrote:

    """
    Regarding compound literals, why is one necessary when assigning to
    'q' here:

    typedef struct {double x, y;} Point;

    Point p = {10, 20};
    Point q;
    q = (Point){30, 40};
    """

    Regarding your comments about why compound literals look like they do,
    it sounded like speculation on your part. Not much for me to say about
    it other than putting another POV on some parts.

    I'd say my answer was *informed* speculation, based on the facts
    about how compound literals are defined and my knowledge of the
    implications of other possible definitions (in particular, that
    a version without the type name probably couldn't be made to work
    without radical and otherwise unnecessary changes to C). If you
    really want to know what the authors of the standard had in mind,
    you can search through the committee's published documents as well
    as I can. I don't believe that's what you want to know.

    Tell me this. Were you really interested in an actual answer to your
    question, or was it just a rhetorical method to complain yet again
    about a feature of C that you don't like? I foolishly assumed that
    you wanted an answer. All the evidence suggests that you didn't.

    Should I assume that any time you ask a question about C, particularly
    about why a feature you dislike is the way it is, that you really don't
    care about the answer?

    It still came across as excuses for something that you clearly think
    is a trivial matter. I consider cleaner, less cluttered code
    important.

    Explanations, not excuses, for a decision for which there were valid
    reasons that you refuse to acknowledge or accept.

    (I don't expect acknowledgement from you. I enjoyed writing the
    explanation, and I hope that others might benefit from it, or at
    least find it interesting.)
    [...]

    In the case of 'int32_t' this is supposedly a core C type but it is
    quite unknown to the language until you include a particular header.
    Who said it was a "core C type"? What does "core C type" even mean?
    (It's not mentioned in 6.2.3, "Types".)

    It came up in a thread last year where it was suggested that stdint
    types were pretty much of the same rank as 'char short int long'
    etc. I'm not going to trawl through of posts to try and find it.

    The word "rank" has a specific meaning; I presume that's not what
    you meant. If that other person did mean "rank" in that sense,
    then it was likely to be a correct statement; if int32_t is a
    typedef for int, then it has the same rank as int.

    And I suppose I have to admit that my question was rhetorical.
    Touch‚.

    int32_t is not a "core C type", for any reasonable definition of that
    vague phrase. If someone said it is, I disagree, but I also am not
    going to trawl through posts to find it.

    Of course I don't agree that they are a core type; they are usually
    typedefs around 'char short' etc.

    But my example highlighted the fact that you can do this:

    Point Point;

    provided the first Point is a user-defined type defined in an outer
    scope. Further:

    Point typedef Point; // new scope starts at that 'typedef'
    {Point Point;}
    Yet again, "Doctor, it hurts when I do this."

    And yet again on my part, why allow it in the first place?

    I could answer that, but I'm nearly certain you would not be
    interested in the answer.

    C uses declarations where the type comes first. Now it is more
    fashionable for the type to come after the identifier being
    defined.

    It is not "fashionable" in any sense relevant to the topic of this
    newsgroup. Yes, different languages have different declaration
    syntax. I'll even acknowledge that the declaration syntax of some
    other languages has real advantages over C's. But C is what we
    try to discuss here.

    [...]

    The attitude here seems to be, if you can write nonsense in any
    language anyway, then why bother making it harder to do so? Let's have
    fewer rules and make it easier!

    No, that's what the attitude here seems *to you* to be. As usual,
    you've misunderstood what everyone else here thinks.

    Countless posts here that people have made suggested exactly that.

    You're wrong. I won't bother to explain why. I might if you could
    convince me that the explanation would be of any interest to you,
    but that seems unlikely.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bart@3:633/10 to All on Sunday, June 14, 2026 12:28:03
    On 14/06/2026 02:26, Keith Thompson wrote:
    Bart <bc@freeuk.com> writes:

    Regarding your comments about why compound literals look like they do,
    it sounded like speculation on your part. Not much for me to say about
    it other than putting another POV on some parts.

    I'd say my answer was *informed* speculation, based on the facts
    about how compound literals are defined and my knowledge of the
    implications of other possible definitions (in particular, that
    a version without the type name probably couldn't be made to work
    without radical and otherwise unnecessary changes to C). If you
    really want to know what the authors of the standard had in mind,
    you can search through the committee's published documents as well
    as I can. I don't believe that's what you want to know.

    Tell me this. Were you really interested in an actual answer to your question, or was it just a rhetorical method to complain yet again
    about a feature of C that you don't like?

    Why is this such a big deal?

    I find it annoying that one has to write 'a = (T){b}' instead of just 'a
    = {b}' (**)

    I asked 'why' that was necessary. You gave a complicated response which
    boils down to it being too hard to do or not practical. Or maybe nobody
    cared enough about readability to try a bit harder.

    I then questioned some of the responses as I think it /would/ have been possible.

    Since I know the decision has been made, this is not going to change C.
    But it is interesting to me from a PL design POV.

    I acknowledged it my making a reply; I could have decided to leave it there.

    (** I have to write 'a := T(b)' in my scripting language, when T is
    record type, for example 'a := point(10, 20)'.

    But there is a good reason: 'a' has a dynamic type so that info has to
    be provided as it cannot be infered from the type of 'a'.

    But C is a statically typed language: it should not be necessary. You
    yourself gave examples where it wasn't, and I gave an example from mine
    for what is /basically the same language/, in type system and capabilities.)









    I foolishly assumed that
    you wanted an answer. All the evidence suggests that you didn't.

    Should I assume that any time you ask a question about C, particularly
    about why a feature you dislike is the way it is, that you really don't
    care about the answer?

    It still came across as excuses for something that you clearly think
    is a trivial matter. I consider cleaner, less cluttered code
    important.

    Explanations, not excuses, for a decision for which there were valid
    reasons that you refuse to acknowledge or accept.

    (I don't expect acknowledgement from you. I enjoyed writing the
    explanation, and I hope that others might benefit from it, or at
    least find it interesting.)
    [...]

    In the case of 'int32_t' this is supposedly a core C type but it is
    quite unknown to the language until you include a particular header.
    Who said it was a "core C type"? What does "core C type" even mean?
    (It's not mentioned in 6.2.3, "Types".)

    It came up in a thread last year where it was suggested that stdint
    types were pretty much of the same rank as 'char short int long'
    etc. I'm not going to trawl through of posts to try and find it.

    The word "rank" has a specific meaning; I presume that's not what
    you meant. If that other person did mean "rank" in that sense,
    then it was likely to be a correct statement; if int32_t is a
    typedef for int, then it has the same rank as int.

    And I suppose I have to admit that my question was rhetorical.
    Touch‚.

    int32_t is not a "core C type", for any reasonable definition of that
    vague phrase. If someone said it is, I disagree, but I also am not
    going to trawl through posts to find it.

    Of course I don't agree that they are a core type; they are usually
    typedefs around 'char short' etc.

    But my example highlighted the fact that you can do this:

    Point Point;

    provided the first Point is a user-defined type defined in an outer
    scope. Further:

    Point typedef Point; // new scope starts at that 'typedef'
    {Point Point;}
    Yet again, "Doctor, it hurts when I do this."

    And yet again on my part, why allow it in the first place?

    I could answer that, but I'm nearly certain you would not be
    interested in the answer.

    C uses declarations where the type comes first. Now it is more
    fashionable for the type to come after the identifier being
    defined.

    It is not "fashionable" in any sense relevant to the topic of this
    newsgroup. Yes, different languages have different declaration
    syntax. I'll even acknowledge that the declaration syntax of some
    other languages has real advantages over C's. But C is what we
    try to discuss here.

    [...]

    The attitude here seems to be, if you can write nonsense in any
    language anyway, then why bother making it harder to do so? Let's have >>>> fewer rules and make it easier!

    No, that's what the attitude here seems *to you* to be. As usual,
    you've misunderstood what everyone else here thinks.

    Countless posts here that people have made suggested exactly that.

    You're wrong. I won't bother to explain why. I might if you could
    convince me that the explanation would be of any interest to you,
    but that seems unlikely.



    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Sunday, June 14, 2026 15:01:37
    Bart <bc@freeuk.com> writes:
    On 14/06/2026 02:26, Keith Thompson wrote:
    [...]
    Tell me this. Were you really interested in an actual answer to your
    question, or was it just a rhetorical method to complain yet again
    about a feature of C that you don't like?

    Why is this such a big deal?

    I might consider answering that if I thought you were actually
    interested in an answer.

    [...]

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Tuesday, June 16, 2026 00:12:43
    On Sat, 13 Jun 2026 05:05:23 +0200, Bonita Montero wrote:

    Am 13.06.2026 um 01:52 schrieb Lawrence D?Oliveiro:

    On Fri, 12 Jun 2026 06:16:42 +0200, Bonita Montero wrote:

    Yes, the allocation of the stack is very expensive. And the
    context-switch between threads is a magnitudes more expensive than
    switching between two coroutine conexts.

    Why should that be? What extra overhead is there in
    context-switching between preemptive threads, versus non-preemptive
    ones?

    Because with threading the context-switch happens inside the kernel.

    Microsoft Windows problems again?

    --- PyGate Linux v1.5.16
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Tuesday, June 16, 2026 12:22:24
    On 6/15/2026 5:12 PM, Lawrence D?Oliveiro wrote:
    On Sat, 13 Jun 2026 05:05:23 +0200, Bonita Montero wrote:

    Am 13.06.2026 um 01:52 schrieb Lawrence D?Oliveiro:

    On Fri, 12 Jun 2026 06:16:42 +0200, Bonita Montero wrote:

    Yes, the allocation of the stack is very expensive. And the
    context-switch between threads is a magnitudes more expensive than
    switching between two coroutine conexts.

    Why should that be? What extra overhead is there in
    context-switching between preemptive threads, versus non-preemptive
    ones?

    Because with threading the context-switch happens inside the kernel.

    Microsoft Windows problems again?

    Microsoft Windows problems? What do you mean? preemptive threads say
    POSIX threads are going to have the same issues. Right?

    --- PyGate Linux v1.5.17
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Tuesday, June 16, 2026 12:23:32
    On 6/13/2026 5:32 PM, Lawrence D?Oliveiro wrote:
    On Sat, 13 Jun 2026 13:46:55 -0700, Chris M. Thomasson wrote:

    Its a recursive koch fractal using AppleSoft basic.

    Yes, that was pretty clear. As was the fact that you were able to get
    it working, not *because of* your choice of BASIC to write it in, but
    *in spite of* that.

    It has current stack space. So, with a little work it should be workable
    for continuations.

    --- PyGate Linux v1.5.17
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Tuesday, June 16, 2026 12:25:12
    On 6/11/2026 9:06 PM, Chris M. Thomasson wrote:
    On 6/11/2026 5:12 PM, Lawrence D?Oliveiro wrote:
    On Thu, 11 Jun 2026 14:18:09 -0700, Chris M. Thomasson wrote:

    On 6/10/2026 9:40 PM, Lawrence D?Oliveiro wrote:

    For cases where the bottleneck is in the I/O or the network
    connection (which is a lot of them), threading is typically
    unnecessary. Instead, the popular approach nowadays is to use
    coroutines.

    Not sure why you say that.

    It does tend to be error-prone.

    Well, shit happens. :^)

    Error prone... Well, C is not the lang that takes the corks off the forks:


    (Dirty Rotten Scoundrels (1988) - Dinner With Ruprecht Scene (6/12) | Movieclips)

    https://youtu.be/SKDX-qJaJ08

    rofl!





    That?s why it is best reserved for CPU-intensive tasks that can
    benefit from running a bunch of cores at once.




    --- PyGate Linux v1.5.17
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Wednesday, June 17, 2026 03:07:28
    On Tue, 16 Jun 2026 12:23:32 -0700, Chris M. Thomasson wrote:

    On 6/13/2026 5:32 PM, Lawrence D?Oliveiro wrote:

    On Sat, 13 Jun 2026 13:46:55 -0700, Chris M. Thomasson wrote:

    Its a recursive koch fractal using AppleSoft basic.

    Yes, that was pretty clear. As was the fact that you were able to
    get it working, not *because of* your choice of BASIC to write it
    in, but *in spite of* that.

    It has current stack space.

    But being BASIC, it only has fixed-length arrays to use as the stack,
    doesn?t it?

    So, with a little work it should be workable for continuations.

    I added continuations to my toy PostScript-revival language. I soon
    discovered that having a dedicated stack area was a bad idea. So what
    happens is call frames are allocated on the heap, and chained together
    in various ways: for transferring control for a return, exit, yield or
    stop. An instance of the Continuation class keeps a copy of the
    CallFrame object that was current when it was created, and simply
    makes that current again when it is invoked.

    --- PyGate Linux v1.5.17
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Wednesday, June 17, 2026 03:09:04
    On Tue, 16 Jun 2026 12:22:24 -0700, Chris M. Thomasson wrote:

    Microsoft Windows problems? What do you mean? preemptive threads say
    POSIX threads are going to have the same issues. Right?

    Well, when talking to a Windows programmer, and they say something you
    know doesn?t sound right, it seems reasonable to conclude that it
    comes from their Windows-specific experience.

    --- PyGate Linux v1.5.17
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris M. Thomasson@3:633/10 to All on Wednesday, June 17, 2026 12:11:31
    On 6/16/2026 12:25 PM, Chris M. Thomasson wrote:
    On 6/11/2026 9:06 PM, Chris M. Thomasson wrote:
    On 6/11/2026 5:12 PM, Lawrence D?Oliveiro wrote:
    On Thu, 11 Jun 2026 14:18:09 -0700, Chris M. Thomasson wrote:

    On 6/10/2026 9:40 PM, Lawrence D?Oliveiro wrote:

    For cases where the bottleneck is in the I/O or the network
    connection (which is a lot of them), threading is typically
    unnecessary. Instead, the popular approach nowadays is to use
    coroutines.

    Not sure why you say that.

    It does tend to be error-prone.

    Well, shit happens. :^)

    Error prone... Well, C is not the lang that takes the corks off the forks:

    Damn typos. C will let Ruprecht stab himself in the eyes. ;^)




    (Dirty Rotten Scoundrels (1988) - Dinner With Ruprecht Scene (6/12) | Movieclips)

    https://youtu.be/SKDX-qJaJ08

    rofl!





    That?s why it is best reserved for CPU-intensive tasks that can
    benefit from running a bunch of cores at once.





    --- PyGate Linux v1.5.17
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)