• Re: Loops (was Re: do { quit; } else { })

    From Michael S@21:1/5 to Janis Papanagnou on Mon Apr 14 15:33:14 2025
    On Mon, 14 Apr 2025 14:18:39 +0200
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    Is it that hard to provide a proper for-loop where you don't have
    to spell out every single detail?

    You mean like in Algol 68 or maybe Simula? (Both are interesting.)


    I mean like pretty much every language that hasn't copied C's
    for-loop syntax. For example Lua:

    for i = a, b # iterate over a..b inclusive
    s1
    s2
    ...
    end

    Obviously there are many and there were many programming languages
    that have other and better loop syntaxes than Fortran or Lua (if
    above code is all that it provides).


    Modern Fortran do construct does not lack in features.
    There are languages that match it, but it's hard to see how one can
    improve on it without impacting one or another usability aspects.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Mon Apr 14 14:18:39 2025
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    Is it that hard to provide a proper for-loop where you don't have to
    spell out every single detail?

    You mean like in Algol 68 or maybe Simula? (Both are interesting.)

    I mean like pretty much every language that hasn't copied C's for-loop syntax. For example Lua:

    for i = a, b # iterate over a..b inclusive
    s1
    s2
    ...
    end

    Obviously there are many and there were many programming languages
    that have other and better loop syntaxes than Fortran or Lua (if
    above code is all that it provides).


    Fortran managed it in the 1950s!

    I obviously don't recall FORTRAN good enough to have memorized any
    "good" feature. But as (mostly?) an anachronism it anyway doesn't
    matter any more (to me).

    Fortran's loops looked like this:

    do 100 i = a, b
    s1
    s2
    ...
    100 continue

    Okay, I see what you want; just two values (from, to).

    This Fortran stuff looks really sick (for my taste)! - The "do 100"
    sounds like iterating 100 times, line numbers, 'continue' keyword,
    and a list a,b meaning iteration over a range. - Can it be worse?
    (Later Fortran versions allow a slightly better syntax, but it's
    basically the same anachronistic crude syntax.)

    In _minimalistic_ languages I'd prefer, for example, a style like
    in Pascal (or in similar languages)

    for i := a to b do
    statement_block;

    It's simple, and a clean formalism.


    The C equivalant is this:

    for (i = a; i <= b; ++i)
    stmt

    Differences:

    * Fortran has an official loop index variable 'i'.

    You are saying that you could not use 'j' ? (This is certainly
    different from my memories.) - Anyway, having dedicated variables
    for integer types is sick in itself, also if used without loop.

    C doesn't; a loop can look like this:

    for (x=0; y=1; z=2)

    I don't need to tell you that in "C" you can use arbitrary increments/decrements, not just 1, and arbitrary conditions,
    and more than one initializer and more increment/decrement
    statements, and also omit unnecessary parts.

    If all you want is a "+1" increment you can do that in the loop
    body where i is used, and initialize it at the declaration point

    int i = a;
    for (; i <= b ; ) f(i++)

    which of course would be written with a 'while'

    int i = a;
    while (i <= b) f(i++)

    The "C" syntax has actually a flexibility that is very valuable.
    (Even though I dislike its syntax, but that is a minor point in
    this context).


    * C needs you to provide the exact comparison op

    * C needs you to write the index 'i' three times (with no compiler check
    that they're all identical!)

    They don't need to be identical, because you can write many more
    types of loops than simple counted loops. - This is actually an
    advantage; it allows a lot more sensible loop code patterns than
    those other primitive loops! - I'm astonished that your code
    pattern repertoire is so limited. (Or that you are arguing again
    just to contribute anything, however stupid that is.)


    * C needs you to specify how to increment the loop index

    Of course; another advantage! (And this is common in many
    programming languages, older and newer ones.)


    * Fortran allows an arbitrary number of statements in the loop body.
    C allows only one; multiple statements require a compound statement.

    Jesus! - At times I see you as a sensible communication partner,
    but in this sub-thread I've no hope. - I'll finish this post and
    stop responding to such stupid posts of yours...

    [...]

    Algol68 also ignores white space, at least within identifiers. That
    would have caused clashes with reserved words, so that 'stropping' had
    to be employed, resulting in ugly and fiddly-to-type source code.

    (Huh? You have issues with keywords in caps? Aren't you used to
    that from typically capitalized CPP entities? - But okay. You
    have your own languages where you can ignore other people and
    implement your personal preferences.)


    Of course, in printed material, reserved words simply used bold type,
    and it looked gorgeous. The reality on a computer was rather different.

    There were various stropping methods used in the past, some
    better some worse. The Genie compiler-interpreter uses all caps
    and it looks great; makes the keywords stand out and makes the
    code structure very clear and perfectly legible! (YMMV.)

    And you have a powerful, yet minimalistic syntax; you "pay"
    only for what you need and can express anything. Examples...

    # infinite loop
    DO s1; s2 OD

    # loops n times (no variable necessary)
    TO n DO s1; s2 OD

    # infinite loop with counted index available
    FOR i DO s1; s2(i) OD

    # loop n times with variable value available
    FOR i TO n DO s1; s2(i) OD

    ... and so on until...

    # full arithmetic loop (start, increment, end)
    FOR i FROM k BY 3 TO m DO s1; s2(i) OD

    # full arithmetic loop with condition
    FOR i FROM k BY 3 TO m WHILE cond(i) DO s1; s2 OD

    # only condition (no arithmetic)
    WHILE cond DO s1; s2 OD

    # only condition (with preparing statements)
    WHILE s1; s2; cond DO s1; s2 OD

    What you can see here are a couple of advantages with
    this sort of loop;

    * one formal construct (not many variants) to express
    all the common loop controls

    * better readability (because of stropping!); an easy
    differentiation of syntax structure and user defined
    entities (variables, conditions, functions, ...)

    * all loop-parts (but DO and OD) optional; no typing
    overhead, clear constructs, sensible defaults for
    omitted parts

    * implicit bracketing (no extra braces nor additional
    keywords necessary) with short keywords DO OD

    * loop variables need no declaration

    * loop variable scope is just the loop

    The specific Genie compiler-interpreter supports also
    a (non-standard) UNTIL part. (Just for completeness.)


    The Simula loop, while not as rich as Algol 68's, has
    also some distinct specifics; just a short example

    FOR z := 2, 3, 5, 7, 11, 13, 17, 19,
    21 STEP 2 UNTIL 99,
    z+1 WHILE p(z) DO ...

    where value lists, counted parts, conditional parts can
    be taken and interspersed as necessary (also multiple
    times) or just be omitted.

    It's also noteworthy that Simula's logic is applicable
    also for floating point variables without the danger
    of accumulated rounding/truncation issues.


    And you think Fortran's loop is a good paragon? *sigh*

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Mon Apr 14 16:22:37 2025
    On 14/04/2025 13:18, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    Fortran's loops looked like this:

    do 100 i = a, b
    s1
    s2
    ...
    100 continue

    Okay, I see what you want; just two values (from, to).

    This Fortran stuff looks really sick (for my taste)! - The "do 100"
    sounds like iterating 100 times, line numbers, 'continue' keyword,
    and a list a,b meaning iteration over a range. - Can it be worse?
    (Later Fortran versions allow a slightly better syntax, but it's
    basically the same anachronistic crude syntax.)

    In _minimalistic_ languages I'd prefer, for example, a style like
    in Pascal (or in similar languages)

    for i := a to b do
    statement_block;

    I'm not saying there's anything wrong with it. The point was that an A
    to B loop existed in the 1950s; C came out in the 1970s!

    * Fortran has an official loop index variable 'i'.

    You are saying that you could not use 'j' ?

    No, it's just 'i' in this example.


    which of course would be written with a 'while'

    int i = a;
    while (i <= b) f(i++)

    That would be a poor use of 'while'. And bizarre, to use 'while' for
    iteration, but 'for' for loops that are best written as while!

    The "C" syntax has actually a flexibility that is very valuable.

    The flexibility is the problem, because you have to specify the loop in
    such excruciating detail. It is easy to make a mistake which results in
    still legal code. And you now have to analyse each loop to see what kind
    of loop it is:

    Is it simple iteration? Does it count up or down? Are the limits
    exclusive or inclusive? Is it something better off as a while-loop? Does
    it do multiple things at the same time?

    Is there a variable that can be considered to be 'the' loop index?
    (Since there can be multiple such variables; even one variable may not necessarily be an 'index', it could be a pointer.)

    Suppose you see 'i <= N' as the condition; is that '<=' intentional, or
    is it a typo for '<'? It's impossible to tell.

    You can also say that a combination of labels, gotos and 'if' is even
    more flexible! But C is supposed to be a HLL.

    (Even though I dislike its syntax, but that is a minor point in
    this context).


    * C needs you to provide the exact comparison op

    * C needs you to write the index 'i' three times (with no compiler check
    that they're all identical!)

    They don't need to be identical, because you can write many more
    types of loops than simple counted loops. - This is actually an
    advantage;

    This is the kind of error I was making all the time (writing the first
    line, copying it, but forgetting to convert all the variables):

    for(i=0; i < M; ++i)
    for(j=0; j < N; ++i)

    Here, it is not an advantage. I once asked David Brown how many of his for-loops were simple iteration; I think he said 98.5%.

    In my case it would be nearer 100%. It's amazing, with the amount of lower-level coding I do, how little I need to use the flexibility of C's
    'for'.

    Anything unusual can generally be achieved with minor workarounds.

    However with linked-list traversal, that's an example that people gave
    of how flexible for-loops can be:

    for (p = head; p; p = p->next)

    I suggested that could have been better done with an extension to
    'while'. I made a proof-of-concept in my language:

    p := head
    while p, p:=p.next do

    This feature I've kept.


    it allows a lot more sensible loop code patterns than>
    those other primitive loops! - I'm astonished that your code
    pattern repertoire is so limited. (Or that you are arguing again
    just to contribute anything, however stupid that is.)

    It sounds like you're being insulting again just to keep your hand in.
    Why is it some people just cannot resist getting personal?


    * C needs you to specify how to increment the loop index

    Of course; another advantage! (And this is common in many
    programming languages, older and newer ones.)

    You need to tell the computer how to count? OK!

    * Fortran allows an arbitrary number of statements in the loop body.
    C allows only one; multiple statements require a compound statement.

    Jesus! - At times I see you as a sensible communication partner,
    but in this sub-thread I've no hope. - I'll finish this post and
    stop responding to such stupid posts of yours...

    I don't understand; what exactly is the problem here that you see as nonsensical?

    In C you have do this:

    for(...)
    stmt1;

    Then you decide to add a new statement, but this doesn't work:

    for(...)
    stmt1;
    stmt2;

    (And has caused lots of errors.) You have to refactor into:

    for(...) {
    stmt1;
    stmt2;
    }

    Then you decide you don't need stmt2 anymore, and may need to refactor
    back. Or maybe you want to temporarily comment out stmt1:

    for(...)
    // stmt1;

    But now you will be repeating whatever statement follows iself. It's a
    dance.

    If I understand you, you think it is idiotic for me to bring up what you clearly perceive as a non-problem?

    Even though it is one that also existed in Algol60 and Pascal, and was
    solved by Algol68, and now is common in many languages that don't use
    braces. (Braces are the equivalent of BEGIN-END.)

    [...]

    Algol68 also ignores white space, at least within identifiers. That
    would have caused clashes with reserved words, so that 'stropping' had
    to be employed, resulting in ugly and fiddly-to-type source code.

    (Huh? You have issues with keywords in caps?

    Yes I have issues with *constantly* switch from lower case all-caps. It
    is tedious, error prone and the result is ugly code.

    That doesn't bother you? Then you have remarkably low tolerance. But
    again, notice that most languages these days do not distinguish reserved
    words like that.

    There were various stropping methods used in the past, some
    better some worse. The Genie compiler-interpreter uses all caps
    and it looks great; makes the keywords stand out and makes the
    code structure very clear and perfectly legible! (YMMV.)

    And you have a powerful, yet minimalistic syntax; you "pay"
    only for what you need and can express anything. Examples...

    # infinite loop
    DO s1; s2 OD

    # loops n times (no variable necessary)
    TO n DO s1; s2 OD

    # infinite loop with counted index available
    FOR i DO s1; s2(i) OD

    # loop n times with variable value available
    FOR i TO n DO s1; s2(i) OD

    ... and so on until...

    # full arithmetic loop (start, increment, end)
    FOR i FROM k BY 3 TO m DO s1; s2(i) OD

    # full arithmetic loop with condition
    FOR i FROM k BY 3 TO m WHILE cond(i) DO s1; s2 OD

    # only condition (no arithmetic)
    WHILE cond DO s1; s2 OD

    # only condition (with preparing statements)
    WHILE s1; s2; cond DO s1; s2 OD

    (Note: Algol68 comments need a trailing # too.)

    I have all those in my syntax, in fact the above would be legal sytax in
    my langage (since it is case-insensitive), apart from minor details:

    * I use := instead of FROM

    * I use TO/BY rather than BY/TO

    * I don't have embedded WHILE, instead I have embedded WHEN, which
    affects only that iteration. (WHILE will stop the loop when false. Note
    that Algol68 did not have 'break'; it has to use 'goto'.)

    Also, DO, TO and WHILE are independent features in my language, but
    that's an internal detail.

    I also have some extras that are not in Algol68, such as being able to
    iterate over values (of a list etc), or an optional ELSE clause.

    However, I'm not sure why we're talking about Algol68: my complaint was
    about why some languages chose to copy C's crude for-loop syntax, but it
    it was considered primitive even in 1972.

    What you can see here are a couple of advantages with
    this sort of loop;

    * one formal construct (not many variants) to express
    all the common loop controls

    As I said, I have the same features, but it is multiple constructs. So
    having 'one construct' is just a gimmick.

    * better readability (because of stropping!); an easy
    differentiation of syntax structure and user defined
    entities (variables, conditions, functions, ...)

    That's rubbish too. I can also write:

    FOR i := a TO b DO

    if I want (but I don't as it's just a pain). It works because it is case-insensitive.


    * all loop-parts (but DO and OD) optional; no typing
    overhead, clear constructs, sensible defaults for
    omitted parts

    I have sensible defaults too! I also don't have annoying rules about semicolons, or problems with empty bodies:

    DO SKIP OD

    I don't need 'SKIP'.

    DO
    s1;
    s2;
    s3
    OD

    Notice s3 is special-cased, as it has no semicolon. This leads to fun
    and games when inserting, deleting, moving statements, or even
    temporarily commenting lines in or out. At least C gets this right! (Mostly)


    The Simula loop, while not as rich as Algol 68's, has
    also some distinct specifics; just a short example

    FOR z := 2, 3, 5, 7, 11, 13, 17, 19,
    21 STEP 2 UNTIL 99,
    z+1 WHILE p(z) DO ...

    What is it demonstrating? Since it seems to be merely this:

    for z in X while p(z) DO

    where X is any expression including such a constructor. I can do some of
    this stuff, but in my next language up. It is higher level than what
    we're discussing, and not even much about loops.

    And you think Fortran's loop is a good paragon? *sigh*

    It seems we could have kept this short.

    I said that Fortran's original DO-loop was more advanced than C's for-loop.

    You are saying that because there exist languages with more
    sophisticated loops, that that somehow excuses C's poor effort?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Keith Thompson on Tue Apr 15 06:14:09 2025
    On 14.04.2025 23:44, Keith Thompson wrote:
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)
    On 14.04.2025 12:16, bart wrote:
    [...]
    Fortran's loops looked like this:

    do 100 i = a, b
    s1
    s2
    ...
    100 continue

    Okay, I see what you want; just two values (from, to).

    This Fortran stuff looks really sick (for my taste)! - The "do 100"
    sounds like iterating 100 times, line numbers, 'continue' keyword,
    and a list a,b meaning iteration over a range. - Can it be worse?
    (Later Fortran versions allow a slightly better syntax, but it's
    basically the same anachronistic crude syntax.)

    To any programmer familiar with that version of Fortran, the 100 doesn't
    look like iterating 100 times. It looks like a label, and it's
    reasonably consistent with other constructs that refer to labels. The
    syntax isn't great, but don't judge an unfamiliar language syntax by one example.

    Not sure what you mean by "unfamiliar"; back these days it was quite
    commonly known in the IT scene. Myself I programmed in Fortran during
    the 1980's; that was enough to identify all its crudeness[*].

    The Fortran language is not different than any other language in that
    respect that you have to learn it, understand it, accept it, and then
    use it. If you're judging any language from a design perspective then
    it's good to overcome arguing just within the language but take into considerations what other languages did and, with a step back, what
    constructs are exposed to the one learning the syntax.

    The "do 100 i = a, b" is from design perspective in principle not
    different to, for example, the crude declaration details of "C". It's
    not something that we would need to complain about given that Fortran
    is very old. But advocating it is far off, especially in the light of
    the back then next generation languages; Algol 60, Pascal, and so on,
    including even that (old, crude) BASIC, which all offer more sensible
    loop syntaxes to their programmers.

    We don't need to judge Fortran by contemporary languages, it suffices
    to compare it with the language generation following Fortran since the
    1960's. (Or just use common sense.)

    Janis

    [*] But gladly not enough to not forget after four decades all the
    really gory details.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to Janis Papanagnou on Tue Apr 15 06:57:30 2025
    On Mon, 14 Apr 2025 14:18:39 +0200, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to All on Tue Apr 15 09:25:40 2025
    On 15.04.2025 06:57, Rosario19 wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    Sure. Or all done with Turing machines. - But why would one want to.

    Maybe a note aside on your comment; I haven't read many specification
    documents of contemporary language lately, but many of those old specs
    often described the semantics of high-level constructs (like loops) by
    an equivalent 'goto' based code pattern.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Tue Apr 15 09:17:24 2025
    On 14.04.2025 17:22, bart wrote:
    On 14/04/2025 13:18, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    [...]

    I'm not saying there's anything wrong with it. The point was that an A
    to B loop existed in the 1950s; C came out in the 1970s!

    [...]
    [...]

    which of course would be written with a 'while'

    int i = a;
    while (i <= b) f(i++)

    That would be a poor use of 'while'.

    Not the least.

    And bizarre, to use 'while' for
    iteration, but 'for' for loops that are best written as while!

    I was merely trying to provide some options to address your dislike.


    The "C" syntax has actually a flexibility that is very valuable.

    The flexibility is the problem, because you have to specify the loop in
    such excruciating detail. It is easy to make a mistake which results in
    still legal code. And you now have to analyse each loop to see what kind
    of loop it is:

    Well, our opinions obviously differ. I just give you two examples
    (and there's many variants of these) of not uncommon 'for' usages...

    for (c=0; bitstr; c++)
    bitstr &= bitstr-1;

    for (r=1; r<=0x80; r<<=1)
    ...

    and someone already posted another iteration type on linked lists

    for (node = list; node; node = node->next)

    The point here is the observation that there are loops that deviate
    from simple counted loops (and that are commonly used) and that they
    all comprise the same principal structure; initialization, condition
    test, change of loop-variables. The "C" loop syntax reflects that in
    its typical low-level syntax form. (I already said that personally I
    don't like "C"'s syntax, but I do like its flexibility.)

    [...]

    Suppose you see 'i <= N' as the condition; is that '<=' intentional, or
    is it a typo for '<'? It's impossible to tell.

    (This is nonsense.)


    You can also say that a combination of labels, gotos and 'if' is even
    more flexible! But C is supposed to be a HLL.

    Actually, "C" is (IMO) not as high-level as some other languages are.
    I always considered it (snippy) as a excellent "assembler". So if I
    judge "C"'s constructs I do so on the abstraction level the designers
    have chosen. (Or at least I try to do that.)

    (It's nonsense to make up an "argument" for 'goto'.)

    [...]

    They don't need to be identical, because you can write many more
    types of loops than simple counted loops. - This is actually an
    advantage;

    This is the kind of error I was making all the time (writing the first
    line, copying it, but forgetting to convert all the variables):

    for(i=0; i < M; ++i)
    for(j=0; j < N; ++i)

    That first of all means that you are obviously a sloppy programmer.

    Especially if you are doing that "all the time" it's something you
    should work on. (And I don't mean, by writing yet another personal
    programming language that suits you better.)

    (There's something I've heard about in the 1990's, "PSP", "Personal
    Software Process"[*], that might help you increase your success rate
    by reducing common errors you make.)

    [*] https://en.wikipedia.org/wiki/Personal_software_process


    Here, it is not an advantage. I once asked David Brown how many of his for-loops were simple iteration; I think he said 98.5%.

    This number, I think, may be close to reality. - I want to remind
    that N. Wirth gave such informal statistics as rationale for Pascal
    only supporting for-loops with increment and decrement values of 1.

    But given the flexibility of "C"'s syntax that statistics certainly
    has changed; with "C" you can formulate sensible 'for' loops that
    were just not possible [within the 'for'-syntax] before. (I gave
    [just a few] example above; there's yet more.) Now that you can
    formulate such loops their number increased as far as I observe.


    In my case it would be nearer 100%. It's amazing, with the amount of lower-level coding I do, how little I need to use the flexibility of C's 'for'.

    I'm not too astonished; programming is also based on many personal
    factors.


    Anything unusual can generally be achieved with minor workarounds.

    However with linked-list traversal, that's an example that people gave
    of how flexible for-loops can be:

    for (p = head; p; p = p->next)

    I suggested that could have been better done with an extension to
    'while'. I made a proof-of-concept in my language:

    p := head
    while p, p:=p.next do

    This feature I've kept.

    Now that is strange. - Before[*] you argued on a 'while' example:

    "That would be a poor use of 'while'. And bizarre, to use
    'while' for iteration, but 'for' for loops that are best
    written as while!"

    Your mindset on that seems to not yet have reached a stable state.

    But back to the topic; why do you think that introducing yet another
    new syntax would be sensible or even more useful than just using an
    already existing (and fitting) one; because you don't like it that
    way?

    [*] I had snipped it in this post because it appeared to me so
    nonsensical, but if I knew that you support that... - Anyway.


    it allows a lot more sensible loop code patterns than>
    those other primitive loops! - I'm astonished that your code
    pattern repertoire is so limited. (Or that you are arguing again
    just to contribute anything, however stupid that is.)

    It sounds like you're being insulting again just to keep your hand in.
    Why is it some people just cannot resist getting personal?

    There's a few properties that you have problems with that lie not
    within the language but are inherent part of your personality. -
    You clearly exposed two of them; above your problem of handling
    your copy/paste programming errors ("PSP") and here that you are
    restricted in your self-imposed cage of not detecting (and also
    not understanding, if told) that there's many more that you don't
    perceive and that it's used to advantage.



    * C needs you to specify how to increment the loop index

    Of course; another advantage! (And this is common in many
    programming languages, older and newer ones.)

    You need to tell the computer how to count? OK!

    Yes. - Either i++ or i+=2 or z*=10 or r<<=4 or ...

    You say OK but you don't see the obvious applications, do you?
    Meanwhile?


    * Fortran allows an arbitrary number of statements in the loop body.
    C allows only one; multiple statements require a compound statement.

    Jesus! - At times I see you as a sensible communication partner,
    but in this sub-thread I've no hope. - I'll finish this post and
    stop responding to such stupid posts of yours...

    I don't understand; what exactly is the problem here [...]

    There's languages (like Algol 68, Eiffel, Unix Shell, etc.)
    where you have "closed" control constructs (if-fi, do-done,
    case-esac) which make it unnecessary to introduce blocks or
    compound statements in their context. In other languages
    (Pascal, Simula, "C", etc.) you don't have that and if you
    want to have multiple statements in a control structure you
    naturally need to syntactically comprise them.

    That doesn't make the crude and limited Fortran 'for' loop
    any better only because it has a "100 continue" or "end do".

    In C you have do this:

    [ snip bart's known problems with compound statement blocks ]

    (I suggest, here as well, to make yourself familiar with the
    above mentioned "PSP" methods if you have difficulties with
    program evolution and compound statements.)


    If I understand you, you think it is idiotic for me to bring up what you clearly perceive as a non-problem?

    (I see you have a problem that only you can fix.)


    Even though it is one that also existed in Algol60 and Pascal, and was
    solved by Algol68, and now is common in many languages that don't use
    braces. (Braces are the equivalent of BEGIN-END.)

    Having "closed" control constructs (i.e. making explicit braces
    unnecessary) is IMO a Very Good Thing; and personally I prefer
    languages that support such syntaxes. "C" is not such a language.

    Having end-tags doesn't make Fortran a good language or its 'do'
    loop a good syntax.


    (Huh? You have issues with keywords in caps?

    Yes I have issues with *constantly* switch from lower case all-caps. It
    is tedious, error prone and the result is ugly code.

    Okay.


    That doesn't bother you? [...]

    I'm no typist, I have no typist's education, but with my decades
    practice in programming I type sufficiently fast and have indeed
    no problem to occasionally put my small finger on the Shift key
    as professional typists do. - No that doesn't bother me.

    (Things that bother me w.r.t. typing are that the braces that are
    typical of "C" and used there in masses are on my non-US keyboard
    quite difficult to reach.)

    But
    again, notice that most languages these days do not distinguish reserved words like that.

    Yes. And I'm fine with that. Especially since I'm using editors
    with syntax highlighting and nowadays don't print source code
    in black and white on paper any more. For plain text posts it's
    still an advantage, though, to have the keywords stand out. And
    despite the highlighting in my editor it also adds to readability
    when writing and reading programs.


    There were various stropping methods used in the past, some
    better some worse. The Genie compiler-interpreter uses all caps
    and it looks great; makes the keywords stand out and makes the
    code structure very clear and perfectly legible! (YMMV.)

    And you have a powerful, yet minimalistic syntax; you "pay"
    only for what you need and can express anything. Examples...

    [ snip Algol 68 examples ]

    (Note: Algol68 comments need a trailing # too.)

    Yes, I know. I added that '#' for posting only. (Despite '#' is
    [pairwise] usable in the Genie context I'm nonetheless using
    the classical and portable CO ... CO in my programs instead.)


    [ snip some bart language specific features ]

    * I don't have embedded WHILE, instead I have embedded WHEN, which
    affects only that iteration. (WHILE will stop the loop when false. Note
    that Algol68 did not have 'break'; it has to use 'goto'.)

    Yes, Algol 68 (as so many languages back these days) has 'goto'
    available, and used with labels (as opposed to line numbers).

    (You don't need 'break' or 'goto' to leave loops, especially if
    the language supports [also as part of a 'for' loop] 'while'.)

    But what are you trying to say here?

    [ snip more bart language specific features ]

    However, I'm not sure why we're talking about Algol68:

    (Oh, right, and obviously also about your language/preferences.)

    my complaint was
    about why some languages chose to copy C's crude for-loop syntax,

    You mixed into the discussion _your_ compound statement issue
    [that Algol 68 addresses]. You said your language addresses some
    of the issues you have with "C"'s syntax, where you did not a
    job as good as Algol 68 did. You could not see, less appreciate
    the flexibility of "C"'s 'for' loop syntax design decision.

    but it it was considered primitive even in 1972.

    The whole "C" language is "primitive" (in some respects) if
    compared to other HLLs.

    [...]

    * all loop-parts (but DO and OD) optional; no typing
    overhead, clear constructs, sensible defaults for
    omitted parts

    I have sensible defaults too! I also don't have annoying rules about semicolons,

    (Yes, I know that you have noticeable problems where others don't
    care much. You repeatedly told and reminded us about that. Okay.)

    or problems with empty bodies:

    DO SKIP OD

    If there'd be an 'empty statement' possible to have in Algol 68
    (so that I could omit the 'SKIP' in your example) I'd likely have
    nonetheless added a comment to indicate the deliberate absence of
    a statement. (I use such defensive programming patterns with comments
    also in other languages.) YMMV, but I think it's useful if people
    work together in projects, but also if one is programming just for
    own fun.

    Where you think a terse DO OD is best others might prefer to see
    it documented DO # nothing to do # OD and are delighted if that
    "comment" is even standardized by a clear 'NOP' as in DO SKIP OD .

    [...]


    The Simula loop, while not as rich as Algol 68's, has
    also some distinct specifics; just a short example

    FOR z := 2, 3, 5, 7, 11, 13, 17, 19,
    21 STEP 2 UNTIL 99,
    z+1 WHILE p(z) DO ...

    What is it demonstrating?

    That there are a couple _different_ ways that language designers
    can address loop semantics and supported loop features. All the
    three languages have differing approaches, and all with sensible
    rationales.

    Since it seems to be merely this:

    for z in X while p(z) DO

    No. As opposed to Algol 68 the Simula 'while' condition is bound
    [in the example above] to the "z+1" part of the 'for' expression.

    [...]

    And you think Fortran's loop is a good paragon? *sigh*

    It seems we could have kept this short.

    I said that Fortran's original DO-loop was more advanced than C's for-loop.

    You are saying that because there exist languages with more
    sophisticated loops, that that somehow excuses C's poor effort?

    No.

    I was saying that there are different approaches in different
    languages, and that there are good reasons why these languages
    (Algol 68, Simula, Pascal, "C") have defined it in their way;
    you can do useful things in very flexible (and clear) ways.
    (And that Fortran is IMO not amongst those languages. - YMMV.)

    (I also hinted about some other things, your issues and "your
    language", how you "solved" those "issues", that are not worth
    expanding on.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to All on Tue Apr 15 11:15:06 2025
    On 15/04/2025 05:57, Rosario19 wrote:
    On Mon, 14 Apr 2025 14:18:39 +0200, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    For this specific example (ignore 'let' for C), please explain why it is
    better than, say:

    FOR(i,1,36) {

    This is 99% of my for-loops. Is it the same reasoning why I have to
    write 'break' in 99% of my switch-blocks?

    There's something about this group which celebrates these annoying
    language characteristics which are only useful or meaningful in a tiny
    minority of cases: see how wonderful it is for 1% of the time?

    That must surely justify them being both a PITA and dangerously error
    prone in the vast majority of cases!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Tue Apr 15 11:30:24 2025
    On 15/04/2025 08:17, Janis Papanagnou wrote:
    On 14.04.2025 17:22, bart wrote:
    On 14/04/2025 13:18, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    [...]

    I'm not saying there's anything wrong with it. The point was that an A
    to B loop existed in the 1950s; C came out in the 1970s!

    [...]
    [...]

    which of course would be written with a 'while'

    int i = a;
    while (i <= b) f(i++)

    That would be a poor use of 'while'.

    Not the least.

    And bizarre, to use 'while' for
    iteration, but 'for' for loops that are best written as while!

    I was merely trying to provide some options to address your dislike.


    The "C" syntax has actually a flexibility that is very valuable.

    The flexibility is the problem, because you have to specify the loop in
    such excruciating detail. It is easy to make a mistake which results in
    still legal code. And you now have to analyse each loop to see what kind
    of loop it is:

    Well, our opinions obviously differ. I just give you two examples
    (and there's many variants of these) of not uncommon 'for' usages...

    for (c=0; bitstr; c++)
    bitstr &= bitstr-1;

    I can't grok that.

    for (r=1; r<=0x80; r<<=1)
    ...


    and someone already posted another iteration type on linked lists

    for (node = list; node; node = node->next)

    These two I get, and I can tell you that they're all WHILE loops. To
    make make them tidier, I'd have fewer complaints about them if they
    instead looked like this:

    while (node = list; node; node = node->next)

    So, you can optionally add extra elements to a while (x).

    It would be necessary to either define whether while(x; y) means while
    (; x; y) or while (x; y), or to always require either zero or two
    semicolons inside (...).

    That could have kept 'for' for how it works in other languages (the ones
    that haven't just blindly copied C's version!).


    The point here is the observation that there are loops that deviate
    from simple counted loops (and that are commonly used) and that they
    all comprise the same principal structure; initialization, condition
    test, change of loop-variables. The "C" loop syntax reflects that in
    its typical low-level syntax form. (I already said that personally I
    don't like "C"'s syntax, but I do like its flexibility.)

    Let me ask you this: what exactly is the point of the 'while' statement
    in C? Since it can always be trivially be written as:

    for (;cond;)

    It seems to that most use cases (initialise, check exit condition,
    change something that affects the letter), would suit 'for' better.

    But since 'for' then becomes overloaded, there ought to be a dedicated
    feature for simple iteration. So it seems the solution is as a I
    suggested above.

    [...]

    Suppose you see 'i <= N' as the condition; is that '<=' intentional, or
    is it a typo for '<'? It's impossible to tell.

    (This is nonsense.)

    You can't just say that without explanation. WHY it it nonsense? Take this:

    for (i=0 i<=N; ++i)

    Most such loops iterate over 0..N-1 inclusive, so would need "<". So, in
    your opinion, is that <= a typo, or is the intention to iterate over
    0..N inclusive (so N+1 iterations)?


    (May reply to rest separately.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Tue Apr 15 15:25:50 2025
    On Tue, 15 Apr 2025 11:15:06 +0100
    bart <bc@freeuk.com> wrote:

    On 15/04/2025 05:57, Rosario19 wrote:
    On Mon, 14 Apr 2025 14:18:39 +0200, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip
    this post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    For this specific example (ignore 'let' for C), please explain why it
    is better than, say:

    FOR(i,1,36) {

    This is 99% of my for-loops. Is it the same reasoning why I have to
    write 'break' in 99% of my switch-blocks?

    There's something about this group which celebrates these annoying
    language characteristics which are only useful or meaningful in a
    tiny minority of cases: see how wonderful it is for 1% of the time?

    That must surely justify them being both a PITA and dangerously error
    prone in the vast majority of cases!

    I regularly use two languages with "proper loops" - Matlab/Octave and
    VHDL (Ada-like syntax). When writing loops in these languages, I don't
    feel any extra convenience over C. Nor do you suffer from reduced
    flexibility relatively to C, except very rarely.
    In other words, I don't care.

    And it's not because I can become accustomed to anything. E.g. I am
    using tcl for a long time. I never stopped hating most of its syntax,
    including for loops.

    I probably will care (i.e. dislike) language (or C macro) with the
    syntax shown in your last example, but less intensely than tcl.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Tue Apr 15 15:34:19 2025
    On Tue, 15 Apr 2025 11:30:24 +0100
    bart <bc@freeuk.com> wrote:


    Let me ask you this: what exactly is the point of the 'while'
    statement in C? Since it can always be trivially be written as:

    for (;cond;)

    It seems to that most use cases (initialise, check exit condition,
    change something that affects the letter), would suit 'for' better.

    But since 'for' then becomes overloaded, there ought to be a
    dedicated feature for simple iteration. So it seems the solution is
    as a I suggested above.


    I suspect that 'while' loop is here in C because Dennis Ritchie wanted
    'do .. while() ' and thought that if the keyword is here anyway than
    why not reuse it?
    In the hindsight, probably a mistake.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Michael S on Tue Apr 15 13:51:59 2025
    On 15/04/2025 13:34, Michael S wrote:

    <snip>

    I suspect that 'while' loop is here in C because Dennis Ritchie wanted
    'do .. while() ' and thought that if the keyword is here anyway than
    why not reuse it?
    In the hindsight, probably a mistake.

    In hindsight:

    $ find . -name \*.c | xargs cat | wc -l
    126343
    $ find . -name \*.c | xargs grep -w while | wc -l
    556
    $ find . -name \*.c | xargs grep -w for | wc -l
    1258


    So although I use for() about twice as much as I use while(), I
    still find while a better option one time in three. That's useful
    enough to make it worth keeping in the toolbox.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Michael S on Tue Apr 15 13:55:43 2025
    On 15/04/2025 13:25, Michael S wrote:
    On Tue, 15 Apr 2025 11:15:06 +0100
    bart <bc@freeuk.com> wrote:

    On 15/04/2025 05:57, Rosario19 wrote:
    On Mon, 14 Apr 2025 14:18:39 +0200, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip
    this post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    For this specific example (ignore 'let' for C), please explain why it
    is better than, say:

    FOR(i,1,36) {

    This is 99% of my for-loops. Is it the same reasoning why I have to
    write 'break' in 99% of my switch-blocks?

    There's something about this group which celebrates these annoying
    language characteristics which are only useful or meaningful in a
    tiny minority of cases: see how wonderful it is for 1% of the time?

    That must surely justify them being both a PITA and dangerously error
    prone in the vast majority of cases!

    I regularly use two languages with "proper loops" - Matlab/Octave and
    VHDL (Ada-like syntax). When writing loops in these languages, I don't
    feel any extra convenience over C.

    I'm not familiar with those, but the first Ada loop example I googled
    for was this:

    for Variable in 0 .. 9 loop

    In C that exact example would be:

    for (Variable = 0; Variable < 10; ++Variable) {

    or maybe:

    for (Variable = 0; Variable <= 9; Variable = Variable + 1) {

    So, in the Ada:

    * Not having to write the variable 3 times (with C not always being
    able to detect if they didn't match)

    * Not having to either offset the upper limit, or juggle between <
    and <=

    * Not having to explicitly provide the code to increment the variable

    doesn't have ANY extra convenience?

    (You can have a 100MB compiler and you still have to tell it how to
    increment a loop index! That is plain crazy.)

    And it's not because I can become accustomed to anything. E.g. I am
    using tcl for a long time. I never stopped hating most of its syntax, including for loops.

    TCL's for loop appears to be inspired by C's:

    for {set Variable 0} {$Variable < 10} {incr Variable} {

    It's extraordinary how difficult a task it appears to be with some
    languages to iterate a variable over a range!

    I acknowledge that with the popularity of zero-based languages, which
    means usually iterating over 0..N-1 inclusive rather than 1..N, there is
    some confusing about denoting the upper limit.

    So I invented a new postfix operator which turns an inclusive upper
    limit into an exclusive one. It looks like "-1", and works like this:

    FOR Variable in 0..N-1

    Most C code I write manually is small sequences mainly to do with
    compiler testing and benchmarks. 'for'-loops and especially 'printf'
    feature heavily.

    Those are two features with an unnecessarily elaborate syntax where you
    have to dot all the i's and cross all the t's, even for temporary code
    that is only needed for a few minutes.

    That is incredibly annoying, especially as I am a terrible typist.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Tue Apr 15 13:33:21 2025
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    * Not having to write the variable 3 times (with C not always being
    able to detect if they didn't match)

    This is indeed a source of errors in C nested loops. Say we have
    these macros:

    FOR (i, 0, N-1)
    FOR (j, 0, i)
    ...

    we are less likely to make some copy paste error like

    for (i = 0; i < N; i++)
    for (j = 0; j < i; i++)
    ...

    Int he past, I've run into bugs in nested loops, along these lines.

    In loop-heavy code, making a macro like the FOR above might not
    be a bad idea.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Tue Apr 15 13:19:52 2025
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    On 15/04/2025 08:17, Janis Papanagnou wrote:
    and someone already posted another iteration type on linked lists

    for (node = list; node; node = node->next)

    These two I get, and I can tell you that they're all WHILE loops. To
    make make them tidier, I'd have fewer complaints about them if they
    instead looked like this:

    while (node = list; node; node = node->next)

    That's mostly bike shedding. It could also have been called:

    do (node = list; node; node = node->next)

    loop (node = list; node; node = node->next)

    Lisp called this kind of general variable stepping loop "do"

    (do ((var1 init1 step1)
    (var2 init1 step2)
    ...)
    (until-this-is-true also-this ... yield-this-result)
    do-this
    and-this
    ...)

    Naming things can be hard. The reason that the loop is called for
    is that most instance of for have a focus on the specific variable
    that is initialized, and the guard condition has to do with it
    hitting some specific terminating value.

    So, you can optionally add extra elements to a while (x).

    It would be necessary to either define whether while(x; y) means while
    (; x; y) or while (x; y), or to always require either zero or two
    semicolons inside (...).

    That could have kept 'for' for how it works in other languages (the ones
    that haven't just blindly copied C's version!).

    Common Lisp uses "for" to indicate several kinds of variable
    stepping clauses inside the loop syntax, some of which are:

    [4]> (loop for x in '(a b c)
    for y = 1 then (1+ y)
    for z = (* y 10)
    with w = (* y 10)
    collect (list x y z w))
    ((A 1 10 10) (B 2 20 10) (C 3 30 10))

    When loop is used to simulate the classic Lisp do loop,
    it's done with the "for var = init then step" clauses.

    There is a "for var from N to M" clause, as well as "for var below N"
    which goes from 0 to N-1.

    Why the C for loop is called "for" is that it is oriented toward
    variable stepping. The while part of it is just the termination test.

    for (node = list, count = 0;
    node;
    node = node->next, count++)
    ...

    While loops occur that are not focused on stepping specific variables:

    while (!(*status_port & CTS)) { }

    while (queue_empty(q))
    cond_wait(&condvar, &mutex);

    Let me ask you this: what exactly is the point of the 'while' statement
    in C?

    Since it can always be trivially be written as:

    for (;cond;)

    That is simply untidy looking.

    If C had a preprocessor from the beginning, while could have ben defined as:

    #define while(cond) for(;cond;)

    There are still some reasons not to do that, and preprocessing
    came later.

    It seems to that most use cases (initialise, check exit condition,
    change something that affects the letter), would suit 'for' better.

    The new for can declare a variable. This is important in macros
    because the loop header encloses the declaration, such that
    it cannot accidentally tear away as a fragment of another
    statement:

    This macro:

    #define step(type, var, from, to) for(type var = from; var <= to; var ++)

    cannot be defined using while without issues.

    #define step(type, var, from, to) type var = from; while (var <= to; var ++)

    Yes; we can make a macro

    #define whl(cond) for (;cond;)


    But since 'for' then becomes overloaded, there ought to be a dedicated feature for simple iteration.

    Once the macro preprocessor was introduced, programmers met their
    need for dedicated, simplified iteration constructs that way, albeit imperfectly.

    // step n for each node in list

    list_for (n, list) { .... }

    #define list_for(n, list) for (node n = list; n; n = n->next)

    A lot of these kinds of macros have issues of hygiene; we wouldn't
    want them in a standard header file. They serve well the specific
    codebase they are in, and that's all that can be said for them.

    Suppose you see 'i <= N' as the condition; is that '<=' intentional, or
    is it a typo for '<'? It's impossible to tell.

    (This is nonsense.)

    You can't just say that without explanation. WHY it it nonsense? Take this:

    for (i=0 i<=N; ++i)

    It isn't nonsense. Guard conditions in for loops have historically been a source of off-by-one errors in C programming, which bears acknowledging.

    Most such loops iterate over 0..N-1 inclusive, so would need "<". So, in
    your opinion, is that <= a typo, or is the intention to iterate over
    0..N inclusive (so N+1 iterations)?

    Indeed in a "for i from 0 to n + 1" type construct, it is
    vanishingly unlikely that n + 1 is a typo.

    It may be wrong, but as a finger slip-up that the eyes didn't catch.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Tue Apr 15 14:13:57 2025
    bart <bc@freeuk.com> writes:
    On 15/04/2025 05:57, Rosario19 wrote:
    On Mon, 14 Apr 2025 14:18:39 +0200, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    For this specific example (ignore 'let' for C), please explain why it is >better than, say:

    FOR(i,1,36) {

    Because it can't do this:

    for(tp = root; tp != NULL; tp = tp->next)


    This is 99% of my for-loops.

    Who cares what your for-loops are like?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Tue Apr 15 15:30:51 2025
    On 15/04/2025 14:33, Kaz Kylheku wrote:
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    * Not having to write the variable 3 times (with C not always being
    able to detect if they didn't match)

    This is indeed a source of errors in C nested loops.

    According to Janis Papanagnou, it is 100% the programmer's fault. There
    is nothing wrong with the language!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Tue Apr 15 15:28:15 2025
    On 15/04/2025 08:17, Janis Papanagnou wrote:
    On 14.04.2025 17:22, bart wrote:

    (It's nonsense to make up an "argument" for 'goto'.)

    The fastest bytecode interpreters in C, at present rely on using
    'computed goto' (although along with label pointers, an extension).

    There are other uses too: C is popular as an intermediate language, and
    to that end, 'goto' is essential to express constructs the original
    language may have, but don't exist in C.

    There are other applications, but I doubt that will cut any ice.
    Probably you personally haven't used 'goto' since 1986, and think no one
    else needs to use it either.

    This is the kind of error I was making all the time (writing the first
    line, copying it, but forgetting to convert all the variables):

    for(i=0; i < M; ++i)
    for(j=0; j < N; ++i)

    That first of all means that you are obviously a sloppy programmer.

    And that's the kind of remark that shows you haven't a clue about
    ergonomic language design. Why deliberately design a feature with so
    many extra, undetectable, error opportunities?

    Oh, I know: why don't we just put all the blame on the programmer! They
    will just have to be extra careful instead on concentrating on more
    relevant matters.

    A good thing that approach is not used on safety matters in real life.


    (There's something I've heard about in the 1990's, "PSP", "Personal
    Software Process"[*], that might help you increase your success rate
    by reducing common errors you make.)

    [*] https://en.wikipedia.org/wiki/Personal_software_process

    That's brilliant, thanks. So when I'm finding it incredibly error-prone
    to write my applications in 100% assembly, it's nothing at all to do
    with the poor choice of language, I'm just incredibly sloppy, and that
    web-site will help me!


    Here, it is not an advantage. I once asked David Brown how many of his
    for-loops were simple iteration; I think he said 98.5%.

    This number, I think, may be close to reality. - I want to remind
    that N. Wirth gave such informal statistics as rationale for Pascal
    only supporting for-loops with increment and decrement values of 1.

    I agree with Wirth. Anything unusual can be trivially expressed with
    WHILE. Most languages support WHILE, and so can express anything that
    C's FOR loop can.

    The result is that FOR is a simple, streamlined iteration feature,
    instead of a free-for-all which can require readers double-guessing the programmer's intention.

    Now that is strange. - Before[*] you argued on a 'while' example:

    "That would be a poor use of 'while'. And bizarre, to use
    'while' for iteration, but 'for' for loops that are best
    written as while!"

    Do you understand WHY it was a poor choice? Clearly not. It was poor
    choice because you used WHILE to implement a simple iteration of 'i'
    over 'a' to b'. That is *exactly* what FOR should be used for.

    There two main kinds of iterations, putting aside endless loops, and repeat-N-times with no index:

    (1) Where the number of iterations is known in advance, and the
    iteration is over a numerical sequence or a set of values

    (2) Where the number of iterations is either not known in advance, or
    the termination depends on some condition.

    Here's my poser: which one of these is typically done by FOR in most
    languages, and which is done by WHILE?

    I suspect you have got these mixed up. You showed WHILE being used for
    (1), and you heavily promote FOR to be used for (2).

    Or maybe this everything backwards thinking is just typical of C!

    There's a few properties that you have problems with that lie not
    within the language but are inherent part of your personality. -
    You clearly exposed two of them; above your problem of handling
    your copy/paste programming errors ("PSP")

    So, in your opinion, that issue I had was 100% my fault, and 0% due to
    poor language design?

    To reiterate that C example:

    for(i=0; i<M; ++i)

    I had to duplicate this line and change 4 identifiers within it. In my
    syntax, I would duplicate this line:

    for i to M do

    and change only 2 identifiers. In C there is twice as much scope for the
    error, and there is more infrastructure for it to hide behind, but it
    still doesn't matter?

    Suppose the loop indices are not needed inside the bodies; in my
    language I would just write:

    to M do
    to N do

    Here I wouldn't copy and paste, it's easier to just type those 3 tokens!
    So there is no opportunity for error.

    Do you still say that ergonomic language design plays no part in this AT
    ALL, it is always 100% Bart's fault?


    * C needs you to specify how to increment the loop index

    Of course; another advantage! (And this is common in many
    programming languages, older and newer ones.)

    You need to tell the computer how to count? OK!

    Yes. - Either i++ or i+=2 or z*=10 or r<<=4 or ...

    Even for 99.9% of loops where you increment by one? Yikes!


    You say OK but you don't see the obvious applications, do you?

    It's very simple:

    for i := a to b do # automatically increments by 1 ...
    for i := a to b by c do # ... unless told otherwise

    The default should be to increment by 1. Do you have a problem with that concept? In Ada it's apparently:

    for i in a .. b loop

    It seems to have figured it out! Even Fortran managed it.

    do 100 i = a, b # increment by 1
    do 100 i = a, b, c # increment by c

    This is a truely fascinating place, where black is white and every
    crappy misfeature is an essential must-have!

    That doesn't make the crude and limited Fortran 'for' loop
    any better only because it has a "100 continue" or "end do".

    It is yet another advantage that C doesn't have, and which other
    languages have had to introduce.

    In C, braces, /and the ability to not use them for one statement/ are
    another poor feature which can lead to often undetectable errors.

    Just look at the vast number of placement syles that exist. It's all a
    huge headache that those languages with automatically closed blocks
    don't have.

    Funnily enough, C's preprocessor is one of those languages:

    #if
    ....
    #endif

    As I said above, this is topsy-turvy: the grown-up syntax is relegated
    to the preprocessor; the real language has the crappy syntax!

    Having end-tags doesn't make Fortran a good language or its 'do'
    loop a good syntax.

    Why? It works and it's simple. You need 4 things to denote a loop header
    with an index variable:

    (1) The name of the variable
    (2) The start value
    (3) The end value
    (4) Some keyword to tell the compiler this is a loop statement

    Plus whatever supplementary syntax the language stipulates. In modern
    Fortran that appears to be:

    (5) '=' after the index
    (6) ',' between the limits.

    Total 6 elements (do i=a,b) . In mine, (2) is optional when it is 1, so
    it can be as little as 5 elements (for i to b do), otherwise 7.

    C however needs 13 elements in all! Short and snappy.

    (Note: Algol68 comments need a trailing # too.)

    Yes, I know. I added that '#' for posting only. (Despite '#' is
    [pairwise] usable in the Genie context I'm nonetheless using
    the classical and portable CO ... CO in my programs instead.)

    (Both are poor design choices. Leave off one # or CO, and everthing gets
    out of step. And it means you can't comment out code that contains
    comments. See it's not just C I can criticise.)

    (Oh, right, and obviously also about your language/preferences.)

    You tried to assert some superiority by describing Algol68 features, but
    forgot that my language was originally based on Algol68 syntax.
    Obviously tweaked to get bad parts out.

    The whole "C" language is "primitive" (in some respects) if
    compared to other HLLs.

    Yes. (Why do I find it suprising to see you admit that?)

    Where you think a terse DO OD is best others might prefer to see
    it documented DO # nothing to do # OD and are delighted if that
    "comment" is even standardized by a clear 'NOP' as in DO SKIP OD .

    Huh? Empty {} blocks occur in C too; they don't need a comment. Maybe
    the contents are yet to be written, or are commented out.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Tue Apr 15 15:41:37 2025
    On 15/04/2025 15:13, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 05:57, Rosario19 wrote:
    On Mon, 14 Apr 2025 14:18:39 +0200, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    For this specific example (ignore 'let' for C), please explain why it is
    better than, say:

    FOR(i,1,36) {

    Because it can't do this:

    for(tp = root; tp != NULL; tp = tp->next)

    <Face-palm>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Tue Apr 15 20:14:43 2025
    On Tue, 15 Apr 2025 17:42:24 +0100
    bart <bc@freeuk.com> wrote:


    Suppose you have two ways A and B to implement a feature in a
    language.

    You find that those using A tend to make twice as many mistakes in
    that feature, and have more undetectable bugs, as those who use B.

    Your job is to choose which of A and B to keep.

    Would your decision completely ignore such findings?


    I would, if twice as many mistakes amount to very small number. The
    same for 100 time as many.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Tue Apr 15 18:22:27 2025
    On 15.04.2025 16:30, bart wrote:
    On 15/04/2025 14:33, Kaz Kylheku wrote:
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    * Not having to write the variable 3 times (with C not always being
    able to detect if they didn't match)

    This is indeed a source of errors in C nested loops.

    According to Janis Papanagnou, it is 100% the programmer's fault. There
    is nothing wrong with the language!

    No, there is nothing wrong with the language if you make such errors.

    The programmer selects (or constructs) the algorithm, the language has
    clear semantics for such simple loop constructs without any irregular
    or hidden semantics, and the programmer's task is to know the elements
    of the language and transfer the algorithm to a correct coding. - It's self-delusion if you try to blame the language for the mistakes you do.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Tue Apr 15 17:42:24 2025
    On 15/04/2025 17:22, Janis Papanagnou wrote:
    On 15.04.2025 16:30, bart wrote:
    On 15/04/2025 14:33, Kaz Kylheku wrote:
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    * Not having to write the variable 3 times (with C not always being >>>> able to detect if they didn't match)

    This is indeed a source of errors in C nested loops.

    According to Janis Papanagnou, it is 100% the programmer's fault. There
    is nothing wrong with the language!

    No, there is nothing wrong with the language if you make such errors.

    The programmer selects (or constructs) the algorithm, the language has
    clear semantics for such simple loop constructs without any irregular
    or hidden semantics, and the programmer's task is to know the elements
    of the language and transfer the algorithm to a correct coding. - It's self-delusion if you try to blame the language for the mistakes you do.

    Suppose you have two ways A and B to implement a feature in a language.

    You find that those using A tend to make twice as many mistakes in that feature, and have more undetectable bugs, as those who use B.

    Your job is to choose which of A and B to keep.

    Would your decision completely ignore such findings?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Tue Apr 15 18:17:02 2025
    On 15/04/2025 14:19, Kaz Kylheku wrote:
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    On 15/04/2025 08:17, Janis Papanagnou wrote:
    and someone already posted another iteration type on linked lists

    for (node = list; node; node = node->next)

    These two I get, and I can tell you that they're all WHILE loops. To
    make make them tidier, I'd have fewer complaints about them if they
    instead looked like this:

    while (node = list; node; node = node->next)

    That's mostly bike shedding. It could also have been called:

    do (node = list; node; node = node->next)

    loop (node = list; node; node = node->next)

    That's sort of the point. It is not 'for' as is it generally understood.
    It's more of a souped-up while.

    Thats's fine. But it means a real 'for' loop doesn't exist in C; you
    have to emulate it using that 3-way construct, which is naff, and also
    error prone.

    Lisp called this kind of general variable stepping loop "do"

    (do ((var1 init1 step1)
    (var2 init1 step2)
    ...)
    (until-this-is-true also-this ... yield-this-result)
    do-this
    and-this
    ...)

    Naming things can be hard. The reason that the loop is called for
    is that most instance of for have a focus on the specific variable
    that is initialized, and the guard condition has to do with it
    hitting some specific terminating value.

    In what I recognise as 'for' loops, any variable is specified only once
    in the header. Any initialisation and increment is handled automatically.

    The same applies if it loops over a set of values; that might mean
    managing some implicit index. But hey, this is a HLL, and it's the
    compiler's job to that.

    So, you can optionally add extra elements to a while (x).

    It would be necessary to either define whether while(x; y) means while
    (; x; y) or while (x; y), or to always require either zero or two
    semicolons inside (...).

    That could have kept 'for' for how it works in other languages (the ones
    that haven't just blindly copied C's version!).

    Common Lisp uses "for" to indicate several kinds of variable
    stepping clauses inside the loop syntax, some of which are:

    [4]> (loop for x in '(a b c)
    for y = 1 then (1+ y)
    for z = (* y 10)
    with w = (* y 10)
    collect (list x y z w))
    ((A 1 10 10) (B 2 20 10) (C 3 30 10))


    I've looked in the past at CLisp and its loops. My view is that the
    number of possibilities it provides is over the job. It's like somebody
    was tasked with thinking up as many as possible, and making them all
    available.

    I don't know what your example does. Are these nested loops? Parallel ones?

    My own reduce to this:

    for [i,]x in A [when cond] do # i exposes internal index

    and the older:

    for i [:= A] to/downto B [by C] [when cond] do

    Languages like CPython go to town a bit more, and do deconstructing etc. However the only thing I've copied from that is an optional 'else' part.

    Unusual loops are rare and the requirements diverse enough that I can't
    see the point of trying to provide dedicated features beyond the basics.

    For custom loops, people can start off with:

    do
    .....
    end

    then add what they like out of ordinary features.


    When loop is used to simulate the classic Lisp do loop,
    it's done with the "for var = init then step" clauses.

    There is a "for var from N to M" clause, as well as "for var below N"
    which goes from 0 to N-1.

    That's a poor way to do it. I suggested elsewhere using only inclusive
    ranges, and using '-1' as a postfix 'operator' to treat it as exclusive.

    (Inclusive ranges are more natural:

    Monday .. Friday
    'A' .. 'Z'
    Iterate over the elements in X

    People don't expect that first to stop at Thursday, or to only go up to
    'Y', or to iterate over all elements except the last!)

    Since it can always be trivially be written as:

    for (;cond;)

    That is simply untidy looking.

    But this:

    for (index = A ; index <= B; index += 1)

    is fine!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Tue Apr 15 19:07:19 2025
    bart <bc@freeuk.com> writes:
    On 15/04/2025 14:19, Kaz Kylheku wrote:

    Thats's fine. But it means a real 'for' loop doesn't exist in C; you
    have to emulate it using that 3-way construct, which is naff, and also
    error prone.

    Real for loops _are_ a three-way construct.

    135 FOR I=1 TO 10 STEP 2 [BASIC]

    for(i = 1; i < 11; i += 2) [C/C++]

    do 1 = 1, 10, 2 [FORTRAN]

    FOR i OVER i.RANGE DESCENDING
    DO
    countdown(i)
    DONE; [SPRITE]



    SPRITE also had:

    UNTIL done, notfound
    DO
    ...
    IF token = "this"
    THEN LOOP_EXIT done
    FI;
    ...
    IF i = upb(table)
    THEN LOOP_EXIT notfound
    FI;
    ...
    OD
    CASE
    IS done: write("i=", i);
    OR notfound write("not found", upb(table));

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Tue Apr 15 19:55:50 2025
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    On 15/04/2025 14:19, Kaz Kylheku wrote:
    Common Lisp uses "for" to indicate several kinds of variable
    stepping clauses inside the loop syntax, some of which are:

    [4]> (loop for x in '(a b c)
    for y = 1 then (1+ y)
    for z = (* y 10)
    with w = (* y 10)
    collect (list x y z w))
    ((A 1 10 10) (B 2 20 10) (C 3 30 10))


    I've looked in the past at CLisp and its loops. My view is that the
    number of possibilities it provides is over the job. It's like somebody
    was tasked with thinking up as many as possible, and making them all available.

    This is easy to because loop is a macro; you can just write code that
    you can distribute as a Lisp source file. Early implementatons of loop
    were distributed that way. It's happened that some applications would
    "bring their own loop" to work around bugs in a Lisp vendor's.

    Inspired by the Lisp loop, I made something like it for Awk
    using the GNU C Preprocessor.

    This was possible largely in part due to the way the
    for ( ... ; ... ; ...) header syntax is. The C-style loop
    gives us a target construct into which we can compile everything that we
    need from all the multiple clauses.

    The manual page for the macro is here:

    https://www.kylheku.com/cgit/cppawk/tree/cppawk-iter.1

    It is part of the cppawk project:

    https://www.kylheku.com/cgit/cppawk/about/

    There are regression/coverage test cases for it here:

    https://www.kylheku.com/cgit/cppawk/tree/testcases-iter

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Tue Apr 15 21:46:32 2025
    On 15/04/2025 20:07, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 14:19, Kaz Kylheku wrote:

    Thats's fine. But it means a real 'for' loop doesn't exist in C; you
    have to emulate it using that 3-way construct, which is naff, and also
    error prone.

    Real for loops _are_ a three-way construct.

    135 FOR I=1 TO 10 STEP 2 [BASIC]

    for(i = 1; i < 11; i += 2) [C/C++]

    do 1 = 1, 10, 2 [FORTRAN]

    Any step other than 1 is unusual. So Basic and Fortran would typically be:

    for i = 1 to 10 # 6 tokens; Basic
    do i = 1, 10 # 6 tokens; Fortran
    for i = 1, 10 # 6 tokens; Lua
    for i to 10 do # 5 tokens; Mine (using default start)
    to 10 do # 3 tokens; Mine (when index is not needed)

    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C

    * I've added 'int' for the C, as most of the above don't need a
    declaration for the loop index. But it will still be 14 without

    * I use += for the increment because you did. ++ saves one token,
    but it's still at 13/14 tokens

    * All the above can directly use 10 as the upper bound; C has to use
    11 when written idiomatically

    Even using a step of two, that would only add 2 tokens to the above; C
    will still need 14/15 tokens.

    Note that C's for-loop is dumb; it merely take three expressions A B C
    that can be completely unrelated, and arranges them into a loop:

    A; while (B) {...; C}


    SPRITE also had:

    UNTIL done, notfound
    DO
    ...
    IF token = "this"
    THEN LOOP_EXIT done
    FI;
    ...
    IF i = upb(table)
    THEN LOOP_EXIT notfound
    FI;
    ...
    OD
    CASE
    IS done: write("i=", i);
    OR notfound write("not found", upb(table));

    That's pretty weird, but whatever it does, it's nothing to do with
    iterating a variable over a range.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Janis Papanagnou on Tue Apr 15 20:37:43 2025
    On 2025-04-15, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    On 15.04.2025 16:30, bart wrote:
    On 15/04/2025 14:33, Kaz Kylheku wrote:
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    * Not having to write the variable 3 times (with C not always being >>>> able to detect if they didn't match)

    This is indeed a source of errors in C nested loops.

    According to Janis Papanagnou, it is 100% the programmer's fault. There
    is nothing wrong with the language!

    No, there is nothing wrong with the language if you make such errors.

    The programmer selects (or constructs) the algorithm, the language has
    clear semantics for such simple loop constructs without any irregular
    or hidden semantics, and the programmer's task is to know the elements
    of the language and transfer the algorithm to a correct coding. - It's self-delusion if you try to blame the language for the mistakes you do.

    While it would be close to professional misconduct for an engineer
    to deflect responsibility for a problem by blaming tools and materials
    (which he or she chose!) it is also the engineer's responsibility to
    identify how the nature of the tools contributes to problems.

    Programming tools contribute to risk. The more details you have to
    specify to solve a problem, that are not checked by machine, the greater
    the probability of making a mistake. The severity of a mistake
    also depends on tools.

    Open-coding something detailed tends to be more risky than using a
    verified, encapsulated abstraction which does the same thing, but
    figures out some of the details.

    The main things developers do wrong is choosing the wrong tool for
    the job. In such cases, it can be a fool's errand to try to
    catalog how the tool contributed to a problem. You wouldn't have
    a "post mortem" meeting about why the hammer failed to drive a screw,
    and how it could be improved.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Wed Apr 16 01:41:29 2025
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    Note that C's for-loop is dumb; it merely take three expressions A B C
    that can be completely unrelated, and arranges them into a loop:

    A; while (B) {...; C}

    - In this proposed arrangement, if the "continue" keyword is used in the
    loop, it will not execute C. You need:

    A; while (B) {...; contin_001: C}

    and then use "goto contin_001". The 001 is for uniqueness within
    the function, to which labels are scoped.

    - the arrangement doesn't produce macros very well using the
    ordinary preprocessor. Suppose we want to create loop which
    steps by 1 from hither to yon:

    #define loop_start(A, B, C) do { A = B; while (A < C) {

    #define loop_end(A) A++; } } while (0)

    we end up with two macros, where we have to repeat the variable.

    With the for loop we can just do

    #define loop(A, B, C) for (A = B; A < C; A++)

    Good thing we have that for syntax with its compact, encapsulated
    header that holds all the parts needed.

    If you keep plugging away with the naked "for" without making yourself a convenient macro, that's your problem.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Tue Apr 15 22:37:30 2025
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    Note that C's for-loop is dumb; it merely take three expressions A B C
    that can be completely unrelated, and arranges them into a loop:

    A; while (B) {...; C}
    Note that this problem is not unique to the for() statement. An
    assignment statement allows you to arrange three unrelated expressions
    together like

    A = B + C;

    "Doctor, it hurts when I hit my head with a hammer!"
    "Then stop doing that."

    The key to using the for() statement is to make sure the three
    expressions are related appropriately. Many different powerful and
    useful ways of using a for() statement have been shown in this thread
    that are not equivalent to for(int i=start; i<end; i += increment). Individually, those uses aren't particularly common, but collectively
    I've needed each of those uses often enough to be grateful that C has
    such a flexible construct to do it with.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to James Kuyper on Wed Apr 16 03:30:25 2025
    On 2025-04-16, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    Note that C's for-loop is dumb; it merely take three expressions A B C
    that can be completely unrelated, and arranges them into a loop:

    A; while (B) {...; C}
    Note that this problem is not unique to the for() statement. An
    assignment statement allows you to arrange three unrelated expressions together like

    A = B + C;

    "Doctor, it hurts when I hit my head with a hammer!"
    "Then stop doing that."

    The key to using the for() statement is to make sure the three
    expressions are related appropriately.

    The observation is valid that the three expressions often fall into a
    pattern by which they can be condensed.

    for (var = from; var < to; var++)

    can be expressed by a construct which mentions var ony once,
    and omits the operators.

    You can obtain this with the preprocessor and be reasonably happy.

    Similarly, sometimes assignment statements fit patterns which
    lead us to want to condense them.

    One pattern is

    A = A + C

    for which we have

    A += C

    in order to avoid mentioning A twice, and of course for

    A = A + 1

    we have

    ++A (as well as A++ which lets us capture the prior value)

    C pointer arithmetic affords us a way to condense this pattern also:

    A[i] = B[i] + C[i]

    in a loop body where these expressions are repeated multiple times,
    and are both read and written, we can achieve economy of expression with

    double a = &A[i];
    double b = &B[i];
    double c = &C[i];

    *a = *b + *c;

    Sometimes code like this shamelessly uses preprocessing, hopefully
    confined to a single translation unit.

    #define a A[i]
    #define b B[i]
    #define c C[i]

    a = b + c

    C provides some decent syntactic sugars to shorten code.

    It seems shortsighted to criticize C for having a verbose for loop
    construct, given that it can be macroed over, and that other devices
    more than make up for it.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Wed Apr 16 07:35:46 2025
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Janis Papanagnou on Wed Apr 16 07:44:15 2025
    On 16.04.2025 07:19, Janis Papanagnou wrote:

    If you have some conditioning that "most" is the programming world
    then I suggest to #define MOST_LOOP for (i=0 i<=N; ++i)

    LOL! - Should have been #define MOST_LOOP for (i=0 i<N; ++i)

    off-by-one error by copy/paste-programming! - All points proven.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Wed Apr 16 07:39:11 2025
    On 15.04.2025 18:42, bart wrote:
    On 15/04/2025 17:22, Janis Papanagnou wrote:
    On 15.04.2025 16:30, bart wrote:
    On 15/04/2025 14:33, Kaz Kylheku wrote:
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    * Not having to write the variable 3 times (with C not always
    being
    able to detect if they didn't match)

    This is indeed a source of errors in C nested loops.

    According to Janis Papanagnou, it is 100% the programmer's fault. There
    is nothing wrong with the language!

    No, there is nothing wrong with the language if you make such errors.

    The programmer selects (or constructs) the algorithm, the language has
    clear semantics for such simple loop constructs without any irregular
    or hidden semantics, and the programmer's task is to know the elements
    of the language and transfer the algorithm to a correct coding. - It's
    self-delusion if you try to blame the language for the mistakes you do.

    Suppose you have two ways A and B to implement a feature in a language.

    You find that those using A tend to make twice as many mistakes in that feature, and have more undetectable bugs, as those who use B.

    Your job is to choose which of A and B to keep.

    Would your decision completely ignore such findings?

    We have a couple decisions to make, some factors are often predefined.
    The necessary and possible decisions are made on different levels
    depending on the role you have in a software project.

    If I'd have a choice in the used language I might or might not use "C" depending on the requirements to fulfill.

    To be concrete; it's unlikely that I'll use Algol 68 or "your language"
    and it had been the case that we had to use languages like C++ or Java.

    If I have a choice in the participating programmers I would certainly
    select those programmers that don't program by copy/paste and fail to
    create correct code even in trivial cases like 'for' loops.

    To be concrete for the factors exposed here; I would not select you for
    the programming team; more often than not I see you only complaining
    and having issues with understanding of (commonly known) programming
    and programming language aspects.

    As a pure programmer with a given environment I would use the features
    of a language that appears most appropriate. You, OTOH, will obviously
    be helpless since you fail even with simple loops in "C" - since that's
    what "C" provides as control constructs for loops.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Wed Apr 16 07:19:18 2025
    On 15.04.2025 12:30, bart wrote:
    On 15/04/2025 08:17, Janis Papanagnou wrote:
    On 14.04.2025 17:22, bart wrote:
    On 14/04/2025 13:18, Janis Papanagnou wrote:
    [...]

    The "C" syntax has actually a flexibility that is very valuable.

    The flexibility is the problem, because you have to specify the loop in
    such excruciating detail. It is easy to make a mistake which results in
    still legal code. And you now have to analyse each loop to see what kind >>> of loop it is:

    Well, our opinions obviously differ. I just give you two examples
    (and there's many variants of these) of not uncommon 'for' usages...

    for (c=0; bitstr; c++)
    bitstr &= bitstr-1;

    I can't grok that.

    It's a simple example of a loop where the condition is not depending
    on the counting loop variable. - What is it that you don't understand
    here? - That's one example where the "C" loop design decision allows
    to express yet more sensible functionality than only simple loops with
    counts of 1.

    (In case you don't understand the actual operation - which is not the
    point of this example - inspect, e.g., K&R and the footnotes there.)

    If all you know (and can handle) is a simple counted loop then every
    extension may appear to you being strange.

    [ meaningless while/for stuff snipped ]

    (One of your fundamental problems with "C" seems to be to understand
    the 'for' keyword meaning only counted loops with one variable and a
    simple +1 increment. - I can't help you here.)


    [...]

    Suppose you see 'i <= N' as the condition; is that '<=' intentional, or
    is it a typo for '<'? It's impossible to tell.

    (This is nonsense.)

    You can't just say that without explanation. WHY it it nonsense?

    It's nonsense because all programmers use the comparison operations
    that are necessary; I don't know about you but if I do a primitive
    arithmetic loop I start with 0 and compare < against N (the amount
    of iterations) or start with 1 and compare <= against N; if that's
    what is intended.

    I've written code where the logic required comparisons of i < N-1
    and also i <= N . So what? - Should I not do that because you are
    getting confused when inspecting my code?

    It's nonsense on so many levels.

    If you have doubts ask the programmer or verify the logic. If you
    are the programmer add a comment to make the intention clear. If
    you are a project lead define coding standards, coach your team,
    invent QA measures, do code reviews.

    Take this:

    for (i=0 i<=N; ++i)

    Most such loops iterate over 0..N-1 inclusive, so would need "<".

    (One of your fundamental problems with "C" seems to be to understand
    the 'for' keyword meaning only counted loops with one variable and a
    simple +1 increment. - I can't help you here.)

    If you have some conditioning that "most" is the programming world
    then I suggest to #define MOST_LOOP for (i=0 i<=N; ++i)
    so that you don't make error and don't get confused respectively.

    So, in
    your opinion, is that <= a typo, or is the intention to iterate over
    0..N inclusive (so N+1 iterations)?

    It depends on the context.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to bart on Wed Apr 16 11:58:36 2025
    On Tue, 15 Apr 2025 11:15:06 +0100, bart wrote:
    On 15/04/2025 05:57, Rosario19 wrote:
    On Mon, 14 Apr 2025 14:18:39 +0200, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip this
    post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    For this specific example (ignore 'let' for C), please explain why it is >better than, say:

    FOR(i,1,36) {

    This is 99% of my for-loops. Is it the same reasoning why I have to
    write 'break' in 99% of my switch-blocks?

    APL has just one char "iota" for represent range example iota_36 would
    be the range 1..36

    {function w}ApplyToAll iota_36

    it is equivalent of above loop

    for(;;) it is better, because the eye see where are the initialiation,
    where the end of loop condition, where the loop increment or loop
    change variables, easier.

    There's something about this group which celebrates these annoying
    language characteristics which are only useful or meaningful in a tiny >minority of cases: see how wonderful it is for 1% of the time?

    i'm not agree, when one has something of complex is better for() loop,
    but when has something that is more complex than remain goto label...

    That must surely justify them being both a PITA and dangerously error
    prone in the vast majority of cases!

    when one has used for() loop enought time should find that very easy
    and convenient.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to Janis Papanagnou on Wed Apr 16 11:45:24 2025
    On Tue, 15 Apr 2025 09:25:40 +0200, Janis Papanagnou wrote:

    On 15.04.2025 06:57, Rosario19 wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    Sure. Or all done with Turing machines. - But why would one want to.

    because one not has the for loop, because is need more flexibility in
    what code has to make, because one find so easy goto label, that it is
    easier of the loop for, even if i think in 80% of cases for loop is
    less chars and easier of the loop that use goto label

    Maybe a note aside on your comment; I haven't read many specification >documents of contemporary language lately, but many of those old specs
    often described the semantics of high-level constructs (like loops) by
    an equivalent 'goto' based code pattern.

    yes low level is goto label

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to Kaz Kylheku on Wed Apr 16 12:09:10 2025
    On Tue, 15 Apr 2025 13:33:21 -0000 (UTC), Kaz Kylheku wrote:

    On 2025-04-15, bart wrote:
    * Not having to write the variable 3 times (with C not always being
    able to detect if they didn't match)

    This is indeed a source of errors in C nested loops. Say we have
    these macros:

    FOR (i, 0, N-1)
    FOR (j, 0, i)
    ...

    we are less likely to make some copy paste error like

    for (i = 0; i < N; i++)
    for (j = 0; j < i; i++)
    ...

    Int he past, I've run into bugs in nested loops, along these lines.

    if F is a macro as #define F for
    until now i not find any inconvenient for me at last

    In loop-heavy code, making a macro like the FOR above might not
    be a bad idea.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to bart on Wed Apr 16 12:04:59 2025
    On Tue, 15 Apr 2025 13:55:43 +0100, bart wrote:
    On 15/04/2025 13:25, Michael S wrote:
    On Tue, 15 Apr 2025 11:15:06 +0100
    bart wrote:

    On 15/04/2025 05:57, Rosario19 wrote:
    On Mon, 14 Apr 2025 14:18:39 +0200, Janis Papanagnou wrote:
    (While there's some "C" stuff in here it contains a lot of non-"C"
    samples for comparison. So [OT]-sensible folks may want to skip
    this post.)

    On 14.04.2025 12:16, bart wrote:
    On 14/04/2025 05:23, Janis Papanagnou wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    For this specific example (ignore 'let' for C), please explain why it
    is better than, say:

    FOR(i,1,36) {

    This is 99% of my for-loops. Is it the same reasoning why I have to
    write 'break' in 99% of my switch-blocks?

    There's something about this group which celebrates these annoying
    language characteristics which are only useful or meaningful in a
    tiny minority of cases: see how wonderful it is for 1% of the time?

    That must surely justify them being both a PITA and dangerously error
    prone in the vast majority of cases!

    I regularly use two languages with "proper loops" - Matlab/Octave and
    VHDL (Ada-like syntax). When writing loops in these languages, I don't
    feel any extra convenience over C.

    I'm not familiar with those, but the first Ada loop example I googled
    for was this:

    for Variable in 0 .. 9 loop

    99% of variable in my C code it one just a letter lenght

    In C that exact example would be:

    for (Variable = 0; Variable < 10; ++Variable) {

    or maybe:

    for (Variable = 0; Variable <= 9; Variable = Variable + 1) {

    somethime i use F as macro for "for" so for me above would be:

    F(j=0;j<=9;++j)

    So, in the Ada:

    * Not having to write the variable 3 times (with C not always being
    able to detect if they didn't match)

    * Not having to either offset the upper limit, or juggle between <
    and <=

    * Not having to explicitly provide the code to increment the variable

    doesn't have ANY extra convenience?

    (You can have a 100MB compiler and you still have to tell it how to >increment a loop index! That is plain crazy.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to bart on Wed Apr 16 12:29:05 2025
    On Tue, 15 Apr 2025 11:30:24 +0100, bart wrote:

    for (i=0 i<=N; ++i)

    Most such loops iterate over 0..N-1 inclusive, so would need "<". So, in >your opinion, is that <= a typo, or is the intention to iterate over
    0..N inclusive (so N+1 iterations)?


    (May reply to rest separately.)

    the loop enter with i=0
    than make i= 1..N N in the count
    so would be N+1 times iterations
    that are 0..N or 0,1,2,3...,N

    <= is not a Typo

    i not find the problem

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Wed Apr 16 12:01:31 2025
    On 16/04/2025 06:19, Janis Papanagnou wrote:
    On 15.04.2025 12:30, bart wrote:

    (One of your fundamental problems with "C" seems to be to understand
    the 'for' keyword meaning only counted loops with one variable and a
    simple +1 increment. - I can't help you here.)

    And your problem seems to the opposite: being unable to understand that for-loop (perhaps spelled 'do') can be a specialised feature to iterate
    one or more variables over a predetermined range or set of values.

    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    Everyone here is defending the latter to the death. Why? Apparently the
    ONLY argument is 'flexibility'.

    Having to writing a simple iteration in such a convoluted and unchecked
    manner is much better because - you can use the same syntax to iterate
    over a list!


    I've written code where the logic required comparisons of i < N-1
    and also i <= N . So what? - Should I not do that because you are
    getting confused when inspecting my code?


    This is worrying. So you have a bunch of code with multiple like this:

    for (i=0; i<N; ++)
    for (i=0; i<N; ++)
    for (i=0; i<=N; ++)
    for (i=0; i<N; ++)

    And you notice one has <= while the others have <. But according to you,
    this is nothing remarkable and raises no flags. Obviously the author
    intended to iterate one more time there!

    With language-supported iteration, the comparison operator is not
    exposed, so the programmer cannot accidentally type the wrong one.

    (I see I have ++ and not ++i; never mind. It is telling that it took me
    a minute to notice!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to All on Wed Apr 16 12:38:07 2025
    On 16/04/2025 11:29, Rosario19 wrote:
    On Tue, 15 Apr 2025 11:30:24 +0100, bart wrote:

    for (i=0 i<=N; ++i)

    Most such loops iterate over 0..N-1 inclusive, so would need "<". So, in
    your opinion, is that <= a typo, or is the intention to iterate over
    0..N inclusive (so N+1 iterations)?


    (May reply to rest separately.)

    the loop enter with i=0
    than make i= 1..N N in the count
    so would be N+1 times iterations
    that are 0..N or 0,1,2,3...,N

    <= is not a Typo

    i not find the problem


    No? What about here:

    enum {N=10};
    int A[N];

    for (int i=0; i <= N; ++i) A[i] = i;

    Is there still no problem? Except this will be in the middle of 1000
    lines of busy code with longer identifiers and more elaborate expressions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Wed Apr 16 12:32:13 2025
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?

    THAT would be nonsense! For your benefit, I've done a survey of a 30Kloc
    C program (not one of mine). It has 181 for-loop statements, of which:

    15 are endless loops (for (;;))
    23 are either linked traversal or do something weird
    143 seems to be simple integer interations

    Of those 143, 137 count upwards with a step of +1; 6 count downwards
    with a step of -1.

    So here, 0% of such loops have a step other than 1. THAT's what I mean
    by 'unusual'.

    Scot Lurndal gave examples comparing C with BASIC/FORTRAN that used
    steps other than one, to back up a claim that they routinely use 3
    components. Actually they rarely do.

    There is something else: all 181 of those loops used the 'for' keyword.
    Which meant I had to painstakingly analyse them one by one to determine
    what they were (and probably overlooked some but the figures will be
    close enough).

    Written in my language, 15 would be 'do' loops; 23 would likely be
    'while' loops; and only those 143 would be 'for' loops.

    No analysis necessary.

    But never, mind, C's for-loop will still be the most superior to
    everybody here. I'd have an easier time arguing about religion!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Wed Apr 16 15:08:37 2025
    On Wed, 16 Apr 2025 12:32:13 +0100
    bart <bc@freeuk.com> wrote:


    But never, mind, C's for-loop will still be the most superior to
    everybody here. I'd have an easier time arguing about religion!


    Who exactly said that it is superior? Surely not me.
    I think, most posters here would agree with my stance that C for() is non-ideal. esp. for writer, but good enough.

    And it has a minor advantage of being more clear for casual readers
    than most "proper" counting loop. When counting loop is written as C
    for() loop, a casual reader does not have to consult the manual about
    meaning of the 1st, 2nd and 3rd (if present) parameters.

    I don't know about you, may be your memory is perfect. Mine is not.
    Even with python, a language that I use more often than once per year, remembering whether range(3) means (0,1,2) or (0,1,2,3) is an effort.
    Much more so with (modern) Fortran, that I read very rarely. In case of Fortran, it certainly does not help that the principle of do loop is the
    same as for loop in Matlab/Octave that I use regularly, but the order of parameters differs.

    Oh, now you could interpret a written above as statement of superiority
    of C syntax. So, no, it is not. Those are *minor* points.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Kaz Kylheku on Wed Apr 16 14:12:20 2025
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-16, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 2025-04-15, bart <bc@freeuk.com> wrote:
    Note that C's for-loop is dumb; it merely take three expressions A B C
    that can be completely unrelated, and arranges them into a loop:

    A; while (B) {...; C}
    Note that this problem is not unique to the for() statement. An
    assignment statement allows you to arrange three unrelated expressions
    together like

    A = B + C;

    "Doctor, it hurts when I hit my head with a hammer!"
    "Then stop doing that."

    The key to using the for() statement is to make sure the three
    expressions are related appropriately.

    The observation is valid that the three expressions often fall into a
    pattern by which they can be condensed.

    for (var = from; var < to; var++)

    can be expressed by a construct which mentions var ony once,
    and omits the operators.

    You can obtain this with the preprocessor and be reasonably happy.

    I'd reject any code that hid a 'for' loop in a preprocessor macro
    during review.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Wed Apr 16 14:09:44 2025
    bart <bc@freeuk.com> writes:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 14:19, Kaz Kylheku wrote:

    Thats's fine. But it means a real 'for' loop doesn't exist in C; you
    have to emulate it using that 3-way construct, which is naff, and also
    error prone.

    Real for loops _are_ a three-way construct.

    135 FOR I=1 TO 10 STEP 2 [BASIC]

    for(i = 1; i < 11; i += 2) [C/C++]

    do 1 = 1, 10, 2 [FORTRAN]

    Any step other than 1 is unusual. So Basic and Fortran would typically be:

    for i = 1 to 10 # 6 tokens; Basic
    do i = 1, 10 # 6 tokens; Fortran
    for i = 1, 10 # 6 tokens; Lua
    for i to 10 do # 5 tokens; Mine (using default start)
    to 10 do # 3 tokens; Mine (when index is not needed)

    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C



    for(i = 1; i++ <= 10;)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Michael S on Wed Apr 16 14:23:18 2025
    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 16 Apr 2025 12:32:13 +0100
    bart <bc@freeuk.com> wrote:


    But never, mind, C's for-loop will still be the most superior to
    everybody here. I'd have an easier time arguing about religion!


    Who exactly said that it is superior? Surely not me.
    I think, most posters here would agree with my stance that C for() is >non-ideal. esp. for writer, but good enough.

    I disagree with that statement, and I expect most posters here
    would also disagree with it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Wed Apr 16 14:21:54 2025
    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:


    So here, 0% of such loops have a step other than 1. THAT's what I mean
    by 'unusual'.

    Sample bias.


    Scot Lurndal gave examples comparing C with BASIC/FORTRAN that used
    steps other than one, to back up a claim that they routinely use 3 >components. Actually they rarely do.

    I made no such claim. You said that for loops were not three-way
    constructs - I showed that was not an accurate statement. I made
    no claims about anything being 'routine'.

    A common construct:

    entity *ep = entities[0];
    for(size_t i = 0ul; i < MAX_ENTITIES; i++, ep++) {
    ep->field = do_something(args);
    }

    in C++

    for(x = map.begin(); x != map.end(); ++x) {
    /* process a red-black tree element */
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Scott Lurndal on Wed Apr 16 17:37:21 2025
    On Wed, 16 Apr 2025 14:09:44 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    bart <bc@freeuk.com> writes:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 14:19, Kaz Kylheku wrote:

    Thats's fine. But it means a real 'for' loop doesn't exist in C;
    you have to emulate it using that 3-way construct, which is naff,
    and also error prone.

    Real for loops _are_ a three-way construct.

    135 FOR I=1 TO 10 STEP 2 [BASIC]

    for(i = 1; i < 11; i += 2) [C/C++]

    do 1 = 1, 10, 2 [FORTRAN]

    Any step other than 1 is unusual. So Basic and Fortran would
    typically be:

    for i = 1 to 10 # 6 tokens; Basic
    do i = 1, 10 # 6 tokens; Fortran
    for i = 1, 10 # 6 tokens; Lua
    for i to 10 do # 5 tokens; Mine (using default start)
    to 10 do # 3 tokens; Mine (when index is not needed)

    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C



    for(i = 1; i++ <= 10;)

    I'd reject this code during review.
    Hopefully, you too.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Michael S on Wed Apr 16 15:31:38 2025
    On 16/04/2025 13:08, Michael S wrote:
    On Wed, 16 Apr 2025 12:32:13 +0100
    bart <bc@freeuk.com> wrote:


    But never, mind, C's for-loop will still be the most superior to
    everybody here. I'd have an easier time arguing about religion!


    Who exactly said that it is superior? Surely not me.
    I think, most posters here would agree with my stance that C for() is non-ideal. esp. for writer, but good enough.

    And it has a minor advantage of being more clear for casual readers
    than most "proper" counting loop.

    Well, there is less ambiguity about the iteration range. But this is
    something that C's 0-based nature has helped create (see below).

    When counting loop is written as C
    for() loop, a casual reader does not have to consult the manual about
    meaning of the 1st, 2nd and 3rd (if present) parameters.

    No, you have to analyse the loop instead:

    for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){
    for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
    for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}

    The first challenge is to isolate the condition! That means carefully
    counting those ; and , characters. Then figuring out what's going on.

    These three clearly are not simple iterations, yet they are all start
    'for'. I'd write the third (at least) like this:

    i = 0;
    while (zLine[i] && IsSpace(zLine[i]) {++i}

    Now constrast with a language where you KNOW that 'for' isn't going to
    be doing anything whacky. You know there will be a loop index name and
    some limits, or a collection of values to loop over:

    for index in firstvalue..lastvalue
    for x in collection

    I don't know about you, may be your memory is perfect. Mine is not.
    Even with python, a language that I use more often than once per year, remembering whether range(3) means (0,1,2) or (0,1,2,3) is an effort.
    Much more so with (modern) Fortran, that I read very rarely. In case of Fortran, it certainly does not help that the principle of do loop is the
    same as for loop in Matlab/Octave that I use regularly, but the order of parameters differs.

    When languages used to be 1-based, it was easy. Then 0-based came along,
    and typically iteration changed from 1..N inclusive, to 0..N-1 inclusive.

    Now, a range may or may not be inclusive. In Python, 0-based, it isn't,
    so range(10) or range(0,10) means 0..9 inclusive.


    Oh, now you could interpret a written above as statement of superiority
    of C syntax. So, no, it is not. Those are *minor* points.

    Here's some C code to print the elements of an array:

    static char* table[] = {"one", "two", "three", "four", "five"};

    for (int i=0; i<sizeof(table)/sizeof(table[0]); ++i)
    printf("%d %s\n", i, table[i]);

    And here is how I'd write it using the 'minor' advantages of my syntax:

    static []ichar table = ("one", "two", "three", "four", "five")

    for i, s in table do
    println i, s
    end

    To me, the differences in that for-loop are like chalk and cheese.

    (Note that the latter is 1-based, but it is not apparent in the code;
    the outputs are numbered 1 to 5. The C is zero-based, and that has to be specified. The outputs are numbered 0 to 4.

    Moreover, I could have specified a different array base, and the loop
    remains unchanged.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Wed Apr 16 15:45:56 2025
    On 16/04/2025 15:09, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 14:19, Kaz Kylheku wrote:

    Thats's fine. But it means a real 'for' loop doesn't exist in C; you
    have to emulate it using that 3-way construct, which is naff, and also >>>> error prone.

    Real for loops _are_ a three-way construct.

    135 FOR I=1 TO 10 STEP 2 [BASIC]

    for(i = 1; i < 11; i += 2) [C/C++]

    do 1 = 1, 10, 2 [FORTRAN]

    Any step other than 1 is unusual. So Basic and Fortran would typically be: >>
    for i = 1 to 10 # 6 tokens; Basic
    do i = 1, 10 # 6 tokens; Fortran
    for i = 1, 10 # 6 tokens; Lua
    for i to 10 do # 5 tokens; Mine (using default start)
    to 10 do # 3 tokens; Mine (when index is not needed)

    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C



    for(i = 1; i++ <= 10;)

    So real for loops are a /two-way/ construct?

    In any case, that doesn't do the same as the others, as it iterates over
    2 to 11 inclusive, not 1 to 10.

    You might try 'for (i=0; i++ < 10);)', but there's still a problem: you
    have to offset the start value by -1. This mean that to iterate over the
    0..9 bounds of 10-element array, you'd have to write:

    for (i = -1; i++ < 9;)

    It becomes exclusive at the lower end, and top becomes inclusive despite
    using '<' instead of '<='.

    The real problem is that the index is incremented in the wrong place.
    Now look again at that Fortran:

    do i = 1, 10 # iterate over 1..10 inclusive
    do i = 0, 9 # iterate over 0..9 inclusive

    It now looks even better: gorgeously simple, clean, intuitive - and
    still shorter.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Wed Apr 16 10:47:56 2025
    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:


    So here, 0% of such loops have a step other than 1. THAT's what I mean
    by 'unusual'.

    The files easily accessible to me contain 13965 for statements, of which
    596 used a step other than 1.

    890 are for iterating over linked lists, such as:

    for(f = *opt; f; f = f->next)

    117 are for iterating over bits in a bit mask, such as:
    for(nLeft=0; !(bitmask & ((u64)1 << nLeft))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Wed Apr 16 16:14:03 2025
    On 16/04/2025 15:47, James Kuyper wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:


    So here, 0% of such loops have a step other than 1. THAT's what I mean
    by 'unusual'.

    The files easily accessible to me contain 13965 for statements, of which
    596 used a step other than 1.

    (I assume you mean other than +1 or -1.)

    So about 4%. What tool did you use to determine that?

    If I look at sql.c (which includes sqlite3.c), there are 1900
    for-statements.

    Among those, 40 involve += or -=, usually in the increment part, however
    I didn't look too closely. I didn't look for ones like i=i+2.

    That would be 2% of the total. But the loops include a substantial
    proportion of fanciful for-headers, and the odd increment might relate
    to those.

    Still, I was replying to someone suggesting my claim of "Any step other
    than 1 is unusual." was "Nonsense".

    I suggest that 2-4% incidence is 'unusual'. In the two smaller programs
    I also looked at, of which I reported one, the incidence was 0% among
    /simple iterations/.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Wed Apr 16 15:44:43 2025
    bart <bc@freeuk.com> writes:
    On 16/04/2025 15:09, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 15/04/2025 14:19, Kaz Kylheku wrote:

    Thats's fine. But it means a real 'for' loop doesn't exist in C; you >>>>> have to emulate it using that 3-way construct, which is naff, and also >>>>> error prone.

    Real for loops _are_ a three-way construct.

    135 FOR I=1 TO 10 STEP 2 [BASIC]

    for(i = 1; i < 11; i += 2) [C/C++]

    do 1 = 1, 10, 2 [FORTRAN]

    Any step other than 1 is unusual. So Basic and Fortran would typically be: >>>
    for i = 1 to 10 # 6 tokens; Basic
    do i = 1, 10 # 6 tokens; Fortran
    for i = 1, 10 # 6 tokens; Lua
    for i to 10 do # 5 tokens; Mine (using default start)
    to 10 do # 3 tokens; Mine (when index is not needed)

    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C



    for(i = 1; i++ <= 10;)

    So real for loops are a /two-way/ construct?

    In any case, that doesn't do the same as the others, as it iterates over
    2 to 11 inclusive, not 1 to 10.

    The point was to execute a loop 10 times, which this does.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to James Kuyper on Wed Apr 16 18:18:40 2025
    On Wed, 16 Apr 2025 10:47:56 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:


    So here, 0% of such loops have a step other than 1. THAT's what I
    mean by 'unusual'.

    The files easily accessible to me contain 13965 for statements, of
    which 596 used a step other than 1.


    In quoted statement "1" was meant to cover both +1 and -1.
    I would be surprised to find out that non-units strides are relatively
    common (say, above 0.1%) outside of several specialized fields, like
    linear algebra and image processing.

    There are yet other fields where we can encounter increments that are non-constant throughout duration of the loop. Bart would probably say
    that such loops do not count, in both senses. I.e. they are not
    counting loops, but forms of while loop.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Michael S on Wed Apr 16 12:28:47 2025
    On 4/16/25 11:18, Michael S wrote:
    On Wed, 16 Apr 2025 10:47:56 -0400
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:


    So here, 0% of such loops have a step other than 1. THAT's what I
    mean by 'unusual'.

    The files easily accessible to me contain 13965 for statements, of
    which 596 used a step other than 1.


    In quoted statement "1" was meant to cover both +1 and -1.

    Most of that code was part of packages I installed rather than code that
    I myself wrote. I naively assumed that any for loop where someone used
    +=, it would be for a stride other than 1 - why use "+=1" rather than
    "++"? However, 37 of those cases did in fact use "+= 1". None of them
    used "-= 1". Indeed, I didn't find any cases of for statements using -=.

    I would be surprised to find out that non-units strides are relatively
    common (say, above 0.1%)

    559/13965 is about 4%.

    outside of several specialized fields, like
    linear algebra and image processing.

    No, for most of them it was some other reason, such as putting tab stops
    after ever 4 characters.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Keith Thompson on Wed Apr 16 18:11:38 2025
    On 2025-04-16, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-16, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    [...]
    The key to using the for() statement is to make sure the three
    expressions are related appropriately.

    The observation is valid that the three expressions often fall into a
    pattern by which they can be condensed.

    for (var = from; var < to; var++)

    can be expressed by a construct which mentions var ony once,
    and omits the operators.

    You can obtain this with the preprocessor and be reasonably happy.

    Sure, you *can*, but I wouldn't.

    But then you would complain about the unpreprocessed version
    being verbose, because it becomes a choice at that point.

    For me the raw C-style for loop is clear enough.

    I could write a macro like:

    #define ITERATE(var, from, to) for ((var) = (from); (var) < (to); (var)++)

    but then anyone reading the code has to understand both how C-style
    for loops work and how the ITERATE macro works.

    Anyone understanding any program has to be prepared to study
    numerous definitions, in all categories of definition.

    Par for the course.

    Does the expansion
    use < or <=? What happens if "to" is INT_MAX? Did the author of
    the macro get everything right?

    If they did get it right, then 37 places where it is being used
    are consistently also getting it right, assuming those places
    intend for ITERATE(a, b, c) to step an integer or pointer value
    over the half-open range[b, c). (This aspect of the macro may
    be error-prone, but no language construct can read you mind
    as to what primary argument value you intended.)

    Mostly I just have to worry about two potential issues in
    each of those 37 places: (1) are they stepping the correct
    variable? E.g. is any inner loop wrongly "hijacking" an outer
    loop's variable? and (2) is the half-open range semantics
    correct for that situation?

    If the 37 loops are open-coded, I have more material to inspect.
    There are more ingredients. Four or five different conventions
    might easily be identified among the 37.

    Here is the crux of the issue: uses of for loop in C follow
    certain recognizeable idioms. You have to stare at the loop for
    a few seconds to identify which idiom it is using, and is it
    getting it right.

    Now if someone else finds that such a macro makes things easier for
    them, that's fine. But often, *in my opinion*, such macros make code
    harder to read for someone who knows C well.

    Also, annoying nonstandard gobbledygook like:

    result_t res = strip_layer_2_header(packet, L2_STRIP_GAUSSIAN);

    Gee, why can't they just put everything in one main() function,
    which is filled with nothing but vocabulary from Section 7 of
    ISO C, Library, instead of changing the language? Nouns and verbs are
    language, you know.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to bart on Wed Apr 16 19:15:53 2025
    On Wed, 16 Apr 2025 12:38:07 +0100, bart wrote:

    On 16/04/2025 11:29, Rosario19 wrote:
    On Tue, 15 Apr 2025 11:30:24 +0100, bart wrote:

    for (i=0 i<=N; ++i)

    Most such loops iterate over 0..N-1 inclusive, so would need "<". So, in >>> your opinion, is that <= a typo, or is the intention to iterate over
    0..N inclusive (so N+1 iterations)?


    (May reply to rest separately.)

    the loop enter with i=0
    than make i= 1..N N in the count
    so would be N+1 times iterations
    that are 0..N or 0,1,2,3...,N

    <= is not a Typo

    i not find the problem


    No? What about here:

    enum {N=10};
    int A[N];

    for (int i=0; i <= N; ++i) A[i] = i;

    Is there still no problem? Except this will be in the middle of 1000
    lines of busy code with longer identifiers and more elaborate expressions.

    in this case the if the lenght of A is N, the loop has to be

    for(i=0; i<N; ++i) A[i] = i;

    so i is in the range 0..N-1
    but i never use macro/enum as lengh of arrays, or at last don't
    rememeber i have had used that

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Kaz Kylheku on Wed Apr 16 18:43:53 2025
    On 2025-04-16, Kaz Kylheku <643-408-1753@kylheku.com> wrote:
    On 2025-04-16, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-16, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    [...]
    The key to using the for() statement is to make sure the three
    expressions are related appropriately.

    The observation is valid that the three expressions often fall into a
    pattern by which they can be condensed.

    for (var = from; var < to; var++)

    can be expressed by a construct which mentions var ony once,
    and omits the operators.

    You can obtain this with the preprocessor and be reasonably happy.

    Sure, you *can*, but I wouldn't.

    But then you would complain about the unpreprocessed version
    being verbose, because it becomes a choice at that point.

    s/would/woudln't/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Kaz Kylheku on Wed Apr 16 20:05:20 2025
    On 16/04/2025 19:43, Kaz Kylheku wrote:
    On 2025-04-16, Kaz Kylheku <643-408-1753@kylheku.com> wrote:

    <snip>


    But then you would complain about the unpreprocessed version
    being verbose, because it becomes a choice at that point.

    s/would/woudln't/

    s/woudln't/wouldn't/

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Wed Apr 16 21:43:38 2025
    On 2025-04-16, bart <bc@freeuk.com> wrote:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?

    Hey Bart, how would you handle a loop like

    do x = m to n ...

    where m and n are not known until run time, and may be the
    extreme values of the type? Like C's INT_MIN and INT_MAX, respectively,
    where x is of type int.

    Because in this loop, x takes on every possible value of the type,
    we cannot have a loop guard which prevents entry of the loop body
    based on solely the value of x.

    The compilaton strategy we will likely pursue for this will be
    a bottom-of-the-loop test. That is to say, after executing
    an iteration, if x has the value n, then the loop terminates.

    Unfortunately, this pattern doesn't lend itself well to the
    for(;;) construct n C.

    The idiom for (x = m; x <= n; x++) only works when x may be
    incremented even when it is already equal to n.

    If the type is singned, like int, and n is INT_MAX, x++
    is undefined behavior after the last iteration.

    So this is part of the reason why for leaves everything open; the C
    programmer can hand-wave away these issues based on the specific use
    case of the loop, whose details are in the open, making it obvious that
    the idiom doesn't fully generalize to every corner case.

    The for construct could use a way of indicating a bottom test,
    like, oh, I don't know:

    for (decl/expr; : expr ; expr) // or some better way

    Here, the : means, jump unconditionally into the first iteration,
    and test expr after each iteration, before doing the increment.

    Then we can do

    for (int i = INT_MIN; : i < INT_MAX; i++)

    After the last iteration, i is INT_MAX, and so the test fails.
    The loop terminates without performing i++.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Wed Apr 16 23:14:23 2025
    On 16/04/2025 21:03, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?

    Exactly, because "unusual" and "the majority" are the only
    possibilities.


    I'm not sure what you're getting at.

    If you go back a few posts, Scott Lurndal was (1) trying to make out
    that all for loops consist of 3 elements like C; (2) showing examples in
    BASIC and FORTRAN that with 'STEP' parts that made them somewhat longer
    than otherwise:

    "135 FOR I=1 TO 10 STEP 2 [BASIC]

    for(i = 1; i < 11; i += 2) [C/C++]

    do 1 = 1, 10, 2 [FORTRAN]"

    This was misleading: C always needs that third part when incrementing,
    *even when the increment is one*, but BASIC and FORTRAN never need it
    *unless* the increment is other than one.

    So I said 'Any step other than 1 is unusual". Which it is (I've seen
    enough code over half a century to know that is true, and I also spent a
    year writing Fortran professionally).

    To which JP said this:

    "Nonsense".

    So do you agree with JP here or with me?

    And if with me, why are you not having a go at JP; another of your
    chummy mates?

    And if you agree JP, then same question.

    We know your opinion. I for one acknowedge that your opinion
    is valid, and you're entitled to hold it. We're just tired
    of you making the same point again and again and again,

    And I'm tired of people trying to catch me out with stupid, invalid
    arguments.

    while
    misrepresenting those of us who hold different opinions.

    What point was JP making when they said "Nonsense", what opinion was
    being opined? My reply were only about the prevalence of certain steps
    in iterating loops within programming languages.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Wed Apr 16 23:42:00 2025
    On 16/04/2025 22:43, Kaz Kylheku wrote:
    On 2025-04-16, bart <bc@freeuk.com> wrote:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?

    Hey Bart, how would you handle a loop like

    do x = m to n ...

    where m and n are not known until run time, and may be the
    extreme values of the type? Like C's INT_MIN and INT_MAX, respectively,
    where x is of type int.

    Because in this loop, x takes on every possible value of the type,
    we cannot have a loop guard which prevents entry of the loop body
    based on solely the value of x.

    I'm not exactly sure what you are asking. Is it a loop like this, here
    in my language:

    int n:=0

    for i in i32.bounds do # ie. i32.min .. i32.max
    ++n
    od

    println n

    This works fine; after a second or so it displays 4294967296.

    However, this languages evaluates using 64 bits. Perhaps this loop may demonstrate the issues better:

    for i in i64.bounds do

    However, I would estimate it would take 190 years to finish.

    I assume you're thinking of C which uses i32 and where comparisons near
    the extreme values of the type are problemetical. Or this line in my
    language:

    for i in i64.max-10 .. i64.max do println i

    which doesn't stop (u64 is OK however). That doesn't worry me too much,
    I can just add a Note to the language spec warning of UB when a for-loop
    bound is at the limits of the type. Where all sorts of other stuff can
    happen because of how values wrap.

    Then workarounds are needed, for example:

    i := a := i64.max-10
    b := i64.max

    to b-a+1 do
    println i++
    od


    The compilaton strategy we will likely pursue for this will be
    a bottom-of-the-loop test. That is to say, after executing
    an iteration, if x has the value n, then the loop terminates.

    Unfortunately, this pattern doesn't lend itself well to the
    for(;;) construct n C.

    The idiom for (x = m; x <= n; x++) only works when x may be
    incremented even when it is already equal to n.

    If the type is singned, like int, and n is INT_MAX, x++
    is undefined behavior after the last iteration.

    So this is part of the reason why for leaves everything open; the C programmer can hand-wave away these issues based on the specific use
    case of the loop, whose details are in the open, making it obvious that
    the idiom doesn't fully generalize to every corner case.

    The for construct could use a way of indicating a bottom test,
    like, oh, I don't know:

    for (decl/expr; : expr ; expr) // or some better way

    Here, the : means, jump unconditionally into the first iteration,
    and test expr after each iteration, before doing the increment.

    Then we can do

    for (int i = INT_MIN; : i < INT_MAX; i++)

    After the last iteration, i is INT_MAX, and so the test fails.
    The loop terminates without performing i++.


    You're trying too hard. I don't think the language needs to bother
    providing solutions, it just needs to specify the limitations.

    If the user needs to know about, and remember in the rare instance it
    comes up, dedicated language features, then the user can also come up
    with their own workarounds as I showed. Eg. in C:

    long long int i, a=INT_MIN, b=INT_MAX, n=0;

    for (i = a; i<=b; ++i) ++n;

    printf("%lld\n", n);

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Wed Apr 16 23:49:22 2025
    On 2025-04-16, bart <bc@freeuk.com> wrote:
    On 16/04/2025 22:43, Kaz Kylheku wrote:
    On 2025-04-16, bart <bc@freeuk.com> wrote:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?

    Hey Bart, how would you handle a loop like

    do x = m to n ...

    where m and n are not known until run time, and may be the
    extreme values of the type? Like C's INT_MIN and INT_MAX, respectively,
    where x is of type int.

    Because in this loop, x takes on every possible value of the type,
    we cannot have a loop guard which prevents entry of the loop body
    based on solely the value of x.

    I'm not exactly sure what you are asking. Is it a loop like this, here
    in my language:

    int n:=0

    for i in i32.bounds do # ie. i32.min .. i32.max
    ++n
    od

    println n

    This works fine; after a second or so it displays 4294967296.

    However, this languages evaluates using 64 bits. Perhaps this loop may demonstrate the issues better:

    for i in i64.bounds do

    However, I would estimate it would take 190 years to finish.

    Sure, but you could have a loop that goes over the last n
    values of the range of i64, for a reasonably small n.

    I assume you're thinking of C which uses i32 and where comparisons near
    the extreme values of the type are problemetical. Or this line in my

    Comparisons aren't; gratuitous increments or displacements are.

    language:

    for i in i64.max-10 .. i64.max do println i

    Exactly, small n.

    which doesn't stop (u64 is OK however).

    What? That's a boogy bug.

    That doesn't worry me too much,
    I can just add a Note to the language spec warning of UB when a for-loop bound is at the limits of the type.

    I will frame these words next time you cricize C of taking some
    easy way out and shirking doing the Right Thing with UB.

    Where all sorts of other stuff can
    happen because of how values wrap.

    You can fix all the other stuff at the language level also.

    Then we can do

    for (int i = INT_MIN; : i < INT_MAX; i++)

    After the last iteration, i is INT_MAX, and so the test fails.
    The loop terminates without performing i++.


    You're trying too hard. I don't think the language needs to bother
    providing solutions, it just needs to specify the limitations.

    I don't understand why you're not in the C camp with these words.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Thu Apr 17 00:59:25 2025
    bart <bc@freeuk.com> writes:
    On 16/04/2025 21:03, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:

    If you go back a few posts, Scott Lurndal was (1) trying to make out
    that all for loops consist of 3 elements like C;

    You again resort to misleading summaries. Classic Troll.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Thu Apr 17 01:48:48 2025
    On 17/04/2025 00:49, Kaz Kylheku wrote:
    On 2025-04-16, bart <bc@freeuk.com> wrote:

    language:

    for i in i64.max-10 .. i64.max do println i

    Exactly, small n.

    which doesn't stop (u64 is OK however).

    What? That's a boogy bug.

    (Yeah. Backend problem which hardcoded signed compared. 'for' iteration
    has its own IL instruction.)

    That doesn't worry me too much,
    I can just add a Note to the language spec warning of UB when a for-loop
    bound is at the limits of the type.

    I will frame these words next time you cricize C of taking some
    easy way out and shirking doing the Right Thing with UB.

    I can make it implementation-defined since the behaviour can be
    predicted on the targets I will use. But in the language, if the natural
    wrap on overflow gives unexpected results, then you have a program bug.

    I think what you were alluding to was the implicit increment used to
    implement for-loops. Well this is the IL instruction for FOR that I
    mentioned above:

    (kforup, ..), # B+:=n; goto L when B<=C

    The increment is part of its behaviour. At the language level, I could
    explain how FOR is implemented, but I'd rather not do that.

    A note that upper and lower limits must be in the range i64.min + s ..
    i64.max - s (where s is the step size) can suffice.

    What's far more useful is that it naturally works with i64 so has limits
    4 billion times bigger than you get with C's default 'int' type.

    Where all sorts of other stuff can
    happen because of how values wrap.

    You can fix all the other stuff at the language level also.

    How do you fix overflow of A * B?


    Then we can do

    for (int i = INT_MIN; : i < INT_MAX; i++)

    After the last iteration, i is INT_MAX, and so the test fails.
    The loop terminates without performing i++.


    You're trying too hard. I don't think the language needs to bother
    providing solutions, it just needs to specify the limitations.

    I don't understand why you're not in the C camp with these words.

    I am in the C camp (I said exactly that a few days ago). I just don't
    like the way the visible language was designed, and think there are too
    many unreasonable UBs.

    There are plenty of higher level languages that can deal with this
    properly (I guess; I haven't tried them).

    Although those that have copied C's 'for'-loop syntax are likely to be
    using the same kind of loop iteration that can cause a problem.

    Maybe the language can detect overflow, but it won't help, as you want
    to loop to stop not abort the program. So it is not a solution.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Thu Apr 17 02:09:29 2025
    On 17/04/2025 01:59, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 21:03, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:

    If you go back a few posts, Scott Lurndal was (1) trying to make out
    that all for loops consist of 3 elements like C;

    You again resort to misleading summaries. Classic Troll.

    You said exactly that:

    SL:
    Real for loops _are_ a three-way construct.


    You gave examples of BASIC and FORTRAN with 3 parts and compared to C
    with three parts.

    You're the fucking troll, mate.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Thu Apr 17 02:26:39 2025
    On 17/04/2025 01:26, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 21:03, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?
    Exactly, because "unusual" and "the majority" are the only
    possibilities.

    I'm not sure what you're getting at.

    I think the misunderstanding is over the meaning of the rather
    vague word "unusual".

    It seems to be happening a lot! SL is now claiming he never said what he
    did in fact say. JP has their own 'misunderstanding'. All trying to
    score some minor victory.

    Would it kill anybody here to admit I might be right about something or
    that I have a point?


    Did you really think that Janis was claiming that "the majority of
    loops in any given program will have steps other than +1 or -1"?

    Why don't you ask them to clarify?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Thu Apr 17 02:19:22 2025
    On 17/04/2025 00:49, Kaz Kylheku wrote:
    On 2025-04-16, bart <bc@freeuk.com> wrote:
    On 16/04/2025 22:43, Kaz Kylheku wrote:
    On 2025-04-16, bart <bc@freeuk.com> wrote:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?

    Hey Bart, how would you handle a loop like

    do x = m to n ...

    where m and n are not known until run time, and may be the
    extreme values of the type? Like C's INT_MIN and INT_MAX, respectively,
    where x is of type int.

    Because in this loop, x takes on every possible value of the type,
    we cannot have a loop guard which prevents entry of the loop body
    based on solely the value of x.

    I'm not exactly sure what you are asking. Is it a loop like this, here
    in my language:

    int n:=0

    for i in i32.bounds do # ie. i32.min .. i32.max
    ++n
    od

    println n

    This works fine; after a second or so it displays 4294967296.

    However, this languages evaluates using 64 bits. Perhaps this loop may
    demonstrate the issues better:

    for i in i64.bounds do

    However, I would estimate it would take 190 years to finish.

    Sure, but you could have a loop that goes over the last n
    values of the range of i64, for a reasonably small n.

    I assume you're thinking of C which uses i32 and where comparisons near
    the extreme values of the type are problemetical. Or this line in my

    Comparisons aren't; gratuitous increments or displacements are.

    OK, I've had a look in detail at the code I generate for for-loops.

    I believe it can be made to work with a test for equality instead of less-than-equal, with the increment done only if unequal. But it's
    slightly more elaborate.

    It works because, for variable limits for example, it already does a
    one-time "<=" check before it enters the loop.

    But there is a restriction: the loop index can't be changed by user code
    within the loop. (Otherwise it can have a value beyond the limit, and
    won't detect that.)

    As it happens, my loop indices are usually immutable, but not always. So
    the revised loop handling can be limited to the case when the index /is/ immutable.

    However, I'm not going to implement that. It's enough to know it is a possibility. This particular issue has not bothered me over 43 years of
    using <= compares, even when my ints were only 16 bits; I doubt it will
    bite any time soon.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Thu Apr 17 12:16:55 2025
    On 17/04/2025 03:18, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    The increment is part of its behaviour. At the language level, I could
    explain how FOR is implemented, but I'd rather not do that.

    Whereas for a language like C which is defined by a written standard,
    the standard *must* specify the behavior at the language level
    (not in terms of generated intermediate or machine code).


    At the language level, the behaviour of FOR loop variable iterating over
    A to B inclusive, simply has the variable assuming each of those values
    in turn. It doesn't say how it does that.

    However, it becomes more important if the language has anything to say
    about the value of the loop variable after the loop terminates (when its
    scope is not limited to the loop body as is the case in my language).

    Then the value might be B + step or B - step, depending on which way it iterates, using the current implementation.

    The fact that
    for (int i = INT_MAX-1; i <= INT_MAX; i++);
    has undefined behavior can be rigorously inferred from the language definition.

    A note that upper and lower limits must be in the range i64.min + s
    .. i64.max - s (where s is the step size) can suffice.

    What's far more useful is that it naturally works with i64 so has
    limits 4 billion times bigger than you get with C's default 'int'
    type.

    You know, of course, that C's int type is not necessarily 32 bits.
    There is no "default" for the width of int. If you had written "with
    32-bit int", that would have been clear and correct.

    I think it's perfectly reasonable for such discussions to assume 'int'
    is 32 bits. And to only qualify it only when it can matter.

    For computers in general, that assumption is likely to have held for at
    least 20 years, possible even 30.

    Or maybe you can tell me where I can buy a computer (not some board with
    an embedded microcontroller) where a C compiler for it has an 'int' type
    other than 32 bits (with either fewer bits, or more!).

    At present it only seems to bother you. Since if it REALLY bothered
    anyone here, nobody would be using 'int'; they'd be using int32_t or
    long, unless they're happy that their int values and intermediate
    calculations would be using only 16 bits.



    [...]

    Maybe the language can detect overflow, but it won't help, as you want
    to loop to stop not abort the program. So it is not a solution.

    If you want to implement, say, an Ada-style for loop, detecting
    overflow is not an issue at the language level. The issue is that
    for the following (I think the Ada syntax is clear enough):

    for I in Integer'Last-1 .. Integer'Last loop
    // whatever
    end loop;

    the language semantics specify that the body of the loop must be
    executed with I equal to Integer'Last-1, and then with I equal to Integer'Last. It's the compiler's job to figure out how to do that,
    either without triggering an overflow or by handling it cleanly enough
    that it doesn't change the behavior.

    Does it define what value I has when the loop terminates, or is the
    scope of I local to the loop body?

    C's for loop, which is both lower level and more flexible, does not
    impose that particular burden on the compiler. It's up to the
    programmer to ensure that a given for loop behaves as desired.


    My post a few hours ago said I'd found a way of getting better-defined behaviour, but I wasn't going to implement it.

    Well, I have done that test now. It replaces a "<=" compare with "==",
    and does the test before any incrementing.

    It seems to work. *But* it requires the loop variable to either be
    immutable (which it usually is in my language) or not be modified to
    have a value above B (for an A to B loop incrementing by +1).

    It also affects the value of the loop index after normal termination,
    since it will always be B, rather than B+1 etc.

    It's workable, but I'm a little happier with the way it was so that
    option is disabled.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to bart on Thu Apr 17 14:36:22 2025
    On 17/04/2025 12:16, bart wrote:
    On 17/04/2025 03:18, Keith Thompson wrote:

    If you want to implement, say, an Ada-style for loop, detecting
    overflow is not an issue at the language level.  The issue is that
    for the following (I think the Ada syntax is clear enough):

         for I in Integer'Last-1 .. Integer'Last loop
             // whatever
         end loop;

    the language semantics specify that the body of the loop must be
    executed with I equal to Integer'Last-1, and then with I equal to
    Integer'Last.  It's the compiler's job to figure out how to do that,
    either without triggering an overflow or by handling it cleanly enough
    that it doesn't change the behavior.

    Does it define what value I has when the loop terminates, or is the
    scope of I local to the loop body?

    My experiments show that:

    (1) Loop variables only have scope within the loop
    (2) Loop variables are read-only; they cannot be modified by user code

    This makes it much simpler to get the desired behaviour of a loop index iterating up to the maximum value of the type.

    So a comparison with other languages (either C or mine) is not that fair.

    Mine can be more restrictive, and I can make it more so (eg. restrict
    the scope of loop variables), but I have no interest in reimplementing Ada.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Thu Apr 17 20:18:59 2025
    On 17/04/2025 19:47, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:

    Or maybe you can tell me where I can buy a computer (not some board
    with an embedded microcontroller) where a C compiler for it has an
    'int' type other than 32 bits (with either fewer bits, or more!).

    Not the point. It's about what "int" *means*. It doesn't mean "a
    32-bit integer".

    At present it only seems to bother you. Since if it REALLY bothered
    anyone here, nobody would be using 'int'; they'd be using int32_t or
    long, unless they're happy that their int values and intermediate
    calculations would be using only 16 bits.

    POSIX and Windows both guarantee that int is at least 32 bits wide, and
    it's perfectly reasonable to rely on those guarantees on those platforms.

    It would be so easy for you to get this right, but you don't even
    acknowledge the possibility that I might have a valid point.


    It's an obscure, pedantic point.

    A better one is that if considering only Windows and POSIX (what about
    MacOS or Android?), then you admit int will be 32 bits (at least, but
    I'm not holding my breath for 64).

    That means that if either of those OSes are implied, then we can assume
    that 'int' means a 32-byte to near 100% likelihood.

    That saves thousands of posters having to qualify every reference to
    'int' with '[on POSIX or Windows]' or 'when it is exactly 32 bits'.

    That would be ironic if they have been making that assumption in their
    source code for years and decades, where it would be critical, but are
    not allowed to do so on long-running Usenet discusssions where it
    doesn't really matter.

    So, like you get tired of my keeping on defending my stances from
    attacks on multiple fronts, I get tired of having remember that some specialised hardware that runs C may have a 16-bit int or something
    equally unusual.

    In that case, why don't I save time by stating:

    * Whenever I mention 'int' type in the context of C, it means the
    32-bit type

    * If I intend it to mean anything other than that, I will say so.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Thu Apr 17 21:44:13 2025
    On 17/04/2025 20:55, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:

    Here's what you wrote upthread:

    What's far more useful is that it naturally works with i64 so has
    limits 4 billion times bigger than you get with C's default 'int'
    type.

    Here's what you could have written:

    What's far more useful is that it naturally works with i64 so has
    limits 4 billion times bigger than you get with 32-bit int.

    That's clearer, shorter, and correct, and would have avoided this
    entire subthread. I would not have commented on it.

    But it misses out the important bit. Clearly i64 has 2**32 times the
    range of i32; that will be the case in any context.

    What's relevant here is that my language's "don't care" 'int' type
    defaults to 64 bits, while C's 'int' type, on pretty much any PC from
    this century, will default to 32 bits.

    Which means people are more likely to encounter problems involving wrap,
    or UB.

    Whether C's 'int' should have moved to 64 bits on 64-bit machines has
    been discussed here in the past.

    That would have kicked such problems a /long/ way down the road.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Fri Apr 18 15:01:50 2025
    On 16.04.2025 16:31, bart wrote:
    On 16/04/2025 13:08, Michael S wrote:
    [...]

    When languages used to be 1-based, it was easy. Then 0-based came along,
    and typically iteration changed from 1..N inclusive, to 0..N-1 inclusive.

    You should be aware that [simple] linear iterations are conceptually
    coupled to arrays. The choice of 0-based arrays and thus iterations is
    "useful" for compiler creators of such languages. They allow without
    overhead and skill for optimization an efficient array access.

    [...]

    Oh, now you could interpret a written above as statement of superiority
    of C syntax. So, no, it is not. Those are *minor* points.

    Here's some C code to print the elements of an array:

    static char* table[] = {"one", "two", "three", "four", "five"};

    for (int i=0; i<sizeof(table)/sizeof(table[0]); ++i)
    printf("%d %s\n", i, table[i]);

    (This all exposes quite clearly the low-level characteristics of "C".)

    And here is how I'd write it using the 'minor' advantages of my syntax:

    static []ichar table = ("one", "two", "three", "four", "five")

    for i, s in table do
    println i, s
    end

    To me, the differences in that for-loop are like chalk and cheese.

    Sure, many language support newer syntaxes for such things. Even older languages do such abstractions; e.g. Awk[*]

    split ("one two three four five", table)
    for (i in table)
    print i, table[i]

    (One of many things I like in this very small but powerful language.)


    (Note that the latter is 1-based, but it is not apparent in the code;
    the outputs are numbered 1 to 5. The C is zero-based, and that has to be specified. The outputs are numbered 0 to 4.

    Moreover, I could have specified a different array base, and the loop
    remains unchanged.)

    Janis

    [*] Read it as "GNU Awk", since in that variant (as opposed to standard
    Awk) you can control the 'for' iteration order.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Scott Lurndal on Fri Apr 18 15:06:13 2025
    On 16.04.2025 16:21, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:


    So here, 0% of such loops have a step other than 1. THAT's what I mean
    by 'unusual'.

    Sample bias.


    Scot Lurndal gave examples comparing C with BASIC/FORTRAN that used
    steps other than one, to back up a claim that they routinely use 3
    components. Actually they rarely do.

    I made no such claim. You said that for loops were not three-way
    constructs - I showed that was not an accurate statement. I made
    no claims about anything being 'routine'.

    A common construct:

    entity *ep = entities[0];
    for(size_t i = 0ul; i < MAX_ENTITIES; i++, ep++) {
    ep->field = do_something(args);
    }

    in C++

    for(x = map.begin(); x != map.end(); ++x) {
    /* process a red-black tree element */
    }


    There's also some other options in C++, say, STL's [functional]
    'for_each()' or, in the newer standards, the variant we already
    saw upthread mentioned as one hiding some "technical details".

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Fri Apr 18 14:41:02 2025
    On 16.04.2025 13:32, bart wrote:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.
    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?

    No. I am saying that there's many ways to define and use 'for' loops,
    and specifically "C" allows (by using an inherent primitive syntax)
    to formulate many useful constructs that are also used regularly in
    those languages that support such constructs.

    As an implied consequence of that you may derive that if you use only
    languages that don't support such constructs you must emulate them in
    other ways in those languages. (This will naturally not be directly
    countable in your preferred statistics.)

    Also if you are using a language with more flexible 'for' loops but
    you are not using that flexibility - because you haven't learned it,
    you just don't grok it, or deliberately abstain from it because, say,
    of some dogma that 'for' loops are only "real" 'for' loops if you use
    them just in sequential traversing of integers with increments of 1 -
    that you will also not see them.

    [...]

    But never, mind, C's for-loop will still be the most superior to
    everybody here.

    (I cannot speak for "everybody" as you seem to prefer.)

    My own opinion I already stated more than one time; it boils down to:
    I dislike "C" syntax in general. I like the flexibility of "C". The
    latter is part of the reason why I use that syntactically "inferior"
    language in some private programming.

    I'd have an easier time arguing about religion!

    (But you are arguing all the time in a religious manner already.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Keith Thompson on Fri Apr 18 15:37:26 2025
    On 17.04.2025 02:26, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 21:03, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?
    Exactly, because "unusual" and "the majority" are the only
    possibilities.

    I'm not sure what you're getting at.

    I think the misunderstanding is over the meaning of the rather
    vague word "unusual".

    Did you really think that Janis was claiming that "the majority of
    loops in any given program will have steps other than +1 or -1"?

    The "majority" is as a typical phrase introduced by bart as sort of
    substitute for an argument. (I usually avoid claims about presumed "majorities", about what "all" or "most" people here or everywhere
    else do.)

    It can be easily looked up what I wrote; but bart regularly just
    moves goalposts when he's lost, instead of accepting the obvious
    facts (or other opinions based on experiences or else).

    To reformulate (from memory) some basics I actually said...

    Statistics of 98% for simple loops are close to reality, IMO.
    Increments of +1/-1 were the rationale for Pascal's decision to
    support just such primitive loops.[*]
    You are lacking flexibility with only such primitive loops.
    Many language provided support more more types of useful loops.
    "C" loops have a flexibility that I appreciate and that I use.
    Statistical numbers have obviously changed for non-simple loops
    for languages that allow such usages.
    (...and maybe some more that I don't recall any more.)

    Janis

    [*] I'd like to take the opportunity to say that Pascal supports
    more than just simple "counted" loops; you can also iterate over
    any "scalar"[**], say, if you have an 'enum' type "red,blue,green"
    you can iterate from "red" to "green".

    [**] "Scalar" with non-mathematical meaning; every countable type.

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Fri Apr 18 15:34:28 2025
    On 18/04/2025 14:01, Janis Papanagnou wrote:
    On 16.04.2025 16:31, bart wrote:
    On 16/04/2025 13:08, Michael S wrote:
    [...]

    When languages used to be 1-based, it was easy. Then 0-based came along,
    and typically iteration changed from 1..N inclusive, to 0..N-1 inclusive.

    You should be aware that [simple] linear iterations are conceptually
    coupled to arrays. The choice of 0-based arrays and thus iterations is "useful" for compiler creators of such languages. They allow without
    overhead and skill for optimization an efficient array access.

    [...]

    Oh, now you could interpret a written above as statement of superiority
    of C syntax. So, no, it is not. Those are *minor* points.

    Here's some C code to print the elements of an array:

    static char* table[] = {"one", "two", "three", "four", "five"};

    for (int i=0; i<sizeof(table)/sizeof(table[0]); ++i)
    printf("%d %s\n", i, table[i]);

    (This all exposes quite clearly the low-level characteristics of "C".)

    It highlights three things that C manages to make quite a meal out of,
    despite them being trivially fixable even in such a low-level language:

    * The for-loop as has been discussed at length

    * Getting at the length of a fixed-size array

    * Needing to use format codes to print things

    (I don't want to know how you can use macros to mitigate some of these;
    at that point it's already failed.)


    for i, s in table do
    println i, s
    end

    To me, the differences in that for-loop are like chalk and cheese.

    Sure, many language support newer syntaxes for such things. Even older languages do such abstractions; e.g. Awk[*]

    split ("one two three four five", table)
    for (i in table)
    print i, table[i]


    (One of many things I like in this very small but powerful language.)

    I had to check your claims:

    * Awk primarily uses a C-style for loop; using 'for in' is an
    alternative (it's not clear if this is specific to gnu-Awk)

    * 'i in table' iterates over /indices/, not values as is more typical of languages that support 'in'.

    (In my stuff, I'd need 'i in table.bounds' to get at the indices, or use
    an auxiliary loop variable as shown above.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Fri Apr 18 15:19:35 2025
    On 18/04/2025 14:37, Janis Papanagnou wrote:
    On 17.04.2025 02:26, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 21:03, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 16/04/2025 06:35, Janis Papanagnou wrote:
    On 15.04.2025 22:46, bart wrote:
    On 15/04/2025 20:07, Scott Lurndal wrote:
    [...]
    Real for loops _are_ a three-way construct.

    [...]

    Any step other than 1 is unusual. [...]

    Nonsense. Arithmetic loop steps other than one are noting unusual
    and been supported by programming languages (and also been used)
    since decades in programming.

    So what are you claiming, that the majority of loops in any given
    program will have steps other than +1 or -1?
    Exactly, because "unusual" and "the majority" are the only
    possibilities.

    I'm not sure what you're getting at.

    I think the misunderstanding is over the meaning of the rather
    vague word "unusual".

    Did you really think that Janis was claiming that "the majority of
    loops in any given program will have steps other than +1 or -1"?

    The "majority" is as a typical phrase introduced by bart as sort of substitute for an argument. (I usually avoid claims about presumed "majorities", about what "all" or "most" people here or everywhere
    else do.)

    It can be easily looked up what I wrote; but bart regularly just
    moves goalposts when he's lost, instead of accepting the obvious
    facts (or other opinions based on experiences or else).

    To reformulate (from memory) some basics I actually said...

    Statistics of 98% for simple loops are close to reality,

    I haven't been able to find that post. In any case, it was not in the
    sequence of posts stemming from this one:

    * Scott Lurndal (SL) makes a claim that all 'real' for-loops have 3
    parts, like C's for(A; B; C) [point 1]

    * He gave example of such loops in C, Basic and Fortran ...

    * ... but used a step of +2 in those Basic and Fortran examples in
    order to contrive to give them a third part [point 2]

    This is where I complained that such a step in Basic and Fortran was
    'unusual' (in fact it's so rare then I wasn't even sure of the syntax),
    and which you called out as 'Nonsense'.

    Later on:

    * SL posts an example of 2-part C for-loop, which contradicts his claim
    of all 'real' for loops having 3 parts [point 3] ...

    * ... which also turns out to be highly incorrect [point 4]

    What's puzzling me is this: why are letting those Points 1, 2, 3 and 4
    go, but aiming all of your criticisms at me?

    In fact you're still at it! Eg: "but bart regularly just moves
    goalposts". So SL didn't move goalposts?

    Regarding Point 4, nobody picked up on it except for Michael S.

    Not you, nor KT or JK who are usually pedantic about such matters.

    Yet I state something which is actually correct, you call that nonsense,
    and everybody defends you and slams me!

    Clear persecution, gaslighting, or both?

    Please take a close look at your posting decisions: why you consistently
    attack my posts, but let dubious posts from others slide.


    IMO.
    Increments of +1/-1 were the rationale for Pascal's decision to
    support just such primitive loops.[*]
    You are lacking flexibility with only such primitive loops.
    Many language provided support more more types of useful loops.
    "C" loops have a flexibility that I appreciate and that I use.
    Statistical numbers have obviously changed for non-simple loops
    for languages that allow such usages.

    This is 'my' flexible loop:

    do
    ....
    od

    Add whatever you like in place of ....

    C doesn't have a dedicated endless loop; it has to be either while(1) or (again!) for(;;). It might seem a small point, but it means I
    acknowledge the importance of such a fundamental construct. It also
    shows I don't don't consider it either a 'while' loop, or a 'for'.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to All on Fri Apr 18 16:57:24 2025
    On 16.04.2025 11:45, Rosario19 wrote:
    On Tue, 15 Apr 2025 09:25:40 +0200, Janis Papanagnou wrote:

    On 15.04.2025 06:57, Rosario19 wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    Sure. Or all done with Turing machines. - But why would one want to.

    because one not has the for loop, because is need more flexibility in
    what code has to make, because one find so easy goto label, that it is
    easier of the loop for, even if i think in 80% of cases for loop is
    less chars and easier of the loop that use goto label

    (Note my question above was rhetorical. - Turing machine programs is
    not something you should consider as scale for what we usually do in programming.)

    Of course, if all you have is an assembler language then "all" you
    have are jumps. (Note: again an accentuated formulation of the point,
    but I'm confident you understand what I'm trying to say.)

    If, for common loop conditions, it's easier for someone to use gotos
    than to use typical loop constructs then I suggest that this person
    should not apply for a programmers' job.

    The "number of characters" in a syntactical construct is IMO not the
    most relevant or primary factor. But abstractions in languages often
    coincide with much terser formulations. And abstractions is what aids
    in programming non-trivial systems. I would abstain from gotos, but
    because of the "number of characters" to type or to spare.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Fri Apr 18 16:40:00 2025
    On 16.04.2025 13:01, bart wrote:
    On 16/04/2025 06:19, Janis Papanagnou wrote:
    On 15.04.2025 12:30, bart wrote:

    (One of your fundamental problems with "C" seems to be to understand
    the 'for' keyword meaning only counted loops with one variable and a
    simple +1 increment. - I can't help you here.)

    And your problem seems to the opposite: being unable to understand that for-loop (perhaps spelled 'do') can be a specialised feature to iterate
    one or more variables over a predetermined range or set of values.

    Why do you think so? - I've given enough examples where you could
    have easily seen that I'm able to take advantage for my programming
    of any loop concept that languages provide, and I've done so, from
    Pascal's simple forms, over Simula and Algol 68 loops, to "C"/C++
    loops and loop algorithms, or Unix Shell's or Awk's loop constructs.

    But if I'd want to use some flexibility of one language and don't
    have it available in another language I'll have to work around it.
    And, vice versa, if I have that flexibility, why not use it.


    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    It's nothing to do with hope. (Your religious approach here is not
    very useful if you want to work as [or become] a serious programmer.)
    If you are intellectually incapable of managing "C" loops I cannot
    help you. - But I have sympathy for you, and can feel your pain if
    you're programming in "C" given what you are repeatedly complaining
    about.


    Everyone here is defending the latter to the death. Why? Apparently the
    ONLY argument is 'flexibility'.

    Why do you think so? - Flexibility is what "C"'s loop provides; it's
    one of the strengths of this loop. - Your agenda and opinion on that
    seems to be different, you certainly cannot see or acknowledge that
    flexibility and instead try to invalidate that fact repeatedly by
    red herrings.

    I see that you're priorities are, as you've shown, for example, how
    many characters you have to type, or whether you have do..od syntaxes
    available as part of the language.

    I cannot believe that you never used any of the possibilities that
    "C" loops provide us. But okay, it's anyway meaningless what you do.


    Having to writing a simple iteration in such a convoluted and unchecked manner is much better because - you can use the same syntax to iterate
    over a list!

    I understand that you want a primitive loop being available. - And
    if that's such a pain that "C" doesn't have it I'd suggest you to
    switch to another language; for your private stuff you can do what
    you like, there's no prerequisites or boundary conditions imposed
    upon you.


    I've written code where the logic required comparisons of i < N-1
    and also i <= N . So what? - Should I not do that because you are
    getting confused when inspecting my code?


    This is worrying. So you have a bunch of code with multiple like this:

    for (i=0; i<N; ++)
    for (i=0; i<N; ++)
    for (i=0; i<=N; ++)
    for (i=0; i<N; ++)

    No. I have written code as I wrote it - still quoted above - not as
    you made it up. I haven't said anything else about it. - Only that I
    have no issues to apply every form as algorithmic demands require it.


    And you notice one has <= while the others have <. But according to you,
    this is nothing remarkable and raises no flags. Obviously the author
    intended to iterate one more time there!

    Yes, different contexts require different implementations.

    (It appears strange to me that your programs look all the same. And,
    honestly, I cannot believe that; I think you're as usual just making
    that up.)


    With language-supported iteration, the comparison operator is not
    exposed, so the programmer cannot accidentally type the wrong one.

    Obviously.


    (I see I have ++ and not ++i; never mind. It is telling that it took me
    a minute to notice!)

    Get some glasses?

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Fri Apr 18 16:58:27 2025
    bart <bc@freeuk.com> writes:
    On 18/04/2025 14:37, Janis Papanagnou wrote:


    * Scott Lurndal (SL) makes a claim that all 'real' for-loops have 3
    parts, like C's for(A; B; C) [point 1]

    Again you mischaracterize what was stated. I simply
    pointed out that most major programming languages have three component
    looping constructs using the 'for' keyword, including C.

    I made no claim about which percentage of real-world uses of the
    'for' construct used all three parts.

    I do think your constant harping on a well-established and widely-used
    language that will never change to satisfy your personal idiosyncrocies
    is rather pointless, other than simple trolling.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Fri Apr 18 18:27:44 2025
    On 18/04/2025 17:58, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 18/04/2025 14:37, Janis Papanagnou wrote:


    * Scott Lurndal (SL) makes a claim that all 'real' for-loops have 3
    parts, like C's for(A; B; C) [point 1]

    Again you mischaracterize what was stated. I simply
    pointed out that most major programming languages have three component looping constructs using the 'for' keyword, including C.

    Apart from C, simple iteration via a loop index has 4 things that need
    to be denoted:

    - Some keyword to say this is such a loop

    - The loop index variable

    - The start value

    - The end value

    Many can have an /optional/ step (or means to reverse the order) in the
    odd cases where that is necessary, making 4/5 if you want to be formal.

    C is quite different; it is merely 3 arbitrary expressions, the middle
    one of which is used as a loop terminating condition (tested notionally
    at the start of the loop).

    But in cases where it is used to emulate the kind of loop described
    above, then the same applies, except that:

    - It will always be 5 parts (the step always has to be accounted for)

    - Nearly everthing about how it works has to be imparted to the
    compiler:
    - The actual expression to initialise the variable
    - The exact expression used for the terminating condition
    - The exact expression used for incrementing to loop index

    - The end value that appears in the terminating condition is
    frequently offset (also can also be the case in real for-loops
    used in 0-based languages)

    - A loop which counts down may well have a quite different pattern
    from an upward counting one

    So a comparison between C for-loops and more formal ones is not that meaningful.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Fri Apr 18 14:10:13 2025
    On 16.04.2025 13:01, bart wrote:
    ...
    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your responsibility for all of the other expressions that make up your
    program. If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Fri Apr 18 23:27:37 2025
    On 18/04/2025 19:10, James Kuyper wrote:
    On 16.04.2025 13:01, bart wrote:
    ...
    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your responsibility for all of the other expressions that make up your
    program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it
    with this group?

    My remarks were about what C call's 'for', being a very low level
    construct, even at this level of language.

    The language will not check that those three parts are correct for the
    loop you are trying to express, because there is no way for it to know that.

    So that if you do make a mistake, it can't help you, unless it fails incidentally for some other reason. This is where you cannot rely on the compiler, and hence my remark.

    See recent posts by JP where they used "<=" instead of "<", and by LP
    where they used "N" instead of "N-1".

    So, yes, I think that is problematic, and the fault is with the
    language. This stuff isn't not hard to get right; even BASIC manages to FOR-loops properly.

    It's a bit of a cheek to suggest that if people tend to make more compiler-undetectable errors because C's FOR is dumb, that they should
    give up programming.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sat Apr 19 08:27:36 2025
    On 19.04.2025 00:27, bart wrote:
    On 18/04/2025 19:10, James Kuyper wrote:
    On 16.04.2025 13:01, bart wrote:
    ...
    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your
    responsibility for all of the other expressions that make up your
    program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it
    with this group?

    You have been repeatedly hinted that the problems you have are
    primarily on your side. You're constantly blaming the language.
    You are obviously incapable of writing correct "C" code.

    You still don't get it that *you* are the biggest obstacle to
    your success. And that you're repeating your whining about "C"
    and everything instead of stop posting tons of repetition, and
    instead thinking about what's said. Or just learning the basics
    would be more advantageous to you. - But you decided to continue
    your nonsense instead, as we see below.


    My remarks were about what C call's 'for', being a very low level
    construct, even at this level of language.

    Certainly not "very low" (compared, e.g., to gotos) but not as
    abstract as in other HLLs; we all know that, and also explicitly
    stated that many many times. Why are you to stubbornly ignoring
    the facts that were written and stated.


    The language will not check that those three parts are correct for the
    loop you are trying to express, because there is no way for it to know
    that.

    Yes. Because "C" loops are different from other loop concepts. And
    the "three parts" are semantically not related. Accept that if you
    intend to program in "C".


    So that if you do make a mistake, it can't help you, unless it fails incidentally for some other reason. This is where you cannot rely on the compiler, and hence my remark.

    You can make mistakes in every language and in every communication
    and anywhere else. - Your postings are a source of mistakes, and
    the bad thing is not the mistakes; it is that you are *repeating*
    your mistakes on and on.


    See recent posts by JP where they used "<=" instead of "<", and by LP
    where they used "N" instead of "N-1".

    If you mean my post where I said "all points proven"...

    I copy/pasted code from your post, but selected the wrong example.
    After posting and rereading I immediately noticed that and corrected
    that. - This was no "C" loop issue, it was a text copy/paste issue.
    It was _my_ [copy/paste] mistake (not a "C" language design mistake).

    Do you understand that? - If not try to not instantly write another
    post but first take 10 minutes to understand what was written.


    So, yes, I think that is problematic, and the fault is with the
    language. This stuff isn't not hard to get right; even BASIC manages to FOR-loops properly.

    As so often explained to you, BASIC has a most primitive loop.[*]
    If that's all you can intellectually handle you're obviously a lousy
    programmer (and far from a software engineer).

    It could be so simple; don't use "C" and all your problems are gone.
    (Well, at least all your "C" related problems.)

    [*] And the implementations I recall also didn't get implementation
    correct for use with real-valued loops. (Just BTW.)


    It's a bit of a cheek to suggest that if people tend to make more compiler-undetectable errors because C's FOR is dumb, that they should
    give up programming.

    If you cannot handle elementary things you should give up programming.
    (Or use it for your personal purposes only and stop bothering other
    people with your personal problems.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sat Apr 19 09:09:00 2025
    On 18.04.2025 19:27, bart wrote:
    [...]

    C is quite different; it is merely 3 arbitrary expressions, the middle
    one of which is used as a loop terminating condition (tested notionally
    at the start of the loop).

    They're not "arbitrary".

    They are chosen by the software designer to fulfill the demands.
    You've already and often demonstrated that you have problems to
    grok non-trivial loops. But I'll anyway support you with another
    example (here from C++, but the principle is the same)

    for (unsigned int i = 0; aa.notEmpty(); i++)
    for (Arabic a = a2r_tab[i].arabic;
    aa.contains(a);
    aa.remove(a))
    r += a2r_tab[i].roman;

    for (unsigned int i = 0; rr.notEmpty(); i++)
    for (Roman r = r2a_tab[i].roman;
    rr.contains(r);
    rr.remove (r))
    a += r2a_tab[i].arabic;

    All elements in the nested loops are algorithmically connected,
    they are not "arbitrary". - I don't expect that (without context
    or comments) anyone understands that; the point is that you just
    cannot formulate the algorithm with primitive loops. And another
    point is that these algorithms are using these _equivalent_ loop
    hierarchies despite working on completely different data types,
    so the (for you probably perceived as unrelated) interconnection
    of the loop elements in the loop hierarchy is meaningful.

    So I think above you meant to say that the loop expressions are
    not "tightly coupled". - Yes, they are not, and thus can be used
    in more advanced algorithmic contexts.

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sat Apr 19 09:20:30 2025
    On 18.04.2025 16:34, bart wrote:
    On 18/04/2025 14:01, Janis Papanagnou wrote:

    Sure, many language support newer syntaxes for such things. Even older
    languages do such abstractions; e.g. Awk[*]

    split ("one two three four five", table)
    for (i in table)
    print i, table[i]


    (One of many things I like in this very small but powerful language.)

    I had to check your claims:

    * Awk primarily uses a C-style for loop; using 'for in' is an
    alternative (it's not clear if this is specific to gnu-Awk)

    The 'in' loop was always available and is also POSIX standard.

    My footnote (you stripped it)....

    [*] Read it as "GNU Awk", since in that variant (as opposed to standard
    Awk) you can control the 'for' iteration order.

    ...pointed to a non-standard GNU extension how to iterate over Awk's associative arrays; the standard provides no guarantee about the order
    of traversal. GNU Awk allows to iterate in various ways; by index or
    by value, in numeric or alphabetic order, ascending or descending.
    These options are a very useful extension.


    * 'i in table' iterates over /indices/, not values as is more typical of languages that support 'in'.

    Yes. - But see what I wrote about traversal options in GNU Awk.

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sat Apr 19 11:26:11 2025
    On 19/04/2025 07:27, Janis Papanagnou wrote:
    On 19.04.2025 00:27, bart wrote:

    So, yes, I think that is problematic, and the fault is with the
    language. This stuff isn't not hard to get right; even BASIC manages to
    FOR-loops properly.

    As so often explained to you, BASIC has a most primitive loop.[*]

    As has been so often pointed out, the vast majority of iterating loops
    can be accommodated by 'for i = a to b'. So in that case it is not
    primitive.

    However C's for-loop genuinely *IS* primitve.

    If that's all you can intellectually handle you're obviously a lousy programmer (and far from a software engineer).

    Do you undertand my reasons for saying what I do?

    Suppose that C had both its primitive loop, and one like Basic's (or
    like Awk's); would that be better? If so, why?

    In fact, WHY does Awk have that other kind of loop? Since the primitive
    form can express it just as well.

    What are the advantages? Say somebody said, if you can't express a loop
    using C-style, and need to rely on 'for-in', then you're a lousy programmer.

    Let's go the other way and say C had no loops at all, and somebody
    advocating for loop statements was told that if they couldn't handle
    'if', 'goto' and labels, then *they* were a lousy programmmer?

    Your arguments are ludicrous, sorry.

    Effectively you are arguing for there to be no higher level languages,
    because anyone who wants them must also be incapable of understanding
    and using what there is.


    It could be so simple; don't use "C" and all your problems are gone.
    (Well, at least all your "C" related problems.)

    Ha! I generally don't.

    The 1% of my coding that involves actual C is enough.

    If you cannot handle elementary things you should give up programming.

    I've written many 10s of 1000s of lines of assembly. But I prefer HLL
    code, and HLL code which has some must-have fundamentals. Like a fucking
    loop that works.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sat Apr 19 13:32:15 2025
    On 19.04.2025 12:26, bart wrote:
    On 19/04/2025 07:27, Janis Papanagnou wrote:
    On 19.04.2025 00:27, bart wrote:

    So, yes, I think that is problematic, and the fault is with the
    language. This stuff isn't not hard to get right; even BASIC manages to
    FOR-loops properly.

    As so often explained to you, BASIC has a most primitive loop.[*]

    As has been so often pointed out, the vast majority of iterating loops
    can be accommodated by 'for i = a to b'. So in that case it is not
    primitive.

    Why is that not primitive? It is about the most restricted loop
    concept one can think of; I'm doing hard to imagine a yet more
    primitive one. All other loops pointed out that far (Algol 68,
    Simula, "C") allow more complex (less primitive) loop constructs.


    However C's for-loop genuinely *IS* primitve.

    Yet has higher expressiveness. We disagree what "primitive" means;
    so it's hard to continue the discussion below since we're speaking
    different languages, obviously.

    I cannot program non-trivial or complex loops with Pascal or BASIC,
    they are too restricted (to just one application way), they're too
    primitive. We've provided many examples in this thread.

    While "C" based its loop on primitive building blocks (statements
    and conditions) you can use in the loop all sorts of concrete "C"
    building blocks, including an assignments for the initializations
    and an increment for the next iteration; as support of a special
    case for the simple, primitive forms as found in other languages.

    [...]

    Suppose that C had both its primitive loop, and one like Basic's (or
    like Awk's); would that be better? If so, why?

    The BASIC dialects I know of supported only one type of loop; the
    simple arithmetic loop. As opposed to Pascal's loop it's possible
    to iterate over real arithmetic ranges, though, but that's it.

    Awk decided to support two types of loops. The 'in' loop is the
    "normal" loop (the arithmetic loop is, for reasons obvious to me,
    the extension); since Awk supports only one data structure, namely
    associative arrays (and no indexed arrays) you need some iteration
    construct that iterates over the keys; "for (key in array)". The
    arithmetic loop is there because functions like 'split()' create
    associative entries with keys "1", "2", etc. (not numeric indices
    1, 2, etc.). But with the implicit type coercion an arithmetic
    'for' loop numbers get converted to strings used as key in Awk's
    associative arrays. Awk is a higher level language than "C" is,
    its array type is more powerful than the indexed arrays we find
    in "C". So there's different requirements.

    I understand that the "C" language designers decided to not provide
    some additional form of loops; that's IMO a sensible decision given
    what low-level language "C" is. To define its loops in a flexible
    form by building blocks as we know them from other places in the
    "C" language makes perfectly sense.

    I don't need a second loop in "C". I know it would help you to not
    make the errors you seem to regularly make as you say.


    In fact, WHY does Awk have that other kind of loop? Since the primitive
    form can express it just as well.

    No. You have a complete misconception about that. In all respects.
    Read what I explained above to get some clue about Awk.

    [...]

    Effectively you are arguing for there to be no higher level languages, because anyone who wants them must also be incapable of understanding
    and using what there is.

    (I don't understand what you write here. But what you think is anyway meaningless here since I already _wrote_ what I _intended_ to say and
    that needs no (mis-)interpretation of you.)

    [...]

    I've written many 10s of 1000s of lines of assembly. But I prefer HLL
    code, and HLL code which has some must-have fundamentals. Like a fucking
    loop that works.

    Fine. I can completely understand your desire of using HLLs. That's
    what I like as well, HLLs. - Just give up considering "C" a HLL and
    stop asking about pointless abstractions in "C". - As opposed to Awk
    you don't have associative arrays that make an 'in' loop necessary,
    and you can do anything with "C" loops that is necessary, much more
    than with some other languages' (of higher level or not) restricted
    loops. You may not make use of "C"'s loop flexibility, you may not
    need it for your application cases, yet it's something that's very
    useful (as shown in many examples). If you can't handle "C" loops
    don't use that language. Why are you here, in CLC; just to complain?

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sat Apr 19 14:05:05 2025
    On 19/04/2025 12:32, Janis Papanagnou wrote:
    On 19.04.2025 12:26, bart wrote:
    On 19/04/2025 07:27, Janis Papanagnou wrote:
    On 19.04.2025 00:27, bart wrote:

    So, yes, I think that is problematic, and the fault is with the
    language. This stuff isn't not hard to get right; even BASIC manages to >>>> FOR-loops properly.

    As so often explained to you, BASIC has a most primitive loop.[*]

    As has been so often pointed out, the vast majority of iterating loops
    can be accommodated by 'for i = a to b'. So in that case it is not
    primitive.

    Why is that not primitive? It is about the most restricted loop
    concept one can think of;

    With the optional step (which is so uncommonly used that I'd forgotten
    it even had it), it handles the vast majority of loops where you want a variable to iterate over a range.

    That includes everything that Algol68 loops do that use 'for'. ('While'
    is an early exit that can achieved with if/goto, but is anyway a feature
    of 'for' that is uncommon.)


    I'm doing hard to imagine a yet more
    primitive one. All other loops pointed out that far (Algol 68,
    Simula, "C") allow more complex (less primitive) loop constructs.

    C, really?

    I don't understand why you're happy using a crippled looping mechanism,
    that is a PITA to use for the majority of iterating loops, just so you
    have that flexibility for the whacky loops that are in the minority,
    most of which can be trivially expressed with 'while'.



    However C's for-loop genuinely *IS* primitve.

    Yet has higher expressiveness.

    So has 'if' and 'goto'. (I think we've been here before!)


    We disagree what "primitive" means;
    so it's hard to continue the discussion below since we're speaking
    different languages, obviously.

    I'll tell you a secret: a few years ago, I also added a C-style 'for'
    statement to my language. So it had two kinds of 'for' that looked like
    this:

    for i in a..b do # also for i[:=a] to b do

    cfor A, B, C do # A B C are arbitrary expressions

    This was because I'd got fed up with people telling me all these
    wonderful things that C's for could do, that I couldn't. So now I could
    do the same!

    But it eventually got dropped as /it was never used/. Why would it? I
    already head the dedicated 'for' for iterations. To express the above
    loop using 'cfor' meant writing:

    cfor i := a, i <= b, ++ i do

    Four extra lots of info (2nd i, <=, ++, 3rd i) , which I needed to get
    just right. No thanks.

    If you were me, would you have instead have got rid of the dedicated
    'for', and kept only 'cfor'? Be honest!

    Since that is exactly what you have been saying about C's 'for'; you
    don't /want/ a better 'for' in C, even if it was in addition to the
    current 'for': 'there is nothing wrong with latter, and anyone who can't
    hack it should give up programming'.




    I understand that the "C" language designers decided to not provide
    some additional form of loops; that's IMO a sensible decision given
    what low-level language "C" is.

    Mine is too. The original version was even lower level and simpler and
    smaller, but it still had PRINT and FOR.


    To define its loops in a flexible
    form by building blocks as we know them from other places in the
    "C" language makes perfectly sense.

    I don't need a second loop in "C". I know it would help you to not
    make the errors you seem to regularly make as you say.

    Lots of people do.



    In fact, WHY does Awk have that other kind of loop? Since the primitive
    form can express it just as well.

    No. You have a complete misconception about that. In all respects.

    Really? So why does this work:

    split ("one two three four five", table)

    for (i=1; i<=5; i++)
    print i, table[i]

    I thought you said Awk didn't support indexed arrays? (Wrap in 'BEGIN
    {...}' for a complete program.)

    don't use that language. Why are you here, in CLC; just to complain?

    I'm here to understand why people are deifying C and its crude for-loop
    by arguing that black is white:

    do i = 1,10 # 'primitive'
    for(i=1; i<=10; ++i) # 'advanced'

    But then at the same some are saying that:

    'for' i 'from' 1 'to' 10 'do'

    from Algol68 is advanced (because you can stick 'while' in there?).

    It's a fascinating. I guess the answers are more psychological than
    otherwise.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Sat Apr 19 14:35:57 2025
    bart <bc@freeuk.com> writes:
    On 18/04/2025 19:10, James Kuyper wrote:
    On 16.04.2025 13:01, bart wrote:
    ...
    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your
    responsibility for all of the other expressions that make up your
    program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it
    with this group?

    It's not an insult, it is a simple fact.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Sat Apr 19 16:24:04 2025
    On 19/04/2025 15:35, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 18/04/2025 19:10, James Kuyper wrote:
    On 16.04.2025 13:01, bart wrote:
    ...
    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your
    responsibility for all of the other expressions that make up your
    program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it
    with this group?

    It's not an insult, it is a simple fact.


    No, it's not.

    Someone points out problems with a poor, open-ended feature in a
    language, which could be alleviated by a more focused version that has
    been proven in countless other languages since the 1950s.

    But no, that can't be possibly be the case with 'our' wonderful
    language. Clearly the person pointing out the obvious is incapable of
    being a programmer.

    That should be left to the people suggesting:

    for(i = 1; i++ <= 10;)

    for a loop where the index is supposed to do the same as in Fortran's 'primitive' "do i = 1, 10".

    So you are talking bollocks.

    I wouldn't go so far as to suggest that you or anyone else gives up
    programming (I might only think that privately), but I would say stay
    miles away from any kind of PL design.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Sat Apr 19 16:28:25 2025
    On 2025-04-19, bart <bc@freeuk.com> wrote:
    On 19/04/2025 07:27, Janis Papanagnou wrote:
    On 19.04.2025 00:27, bart wrote:

    So, yes, I think that is problematic, and the fault is with the
    language. This stuff isn't not hard to get right; even BASIC manages to
    FOR-loops properly.

    As so often explained to you, BASIC has a most primitive loop.[*]

    As has been so often pointed out, the vast majority of iterating loops
    can be accommodated by 'for i = a to b'. So in that case it is not
    primitive.

    However C's for-loop genuinely *IS* primitve.

    The abstraction level difference is very small between a loop which
    supplies only holes where you plug in your tests and increments, and a
    loop which sets up the tests and increments.

    (In this particular case, we can macro over the difference with
    a primitve token-replacing preprocessor.)

    If that's all you can intellectually handle you're obviously a lousy
    programmer (and far from a software engineer).

    Do you undertand my reasons for saying what I do?

    Suppose that C had both its primitive loop, and one like Basic's (or
    like Awk's); would that be better? If so, why?

    We've shown that with preprocessing it does:

    #define for_range(var, from, to) ...

    it's hard to define it so that it is absolutely correct,
    able to handle an int variable going up to INT_MAX.

    In fact, WHY does Awk have that other kind of loop? Since the primitive
    form can express it just as well.

    No, it cannot. The Awk for (x in array) loop is not easily
    reproduced with the regular for loop.

    It has to step x through the keys of the associative array.

    To do it with a low level loop, we need the primitive stepping
    operations:

    for (iter = array_first(array);
    array_more(iter) && key = array_get(iter)
    iter = array_next(iter))
    {
    # key is set to successive keys
    }

    Not only is this extremely clumsy, but those operations
    don't even exist. There is no associative array iterating
    object!

    In my cppawk project there is a predefined keys (var, array) clause you
    can use in the loop macro.

    Under the hood, this actually obtains a list of the keys as a Lisp-like
    list, and then iterates over that. (Other approaches could be used,
    like a function which converts the *keys* of a given array into
    the *values* of a new array, that new array being indexed numerically
    from zero. We could then step over these with i = 0 ... i++.

    It's all pretty inefficient.

    As you can see, it's practically a necessity for awk to have that for/in iteration method.

    I've written many 10s of 1000s of lines of assembly. But I prefer HLL
    code, and HLL code which has some must-have fundamentals. Like a fucking
    loop that works.

    But you yourself wrote such a loop that is broken; it has undefined
    behavior when you go to the maximum value of the signed type.

    That's worse than a 100% correct primitive loop in which if such a
    situation occurs, it is in plain sight, caused by the expressions
    the programmer chose to plug into it.

    I told you I would rub this in your face!

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Scott Lurndal on Sat Apr 19 16:36:36 2025
    On 2025-04-19, Scott Lurndal <scott@slp53.sl.home> wrote:
    bart <bc@freeuk.com> writes:
    On 18/04/2025 19:10, James Kuyper wrote:
    On 16.04.2025 13:01, bart wrote:
    ...
    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your
    responsibility for all of the other expressions that make up your
    program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it >>with this group?

    It's not an insult, it is a simple fact.

    It's not a fact that someone who finds tools problematic shouldn't
    be using them.

    On the contrary, I would argue that if you don't find your tools
    problematic, you might haven a cognitive defect that will also make you
    blind to faults in computer programs other those tools, like ... your
    own code. In other words, a rational case can be made that it is those
    who are blind to problems in their tools shouldn't be programming,
    rather those who find problems in them.

    (It's also not a fact that someone who pointlessly complains about tools
    to a group of people that can't anything about it should not be
    coding in them. That is neither here nor there.)

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Sat Apr 19 15:15:15 2025
    On 19.04.2025 00:27, bart wrote:
    On 18/04/2025 19:10, James Kuyper wrote:
    ...
    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your
    responsibility for all of the other expressions that make up your
    program.
    ...
    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it
    with this group?

    You are constantly complaining about how difficult you find it to be to
    deal with various features of C that most C programmers have little or
    no trouble dealing with. How could I possibly justify concluding that
    the problem lies anywhere other than in your own abilities?

    ...
    The language will not check that those three parts are correct for the
    loop you are trying to express, because there is no way for it to know
    that.

    Yes, it also doesn't check that the three parts that make up A = B + C;
    make sense together. That's the developer's responsibility, not the
    language's.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Sat Apr 19 19:59:03 2025
    On 19/04/2025 17:28, Kaz Kylheku wrote:
    On 2025-04-19, bart <bc@freeuk.com> wrote:
    On 19/04/2025 07:27, Janis Papanagnou wrote:
    On 19.04.2025 00:27, bart wrote:

    So, yes, I think that is problematic, and the fault is with the
    language. This stuff isn't not hard to get right; even BASIC manages to >>>> FOR-loops properly.

    As so often explained to you, BASIC has a most primitive loop.[*]

    As has been so often pointed out, the vast majority of iterating loops
    can be accommodated by 'for i = a to b'. So in that case it is not
    primitive.

    However C's for-loop genuinely *IS* primitve.

    The abstraction level difference is very small between a loop which
    supplies only holes where you plug in your tests and increments, and a
    loop which sets up the tests and increments.

    (In this particular case, we can macro over the difference with
    a primitve token-replacing preprocessor.)

    That's writing your own language on top. You shouldn't need to that to
    be able to use fundamental features!

    If that's all you can intellectually handle you're obviously a lousy
    programmer (and far from a software engineer).

    Do you undertand my reasons for saying what I do?

    Suppose that C had both its primitive loop, and one like Basic's (or
    like Awk's); would that be better? If so, why?

    We've shown that with preprocessing it does:

    #define for_range(var, from, to) ...

    it's hard to define it so that it is absolutely correct,
    able to handle an int variable going up to INT_MAX.

    But, nobody really cares about that. I say more about this later.


    In fact, WHY does Awk have that other kind of loop? Since the primitive
    form can express it just as well.

    No, it cannot. The Awk for (x in array) loop is not easily
    reproduced with the regular for loop.

    It has to step x through the keys of the associative array.

    To do it with a low level loop, we need the primitive stepping
    operations:

    for (iter = array_first(array);
    array_more(iter) && key = array_get(iter)
    iter = array_next(iter))
    {
    # key is set to successive keys
    }

    Not only is this extremely clumsy, but those operations
    don't even exist. There is no associative array iterating
    object!

    I took the example of Awk that was using 'for in' and wrote it like this:

    split ("one two three four five", table)

    for (i=1; i<=5; i++)
    print i, table[i]

    It seemed to work. That it may have unrelated issues with associative
    arrays is another matter.


    In my cppawk project there is a predefined keys (var, array) clause you
    can use in the loop macro.

    Under the hood, this actually obtains a list of the keys as a Lisp-like
    list, and then iterates over that. (Other approaches could be used,
    like a function which converts the *keys* of a given array into
    the *values* of a new array, that new array being indexed numerically
    from zero. We could then step over these with i = 0 ... i++.

    In my script language I can get a helper function to produce a linear
    list of keys then iterate over that with a regular loop.

    My original example used an array of strings, which JP changed to an Awk
    table in order to show off Awk's 'for in'. They haven't yet explained
    why a normal loop and normal indexing work.

    I've written many 10s of 1000s of lines of assembly. But I prefer HLL
    code, and HLL code which has some must-have fundamentals. Like a fucking
    loop that works.

    But you yourself wrote such a loop that is broken; it has undefined
    behavior when you go to the maximum value of the signed type.

    The behaviour is defined: it wraps round and the loop keeps going.

    But even if it went nowhere near the limits of the type, such a loop
    could keep going for a lifetime given a large enough range.

    You don't seem that bothered about that. In both cases the user would
    have to abort the program.


    That's worse than a 100% correct primitive loop in which if such a
    situation occurs, it is in plain sight, caused by the expressions
    the programmer chose to plug into it.

    I told you I would rub this in your face!

    As I said, I don't care. Few people do, especially if working with 64 bits.

    I also said I worked out how to fix it in my language, but won't be
    doing so since it changes the language spec a little, and doesn't help
    with the other problem mentioned above, which is to do with sanitising
    for-loop ranges.

    This is more to do with user code, not language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to bart on Sat Apr 19 20:15:13 2025
    On 19/04/2025 19:59, bart wrote:
    On 19/04/2025 17:28, Kaz Kylheku wrote:
    On 2025-04-19, bart <bc@freeuk.com> wrote:
    On 19/04/2025 07:27, Janis Papanagnou wrote:
    On 19.04.2025 00:27, bart wrote:

    So, yes, I think that is problematic, and the fault is with the
    language. This stuff isn't not hard to get right; even BASIC
    manages to
    FOR-loops properly.

    As so often explained to you, BASIC has a most primitive loop.[*]

    As has been so often pointed out, the vast majority of iterating loops
    can be accommodated by 'for i = a to b'. So in that case it is not
    primitive.

    However C's for-loop genuinely *IS* primitve.

    The abstraction level difference is very small between a loop which
    supplies only holes where you plug in your tests and increments, and a
    loop which sets up the tests and increments.

    (In this particular case, we can macro over the difference with
    a primitve token-replacing preprocessor.)

    That's writing your own language on top. You shouldn't need to that to
    be able to use fundamental features!

    If that's all you can intellectually handle you're obviously a lousy
    programmer (and far from a software engineer).

    Do you undertand my reasons for saying what I do?

    Suppose that C had both its primitive loop, and one like Basic's (or
    like Awk's); would that be better? If so, why?

    We've shown that with preprocessing it does:

    #define for_range(var, from, to) ...

    it's hard to define it so that it is absolutely correct,
    able to handle an int variable going up to INT_MAX.

    But, nobody really cares about that. I say more about this later.


    In fact, WHY does Awk have that other kind of loop? Since the primitive
    form can express it just as well.

    No, it cannot. The Awk  for (x in array) loop is not easily
    reproduced with the regular for loop.

    It has to step x through the keys of the associative array.

    To do it with a low level loop, we need the primitive stepping
    operations:

        for (iter = array_first(array);
             array_more(iter) && key = array_get(iter)
             iter = array_next(iter))
        {
           # key is set to successive keys
        }

    Not only is this extremely clumsy, but those operations
    don't even exist. There is no associative array iterating
    object!

    I took the example of Awk that was using 'for in' and wrote it like this:

      split ("one two three four five", table)

      for (i=1; i<=5; i++)
          print i, table[i]

    It seemed to work. That it may have unrelated issues with associative
    arrays is another matter.


    In my cppawk project there is a predefined keys (var, array) clause you
    can use in the loop macro.

    Under the hood, this actually obtains a list of the keys as a Lisp-like
    list, and then iterates over that. (Other approaches could be used,
    like a function which converts the *keys* of a given array into
    the *values* of a new array, that new array being indexed numerically
    from zero. We could then step over these with i = 0 ... i++.

    In my script language I can get a helper function to produce a linear
    list of keys then iterate over that with a regular loop.

    My original example used an array of strings, which JP changed to an Awk table in order to show off Awk's 'for in'. They haven't yet explained
    why a normal loop and normal indexing work.

    I've written many 10s of 1000s of lines of assembly. But I prefer HLL
    code, and HLL code which has some must-have fundamentals. Like a fucking >>> loop that works.

    But you yourself wrote such a loop that is broken; it has undefined
    behavior when you go to the maximum value of the signed type.

    The behaviour is defined: it wraps round and the loop keeps going.

    But even if it went nowhere near the limits of the type, such a loop
    could keep going for a lifetime given a large enough range.

    You don't seem that bothered about that. In both cases the user would
    have to abort the program.


    That's worse than a 100% correct primitive loop in which if such a
    situation occurs, it is in plain sight, caused by the expressions
    the programmer chose to plug into it.

    I told you I would rub this in your face!

    As I said, I don't care. Few people do, especially if working with 64 bits.

    I tried this on two online Awks:

    BEGIN {
    split ("one two three four five", table)

    for (i=9223372036854775800; i<=9223372036854775806; i++)
    print i

    }

    Both went funny, and the limit isn't even on i63.max.

    I don't know what type 'i' is, but it seems fine with i32.max or
    u32.max, so I assume it's something like 2**52 (typical when f64
    represents integers).

    Whatever, it's giving unexpected results, whether it's due to hitting
    i64.max or reaching a threshold where a simple increment runs out of
    precision bits. As I said, few care.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Kaz Kylheku on Sat Apr 19 15:22:30 2025
    On 4/19/25 12:36, Kaz Kylheku wrote:
    On 2025-04-19, Scott Lurndal <scott@slp53.sl.home> wrote:
    bart <bc@freeuk.com> writes:
    On 18/04/2025 19:10, James Kuyper wrote:
    ...
    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your
    responsibility for all of the other expressions that make up your
    program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it
    with this group?

    It's not an insult, it is a simple fact.

    It's not a fact that someone who finds tools problematic shouldn't
    be using them.

    I wasn't talking about him finding the tools problematic. I was talking
    aobut him find it difficult to ensure that the expressions are not
    arbitrary unrelated expressions, but are in fact correctly related
    expressions. If you cannot ensure that A, B, and C have the correct relationship to make for(A; B; C) work as needed, then you also lack to
    ability to make sure that the expressions in {A; B; C:} work together as needed, and that ability is fundamental to computer programming.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Sat Apr 19 20:36:35 2025
    On 19/04/2025 20:15, James Kuyper wrote:
    On 19.04.2025 00:27, bart wrote:
    On 18/04/2025 19:10, James Kuyper wrote:
    ...
    If all you can do is "hope for the best", you're doing it wrong. It's
    your job to ensure that they are not arbitrary unrelated expressions,
    but correctly related expressions, and that's no different from your
    responsibility for all of the other expressions that make up your
    program.
    ...
    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it
    with this group?

    You are constantly complaining about how difficult you find it to be to
    deal with various features of C that most C programmers have little or
    no trouble dealing with.


    How could I possibly justify concluding that
    the problem lies anywhere other than in your own abilities?

    Did I say I find it difficult? I said the feature was: Poor, Crude,
    Primitive, Error prone, Hard to grok, a PITA to write, among other things.

    You can argue with some of those if you like, but one problem is seeing
    a complex line headed 'for(...' and now you have to spend time
    disentangling it to find out what category of loop was intended. EVERY
    such loop starts with 'for'!

    So your attitude is to totally ignore such criticism? C is perfect? It's
    a wonder any other HLL was ever devised!

    ...
    The language will not check that those three parts are correct for the
    loop you are trying to express, because there is no way for it to know
    that.

    Yes, it also doesn't check that the three parts that make up A = B + C;
    make sense together. That's the developer's responsibility, not the language's.

    You don't think the language could have helped more?

    People do use big compilers now to do a lot of deep analysis of code;
    are you saying those compilers are not necessary, developers should be
    able to figure things out for themselves?

    Or are you saying that it's OK for additional tooling to help out a
    developer, but it is out of the question for a language to provide a
    more convenient feature?

    This is now interesting: suppose I were to say to David Brown that if he
    can't do his work without his advanced compilers, he shouldn't be coding
    in C?

    This is EXACTLY what you are saying. And it is an insult.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Sat Apr 19 20:55:05 2025
    On 19/04/2025 20:22, James Kuyper wrote:
    On 4/19/25 12:36, Kaz Kylheku wrote:
    On 2025-04-19, Scott Lurndal <scott@slp53.sl.home> wrote:
    bart <bc@freeuk.com> writes:
    On 18/04/2025 19:10, James Kuyper wrote:
    ...
    If all you can do is "hope for the best", you're doing it wrong. It's >>>>> your job to ensure that they are not arbitrary unrelated expressions, >>>>> but correctly related expressions, and that's no different from your >>>>> responsibility for all of the other expressions that make up your
    program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it >>>> with this group?

    It's not an insult, it is a simple fact.

    It's not a fact that someone who finds tools problematic shouldn't
    be using them.

    I wasn't talking about him finding the tools problematic. I was talking
    aobut him find it difficult to ensure that the expressions are not
    arbitrary unrelated expressions, but are in fact correctly related expressions. If you cannot ensure that A, B, and C have the correct relationship to make for(A; B; C) work as needed, then you also lack to ability to make sure that the expressions in {A; B; C:} work together as needed, and that ability is fundamental to computer programming.

    In other words, the feature is dumb.

    The compiler cannot do any checking: for (i=0; i<n; ++n) is fine.

    Even in BASIC, if I do this:

    for i=1 to n
    next n

    it will say that n does not match. And here it is optional; in C that
    part is necessary.

    So, BASIC's for-loop is less dumb that C's.

    But, you have a bizarre take on this: if somebody calls it out, then
    rather than agree with them, you will personally insult the person who
    said it, and suggest that if they are incapable of such a simple check,
    then they shouldn't be coding.

    The fact is that people make typos (obviously, not you or JP or SL or
    KT!), and here you would really prefer that the compiler could report
    them, but with this feature, it often can't.

    Your attitude completely stinks, sorry.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Sat Apr 19 20:57:27 2025
    On 19/04/2025 20:54, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    I don't understand why you're happy using a crippled looping
    mechanism, that is a PITA to use for the majority of iterating loops,
    just so you have that flexibility for the whacky loops that are in the
    minority, most of which can be trivially expressed with 'while'.
    [...]

    I agree. You don't understand. What confuses me is your complete lack
    of interest in trying to understand.

    Many of us are happy using C's for loop because we don't consider
    it to be crippled. It is not a PITA to use it for the majority of
    iterating loops; we just use a very common coding pattern like

    for (int i = 0; i < N; i ++) {
    // ...
    }

    We can write "i --" if we want the loop to run in reverse,

    That's not enough for it to run in reverse. I'd be interested in a
    complete example.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Keith Thompson on Sun Apr 20 00:52:42 2025
    On Sat, 19 Apr 2025 13:55:02 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:


    Again, I would not object to adding a new kind of for loop,
    similar to what you would prefer, and visually distinct from the
    existing for loop, in a new version of the C standard. But that's
    not likely to happen because there doesn't seem to be much demand
    for it (for reasons that I know make you angry), and I don't care
    enough to write a proposal. If someone else does write a proposal,
    I'll be glad to help out by nitpicking it.

    [...]


    I don't believe that such proposal can be accepted.
    If I was a member, I'd certainly vote against it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Sun Apr 20 00:34:57 2025
    On 19/04/2025 22:07, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 19/04/2025 20:54, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    [...]
    I don't understand why you're happy using a crippled looping
    mechanism, that is a PITA to use for the majority of iterating loops,
    just so you have that flexibility for the whacky loops that are in the >>>> minority, most of which can be trivially expressed with 'while'.
    [...]
    I agree. You don't understand. What confuses me is your complete
    lack
    of interest in trying to understand.
    Many of us are happy using C's for loop because we don't consider
    it to be crippled. It is not a PITA to use it for the majority of
    iterating loops; we just use a very common coding pattern like
    for (int i = 0; i < N; i ++) {
    // ...
    }
    We can write "i --" if we want the loop to run in reverse,

    That's not enough for it to run in reverse.

    No, it's not. I didn't mean to imply that it was.

    I'd be interested in a
    complete example.

    Really? It's such a simple example that I'm surprised you think you
    need my help. But ok :

    for (int i = N-1; i >=0; i --) {
    // ...
    }

    I wrote that off the top of my head. I then wrote and compiled a
    program using it, and it worked.

    I only recently noticed that the pattern was rather different from an
    upwards loop. For example, for a range of 0..N-1 inclusive the upper
    limit is usually written as N, with N-1 being something that a 1-based
    language is more likely to use.

    I just wondered if you used a different approach. So it looks like 3
    things need to be changed, apart from reversing range limits:

    Start val Comp End Val Increment
    Upwards 0 < N ++
    Downwards N-1 >= 0 --

    It's also just struck me that it would be more consistent if Upwards
    loops used this:

    Upward 0 <= N-1 ++

    I doubt this would be popular though with two extra characters to type
    (and possibly to omit or get wrong).


    A similar loop with an iteration variable of an unsigned type would
    fail because `i >= 0` is always true. I have some thoughts about
    how to deal with that, but I'll leave that aside.

    Just insist on signed loop variables. Or if ints are 32 bits and start
    values are between 2**31 and 2**32, require an i64 loop variable.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Chris M. Thomasson on Sun Apr 20 11:27:55 2025
    On 20.04.2025 04:43, Chris M. Thomasson wrote:

    [...] Also a smith and wesson always beats four aces. [...]

    Unless you have an Oklahoma! [*]

    Janis

    [*] See "M.A.S.H." (1970) for details.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sun Apr 20 11:25:51 2025
    On 19.04.2025 21:36, bart wrote:
    On 19/04/2025 20:15, James Kuyper wrote:

    How could I possibly justify concluding that
    the problem lies anywhere other than in your own abilities?

    Did I say I find it difficult? [...]

    You said you regularly make errors with it.


    So your attitude is to totally ignore such criticism? C is perfect? [...]

    No one ever said that. Rather the opposite; it's often said its an
    imperfect language.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sun Apr 20 12:34:54 2025
    On 19.04.2025 20:59, bart wrote:
    [...]

    My original example used an array of strings, which JP changed to an Awk table in order to show off Awk's 'for in'. They haven't yet explained
    why a normal loop and normal indexing work.

    The CLC newsgroup has a couple pathological posters that flood the
    group repeatedly with arguable contents. I have literally thousands
    of yet unread posts - and I don't intend to read them. I do try to
    answer your posts (as my time allows), despite your personality and
    posts making that cumbersome. - I'm sure I meanwhile answered your
    post from yesterday. - All I demand from you is a minimum patience.
    I think given the, umm, quality of your posts and posting habits it
    is fair to ask you to wait a few days to give me the chance to catch
    up with the backlog. (Mind, I'm also having a life.)

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sun Apr 20 12:41:07 2025
    On 19.04.2025 21:15, bart wrote:
    [...]

    I tried this on two online Awks:

    I suggest to learn it from scratch - that doesn't require much time
    since it's a very terse and to some degree abstract language - and
    not trying behavioral analysis in the first place to understand it.


    BEGIN {
    split ("one two three four five", table)

    for (i=9223372036854775800; i<=9223372036854775806; i++)
    print i

    }

    Both went funny, and the limit isn't even on i63.max.

    Awk has two primitive data types, numbers and strings. Variables can
    be both and get coerced as necessary. The underlying numerical type
    is able to carry floating point values.

    (If, for example, you iterate ad infinitum you will notice that the
    loop value will not change any more at some point.)

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Michael S on Sun Apr 20 13:00:26 2025
    On 19.04.2025 23:52, Michael S wrote:
    On Sat, 19 Apr 2025 13:55:02 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Again, I would not object to adding a new kind of for loop,
    similar to what you would prefer, and visually distinct from the
    existing for loop, in a new version of the C standard. But that's
    not likely to happen because there doesn't seem to be much demand
    for it (for reasons that I know make you angry), and I don't care
    enough to write a proposal. If someone else does write a proposal,
    I'll be glad to help out by nitpicking it.

    [...]

    I don't believe that such proposal can be accepted.
    If I was a member, I'd certainly vote against it.

    Exactly 19 days ago I'd even have written such a proposal, and,
    fitting to the calendar date, of course I'd have used a distinct
    name for the feature; 'for_losers(var,expr,expr[,expr])'.

    BTW, a more serious question. Would a change of the "C" language
    have syntax constructs with such _optional_ components?

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sun Apr 20 12:18:55 2025
    On 19.04.2025 15:05, bart wrote:
    On 19/04/2025 12:32, Janis Papanagnou wrote:
    On 19.04.2025 12:26, bart wrote:
    On 19/04/2025 07:27, Janis Papanagnou wrote:
    On 19.04.2025 00:27, bart wrote:


    I'm doing hard to imagine a yet more
    primitive one. All other loops pointed out that far (Algol 68,
    Simula, "C") allow more complex (less primitive) loop constructs.

    C, really?

    You have already seen many examples of loops that can't be written
    with those heavily restricted Pascal/BASIC/Fortran-like loops.


    I don't understand why you're happy using a crippled looping mechanism,
    that is a PITA to use for the majority of iterating loops, just so you
    have that flexibility for the whacky loops that are in the minority,
    most of which can be trivially expressed with 'while'.

    Because with it I can formulate everything I regularly need in "C"
    (as opposed to those primitive and restricted, specialized loops).

    Think about it; what could the alternatives be that the "C" designers
    have chosen...
    * Provide just a very restricted Pascal like loop? - Then you'd have
    all the now common more diverse loops made impossible and require to
    spread the loop logic across many primitive language constructs.
    * Provide two or there forms of 'for' loops to suit your demands? -
    That would be a possibility, but language designers often don't want
    to overload their language, and especially not invent things that can
    already be expressed easily with the existing features.


    We disagree what "primitive" means;
    so it's hard to continue the discussion below since we're speaking
    different languages, obviously.

    I'll tell you a secret: a few years ago, I also added a C-style 'for' statement to my language. So it had two kinds of 'for' that looked like
    this:

    for i in a..b do # also for i[:=a] to b do

    cfor A, B, C do # A B C are arbitrary expressions

    This was because I'd got fed up with people telling me all these
    wonderful things that C's for could do, that I couldn't. So now I could
    do the same!

    The feature sets in languages should (IMO) follow a design principle.
    It may make sense in one language or not in another language. I don't
    know "your language" so I cannot suggest you anything. All I can say
    is that such featuritis is, as "design principle", not something that
    I'd say you've done right as a basic design approach of your language.
    (But as often said; I don't care about "your language" and what you
    do in your personal environment.)

    [...]

    If you were me, would you have instead have got rid of the dedicated
    'for', and kept only 'cfor'? Be honest!

    (Honestly, I just formulated it above what I think.)


    Since that is exactly what you have been saying about C's 'for'; you
    don't /want/ a better 'for' in C, even if it was in addition to the
    current 'for': 'there is nothing wrong with latter, and anyone who can't
    hack it should give up programming'.

    (Look up what had been written; I won't repeat it.)

    [...]

    In fact, WHY does Awk have that other kind of loop? Since the primitive
    form can express it just as well.

    No. You have a complete misconception about that. In all respects.

    Really? So why does this work:

    I've explained it in my previous post.


    split ("one two three four five", table)

    for (i=1; i<=5; i++)
    print i, table[i]

    I thought you said Awk didn't support indexed arrays? [...]

    Yes. Standard Awk supports only an associative array as structured
    data type. All other array usages are implicit "quirks"; e.g. above
    indexed access is done by coercing integer values to strings that
    are used as keys to the associative array, and "multi-dimensional"
    arrays are also just emulated, and an index [i,j] is actually a key
    that is constructed by [string(i) SUBSEP string(j)] where SUBSEP is
    a string separator, so all in all also just a string that gets used
    as key to the associative array. The same with the "if ((i,j) in a)"
    the (i,j) gets converted to a string to be used as key. The "for-in"
    loop with a quasi "two-dimensional index" "for ((i,j) in a)" isn't
    possible[*], that's especially nasty since you have no direct access
    to 'i' and 'j'; if you want that you need an explicit 'split()' as
    in for (key in a) { split(key,k,SUBSEP); i=k[1]; j=k[2]; ... } .

    [*] It's actually a feature I suggested as a GNU Awk extension, but
    it was dismissed since the feature could be emulated (as shown).


    don't use that language. Why are you here, in CLC; just to complain?

    I'm here to understand why people are deifying C and its crude for-loop
    by arguing that black is white:

    do i = 1,10 # 'primitive'
    for(i=1; i<=10; ++i) # 'advanced'

    "C" loops offer a useful flexibility that Fortran loops don't provide.


    But then at the same some are saying that:

    'for' i 'from' 1 'to' 10 'do'

    from Algol68 is advanced (because you can stick 'while' in there?).

    The loops in the three languages allow more than the simple FROM..TO
    traversal. Yes, that is advanced. And the "C" loop, because of its
    elementary building blocks, allows even more things to formulate.


    It's a fascinating. I guess the answers are more psychological than otherwise.

    Most of the discussion with you is mostly "psychological".

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Janis Papanagnou on Sun Apr 20 15:00:04 2025
    On Fri, 18 Apr 2025 16:57:24 +0200
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    Of course, if all you have is an assembler language then "all" you
    have are jumps. (Note: again an accentuated formulation of the point,
    but I'm confident you understand what I'm trying to say.)


    Many architectures have counting loop as a dedicated construct that
    differs from jump/branch. It is not uncommon even among general-purpose
    CPU architectures. In the realm of DSPs I can not recollect an
    architecture that does *not* have a dedicated loop istruction.
    Also, many (most?) architectures have call (or jump-and-link) and return
    as dedicated instruction distinct from jump/branch.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sun Apr 20 12:43:09 2025
    On 20/04/2025 11:18, Janis Papanagnou wrote:
    On 19.04.2025 15:05, bart wrote:
    On 19/04/2025 12:32, Janis Papanagnou wrote:
    On 19.04.2025 12:26, bart wrote:
    On 19/04/2025 07:27, Janis Papanagnou wrote:
    On 19.04.2025 00:27, bart wrote:


    I'm doing hard to imagine a yet more
    primitive one. All other loops pointed out that far (Algol 68,
    Simula, "C") allow more complex (less primitive) loop constructs.

    C, really?

    You have already seen many examples of loops that can't be written
    with those heavily restricted Pascal/BASIC/Fortran-like loops.


    I don't understand why you're happy using a crippled looping mechanism,
    that is a PITA to use for the majority of iterating loops, just so you
    have that flexibility for the whacky loops that are in the minority,
    most of which can be trivially expressed with 'while'.

    Because with it I can formulate everything I regularly need in "C"
    (as opposed to those primitive and restricted, specialized loops).

    Think about it; what could the alternatives be that the "C" designers
    have chosen...
    * Provide just a very restricted Pascal like loop? - Then you'd have
    all the now common more diverse loops made impossible and require to
    spread the loop logic across many primitive language constructs.

    Good! If that happens then it's halfway there. At present you see 'for'
    but have no idea what was in the mind of the programmer until you've deconstructed the header.

    (They could have simply called it 'while'; at least people will know
    what to expect. With 'for' then being available for a more streamlined, compiled-checked loop.)


    * Provide two or there forms of 'for' loops to suit your demands? -
    That would be a possibility, but language designers often don't want
    to overload their language,

    But overloading in the form of 30-40 integer types to represent the 8
    types i8-i64 and u8-u64, plus the 16 different combinations of writing 'unsigned long long int', and so on, is fine. As are the dozens
    (hundreds?) of macros in stdint.h/inttypes.h.

    and especially not invent things that can
    already be expressed easily with the existing features.

    Show me a for-loop that cannot be expressed with existing features. Many
    are likely to be clearer!

    I don't know why people think that cramming as much code as possible
    into for(...) is a good style of coding. Either into one over-long line,
    or spilling over multiple lines; both should fail a code review.

    Actually here's a example from sqlite3.c:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    And this is how you might be forced to write it instead:

    p=sqliteHashFirst(&pSchema->trigHash);
    while (p) {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p=sqliteHashNext(p);
    }

    Yes, it's spread over two more lines, but so what? It's much clearer:
    the initialisation is done once and then it's out of the way. Setting p
    to the next value is now physically written after the body.

    The execution path is simpler, as you will see if you were to draw a
    line that traces that path.

    I mean, I'm surprised the authors here didn't go one step further and
    put the body inside the loop header too:

    for(p=sqliteHashFirst(&pSchema->trigHash); p;
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)), p=sqliteHashNext(p));

    At least, the execution path simplifies! But little else.


    I'll tell you a secret: a few years ago, I also added a C-style 'for'
    statement to my language. So it had two kinds of 'for' that looked like
    this:

    for i in a..b do # also for i[:=a] to b do

    cfor A, B, C do # A B C are arbitrary expressions

    This was because I'd got fed up with people telling me all these
    wonderful things that C's for could do, that I couldn't. So now I could
    do the same!

    The feature sets in languages should (IMO) follow a design principle.
    It may make sense in one language or not in another language. I don't
    know "your language" so I cannot suggest you anything. All I can say
    is that such featuritis is, as "design principle", not something that
    I'd say you've done right as a basic design approach of your language.
    (But as often said; I don't care about "your language" and what you
    do in your personal environment.)

    So, you don't like the idea of having multiple simple features, each
    with a well defined job that a compiler can check.

    But you like idea of one vaguely defined, open-ended feature that a
    compiler cannot check, as it doesn't know your intentions, and a reader
    also has to disentangle.

    Most of the discussion with you is mostly "psychological".

    It works both ways.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sun Apr 20 14:53:54 2025
    On 20/04/2025 12:00, Janis Papanagnou wrote:
    On 19.04.2025 23:52, Michael S wrote:
    On Sat, 19 Apr 2025 13:55:02 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Again, I would not object to adding a new kind of for loop,
    similar to what you would prefer, and visually distinct from the
    existing for loop, in a new version of the C standard. But that's
    not likely to happen because there doesn't seem to be much demand
    for it (for reasons that I know make you angry), and I don't care
    enough to write a proposal. If someone else does write a proposal,
    I'll be glad to help out by nitpicking it.

    [...]

    I don't believe that such proposal can be accepted.
    If I was a member, I'd certainly vote against it.

    Exactly 19 days ago I'd even have written such a proposal, and,
    fitting to the calendar date, of course I'd have used a distinct
    name for the feature; 'for_losers(var,expr,expr[,expr])'.

    This is quite telling in that:

    (1) You regard the idea of desiring such a feature as a joke

    (2) You consider those who'd like to use it as 'losers'

    Just such a feature seems to be the primary style of 'for' in languages
    such as Ada, Python, Modern Fortran, Odin, Ruby, Julia, Rust, Matlab,
    Algol68, Euphoria, Ocaml, Logo, Nim, PL/I, Haxe, Lua, ....

    Even Bash has it. All losers?

    Interestingly, so does BCPL: you may be aware that C was influenced by
    B, which itself was supposed to be influenced by BCPL. So what the hell happened?



    BTW, a more serious question. Would a change of the "C" language
    have syntax constructs with such _optional_ components?

    Why is that a big deal?

    C's 'for' already has optional parts, although the semicolons need to be present. Do you mean allowing the comma in your example to be optional
    as well as the expression?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Sun Apr 20 17:34:51 2025
    On Sun, 20 Apr 2025 14:53:54 +0100
    bart <bc@freeuk.com> wrote:

    On 20/04/2025 12:00, Janis Papanagnou wrote:

    Exactly 19 days ago I'd even have written such a proposal, and,
    fitting to the calendar date, of course I'd have used a distinct
    name for the feature; 'for_losers(var,expr,expr[,expr])'.

    This is quite telling in that:

    (1) You regard the idea of desiring such a feature as a joke

    (2) You consider those who'd like to use it as 'losers'

    Just such a feature seems to be the primary style of 'for' in
    languages such as Ada, Python, Modern Fortran, Odin, Ruby, Julia,
    Rust, Matlab, Algol68, Euphoria, Ocaml, Logo, Nim, PL/I, Haxe, Lua,
    ....


    In majority of languages in your list 'for' loops iterates through all
    elements of collection. If collection happens to be a range
    (terminology shared by python and Rust) then 'for' behaves as a
    counting loop. If it isn't then it does not. Even Matlab, despite its
    fortranic roots, belongs to that group.
    C++ achieve the same objectives [with typical C++ ugliness] by means
    of std::foreach.
    If I am not mistaken, all exception to that pattern are old languages.


    Even Bash has it. All losers?


    Not all, just many.

    Interestingly, so does BCPL: you may be aware that C was influenced
    by B, which itself was supposed to be influenced by BCPL. So what the
    hell happened?


    So, what happened?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Sun Apr 20 11:25:43 2025
    On 19.04.2025 21:36, bart wrote:
    On 19/04/2025 20:15, James Kuyper wrote:

    How could I possibly justify concluding that
    the problem lies anywhere other than in your own abilities?

    Did I say I find it difficult? [...]

    Yes, repeatedly. You've described it as a source of errors and confusion.

    So your attitude is to totally ignore such criticism? C is perfect? [...]

    No, I said nothing to suggest that. It is a less than perfect language,
    but the amount of trouble you have with it is far more than it's
    imperfections justify.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Michael S on Sun Apr 20 17:45:10 2025
    On 20.04.2025 14:00, Michael S wrote:
    On Fri, 18 Apr 2025 16:57:24 +0200
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    Of course, if all you have is an assembler language then "all" you
    have are jumps. (Note: again an accentuated formulation of the point,
    but I'm confident you understand what I'm trying to say.)

    Many architectures have counting loop as a dedicated construct that
    differs from jump/branch. It is not uncommon even among general-purpose
    CPU architectures. In the realm of DSPs I can not recollect an
    architecture that does *not* have a dedicated loop istruction.
    Also, many (most?) architectures have call (or jump-and-link) and return
    as dedicated instruction distinct from jump/branch.

    Yes, sure. My comparison was more figuratively; I wrote it's an
    "accentuated formulation". (But maybe I shouldn't have written
    it as it was formulated in the first place if it was easy to be
    prone to misunderstandings.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Sun Apr 20 16:53:27 2025
    On 20/04/2025 16:25, James Kuyper wrote:
    On 19.04.2025 21:36, bart wrote:
    On 19/04/2025 20:15, James Kuyper wrote:

    How could I possibly justify concluding that
    the problem lies anywhere other than in your own abilities?

    Did I say I find it difficult? [...]

    Yes, repeatedly. You've described it as a source of errors and confusion.

    Yes it is. That doesn't means I'm incapable of writing such loops. But I
    prefer to use a syntax which involves less typing, has less opportunity
    for typos, and which anyone can instantly grok.




    So your attitude is to totally ignore such criticism? C is perfect? [...]

    No, I said nothing to suggest that. It is a less than perfect language,
    but the amount of trouble you have with it is far more than it's imperfections justify.

    And yet, you are unwilling to accept my criticisms of it, to the extent
    that you'd rather accuse me of being unable to program rather than admit
    I might be at least partly right.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Michael S on Sun Apr 20 16:25:14 2025
    On 20/04/2025 15:34, Michael S wrote:
    On Sun, 20 Apr 2025 14:53:54 +0100
    bart <bc@freeuk.com> wrote:

    On 20/04/2025 12:00, Janis Papanagnou wrote:

    Exactly 19 days ago I'd even have written such a proposal, and,
    fitting to the calendar date, of course I'd have used a distinct
    name for the feature; 'for_losers(var,expr,expr[,expr])'.

    This is quite telling in that:

    (1) You regard the idea of desiring such a feature as a joke

    (2) You consider those who'd like to use it as 'losers'

    Just such a feature seems to be the primary style of 'for' in
    languages such as Ada, Python, Modern Fortran, Odin, Ruby, Julia,
    Rust, Matlab, Algol68, Euphoria, Ocaml, Logo, Nim, PL/I, Haxe, Lua,
    ....


    In majority of languages in your list 'for' loops iterates through all elements of collection. If collection happens to be a range
    (terminology shared by python and Rust) then 'for' behaves as a
    counting loop. If it isn't then it does not. Even Matlab, despite its fortranic roots, belongs to that group.

    I don't quite get your point. So, given a generic form like:

    for x in A

    then some languages, mainly newer ones, will iterate through the values
    of A if it is not a range. If it is a range, then those values are the interpolated elements of the range.

    In other words, in something like:

    for x in 1..10

    x will take on the values 1, 2, ... up to 10 (depending on whether the
    range is closed or open in the language).

    Isn't this exactly what some of us are trying to do? So why is it a joke
    to desire such a nifty form of loop, and why are we losers to do so?

    There is nothing to stop any of those languages from also having a
    feature that does what C-for does, but they choose not to.

    However there are also a great number that do have a C-style 'for',
    often as the primary means of iteration, and there it usually looks
    completely out of place. (For example, JavaScript.)

    This was my opening observation in this sub-thread.



    C++ achieve the same objectives [with typical C++ ugliness] by means
    of std::foreach.
    If I am not mistaken, all exception to that pattern are old languages.


    Even Bash has it. All losers?


    Not all, just many.

    Interestingly, so does BCPL: you may be aware that C was influenced
    by B, which itself was supposed to be influenced by BCPL. So what the
    hell happened?


    So, what happened?

    That's what I'm asking! BCPL, an older and more primitive language than
    the other two, has such a 'for' as described above:

    FOR N = E1 TO E2 DO

    It seems to have been dropped by B, which has only 'while', until C
    introduced a souped-up, 3-element version of 'while', named 'for'.

    Clearly the author of both (Ken Thompson) had no great love for
    'for'-loops; real ones.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Sun Apr 20 19:01:25 2025
    On Sun, 20 Apr 2025 16:25:14 +0100
    bart <bc@freeuk.com> wrote:


    That's what I'm asking! BCPL, an older and more primitive language
    than the other two, has such a 'for' as described above:

    FOR N = E1 TO E2 DO

    It seems to have been dropped by B, which has only 'while', until C introduced a souped-up, 3-element version of 'while', named 'for'.


    I never knew either BCPL or B, but from what I am reading, B is more
    primitive of the two. B was a simplified BCPL. BCPL itself was
    simplified CPL. CPL was so complicated that it took approximately 10
    years from definition to 1st implementation.

    Clearly the author of both (Ken Thompson) had no great love for
    'for'-loops; real ones.



    Ken Thompson was not an author of C. No doubts that Thompson
    influenced it, but still C is Ritchie's language.
    You can probably say that Dennis Ritchie was an author of both
    languages, even if he joined Thompson on later stages of design and implementation of B.

    The second language of Ken Thompson is Go which he co-authored with
    Robert Griesemer and Rob Pike almost 40 years after B.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sun Apr 20 17:55:57 2025
    On 20.04.2025 15:53, bart wrote:
    This is quite telling in that:
    (1) You regard the idea of desiring such a feature as a joke
    (2) You consider those who'd like to use it as 'losers'

    No. As so often you make up things, and you are interpreting
    things like your preconditioned brain wants to see them.


    BTW, a more serious question. Would a change of the "C" language
    have syntax constructs with such _optional_ components?

    Why is that a big deal?

    Why do you think I said or implied it would be a "big deal"?


    C's 'for' already has optional parts, although the semicolons need to be present. Do you mean allowing the comma in your example to be optional
    as well as the expression?

    I think the question in context of my sample is clear enough
    and I see no point in further explanations or repetitions.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sun Apr 20 18:10:59 2025
    On 20.04.2025 17:25, bart wrote:

    [...], and why are we losers to do so?

    Not "we".

    (Your arguments are based on your preconditioned brain.
    Try to overcome that.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Michael S on Sun Apr 20 18:07:18 2025
    On 20.04.2025 16:34, Michael S wrote:
    On Sun, 20 Apr 2025 14:53:54 +0100
    bart <bc@freeuk.com> wrote:
    [...]

    Just such a feature seems to be the primary style of 'for' in
    languages such as Ada, Python, Modern Fortran, Odin, Ruby, Julia,
    Rust, Matlab, Algol68, Euphoria, Ocaml, Logo, Nim, PL/I, Haxe, Lua,
    ....

    In majority of languages in your list 'for' loops iterates through all elements of collection. If collection happens to be a range
    (terminology shared by python and Rust) then 'for' behaves as a
    counting loop. If it isn't then it does not. Even Matlab, despite its fortranic roots, belongs to that group.
    C++ achieve the same objectives [with typical C++ ugliness] by means
    of std::foreach.
    If I am not mistaken, all exception to that pattern are old languages.

    Even Bash has it. All losers?

    The Unix standard shell has no counted loops, but it has indexed
    arrays, and a 'for' loop that effectively processes just lists.

    Kornshell, in its 1988 version the base of POSIX shell, invented
    counted loops in its 1993 version but (while adopted by e.g. Bash)
    this did not enter the Unix standard. Kornshell also supported
    associative arrays. The Unix shells are a big grown conglomerate
    of ancient crude syntax. Some shells try to "orthogonalize" their
    feature set, but Unix shells are still no appropriate measure for
    a sensible language design.


    Not all, just many.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sun Apr 20 17:28:48 2025
    On 20/04/2025 16:55, Janis Papanagnou wrote:
    On 20.04.2025 15:53, bart wrote:
    This is quite telling in that:
    (1) You regard the idea of desiring such a feature as a joke
    (2) You consider those who'd like to use it as 'losers'

    No. As so often you make up things, and you are interpreting
    things like your preconditioned brain wants to see them.

    Huh?????

    You CLEARLY suggested such a proposal would be an April Fool's joke.

    You CLEARLY chose to name the keyword 'for_losers'.

    I didn't make either of those up; YOU did! Proof:

    Exactly 19 days ago I'd even have written such a proposal, and,
    fitting to the calendar date, of course I'd have used a distinct
    name for the feature; 'for_losers(var,expr,expr[,expr])'.

    So what am I missing? What DID you mean if it wasn't that?

    Or is it even worth my asking if you're just going to give me a runaround?




    BTW, a more serious question. Would a change of the "C" language
    have syntax constructs with such _optional_ components?

    Why is that a big deal?

    Why do you think I said or implied it would be a "big deal"?

    That fact that you are asking about it. Optional syntax is hardly novel
    in any language.


    C's 'for' already has optional parts, although the semicolons need to be
    present. Do you mean allowing the comma in your example to be optional
    as well as the expression?

    I think the question in context of my sample is clear enough
    and I see no point in further explanations or repetitions.

    Would it kill you to just answer Yes or No for once?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Sun Apr 20 18:46:32 2025
    On 20.04.2025 13:43, bart wrote:
    On 20/04/2025 11:18, Janis Papanagnou wrote:
    On 19.04.2025 15:05, bart wrote:

    But overloading in the form of 30-40 integer types to represent the 8
    types i8-i64 and u8-u64, plus the 16 different combinations of writing 'unsigned long long int', and so on, is fine. As are the dozens
    (hundreds?) of macros in stdint.h/inttypes.h.

    I haven't said this "is fine". It wasn't at all the topic here.

    (Why do you repeatedly show us your frustration about the "C"
    language in every post and complain about completely *unrelated*
    things to what was said.)


    Show me a for-loop that cannot be expressed with existing features. Many
    are likely to be clearer!

    (There have been sufficient examples posted.)

    The point is that if you have programming elements that are
    related to a loop construct (initialization, exit condition,
    update for next iteration) it makes sense to keep them together.
    It makes not much sense to spread them across a multi-line block
    of statements. - If you haven't ever experienced that, and still
    cannot see and understand that if explained to you, then I can't
    help you.[*]

    [*] Maybe you should visit some University courses. Despite your
    long programming history you really seem to miss some elementary
    basic programming experiences. Or are you mentally so bound to
    primitive loops and your brain so inflexible that nothing helps.


    I don't know why people think that cramming as much code as possible
    into for(...) is a good style of coding.

    But that's not what programmers should do. Why do you again make
    up things. - The point is to keep things together that belong
    together.

    Either into one over-long line,
    or spilling over multiple lines; both should fail a code review.

    (I doubt you've ever been engaged in professional code reviews.)

    [...]

    I'll tell you a secret: a few years ago, I also added a C-style 'for'
    statement to my language. So it had two kinds of 'for' that looked like
    this:

    for i in a..b do # also for i[:=a] to b do

    cfor A, B, C do # A B C are arbitrary expressions

    This was because I'd got fed up with people telling me all these
    wonderful things that C's for could do, that I couldn't. So now I could
    do the same!

    The feature sets in languages should (IMO) follow a design principle.
    It may make sense in one language or not in another language. I don't
    know "your language" so I cannot suggest you anything. All I can say
    is that such featuritis is, as "design principle", not something that
    I'd say you've done right as a basic design approach of your language.
    (But as often said; I don't care about "your language" and what you
    do in your personal environment.)

    So, you don't like the idea of having multiple simple features, each
    with a well defined job that a compiler can check.

    Why do you think so.

    I merely noted that if you, as the language designer, let yourself
    get triggered by feature wishes (whether they fit in your language
    design or not) that this is not what I'd consider to be sensible.
    (Unless you have no "design principles" and just featurities as a
    trigger for evolution of your language.) - Anyway, I don't care.

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Sun Apr 20 20:51:26 2025
    On 20/04/2025 17:46, Janis Papanagnou wrote:
    On 20.04.2025 13:43, bart wrote:
    On 20/04/2025 11:18, Janis Papanagnou wrote:
    On 19.04.2025 15:05, bart wrote:

    But overloading in the form of 30-40 integer types to represent the 8
    types i8-i64 and u8-u64, plus the 16 different combinations of writing
    'unsigned long long int', and so on, is fine. As are the dozens
    (hundreds?) of macros in stdint.h/inttypes.h.

    I haven't said this "is fine". It wasn't at all the topic here.

    Sorry, I forgot the rules. Only YOU are allowed to call adding one extra
    loop type 'overloading' of the language. But *I* am not allowed to call
    the plethora of integer types and support macros 'overloading' of the
    same language.


    Show me a for-loop that cannot be expressed with existing features. Many
    are likely to be clearer!

    (There have been sufficient examples posted.)

    In C? I don't recall any examples in C that could be written without 'for'.

    It makes not much sense to spread them across a multi-line block
    of statements. - If you haven't ever experienced that, and still
    cannot see and understand that if explained to you, then I can't
    help you.[*]

    Here's the example you snipped:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    In my opinion, that for-header is too complex. You can barely make out
    the condition (that lonely 'p' which you have to hunt for).

    The point is that if you have programming elements that are
    related to a loop construct (initialization, exit condition,
    update for next iteration) it makes sense to keep them together.

    So what about this then (another example you snipped):

    for(p=sqliteHashFirst(&pSchema->trigHash); p; sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)), p=sqliteHashNext(p));

    It keeps it even more together, which you seem to like.


    [*] Maybe you should visit some University courses. Despite your
    long programming history you really seem to miss some elementary
    basic programming experiences. Or are you mentally so bound to
    primitive loops and your brain so inflexible that nothing helps.

    I think it is YOU whose brain is so bound to having just the ONE kind of
    loop to do half a dozen different jobs, none of them well.


    I don't know why people think that cramming as much code as possible
    into for(...) is a good style of coding.

    But that's not what programmers should do.

    But they do! Try looking at hundreds of thousands of lines of open
    source projects like I do.

    Why do you again make
    up things. - The point is to keep things together that belong
    together.

    Why are you so crazy about putting everything onto one line? You're
    saying that:

    ONE; TWO; THREE

    is always better than:

    ONE;
    TWO;
    THREE;

    This is usually agreed to be better coding style. The same applies to
    complex type declarations which everyone tells me should use typedefs to
    break them up.

    But when 'for' is involved, it seems all common sense goes out the Window.

    This is an example which I started off trying to simplify:

    for (monthIdx = 0; monthIdx < 12 && yearDay >=
    yearDays[leapYear][monthIdx]; monthIdx++) ;

    I simply can't see it. So the first step is to turn it into a while loop:

    monthIdx = 0;
    while (monthIdx < 12 && yearDay >= yearDays[leapYear][monthIdx])
    monthIdx++;

    Now at least I can see the condition! I'm sorry, but if prefer the
    original, then I don't want to have to debug or maintain your code.

    Here I would go further and use a short loop index:

    m = 0;
    while (m < 12 && yearDay >= yearDays[leapYear][m]) ++m;

    This one is a simple iteration:

    for (character = 0; character <= 255; character++) {

    At least I can see it. However this is simply crying out to be written as:

    for (ch in 0..255)

    You don't get that? You'd rather keep it long-winded because you can do linked-lists too?!

    I just don't get the love. Or maybe, nobody here (perhaps apart from
    Keith) is willing to admit that there's anything wrong with 'for'.

    So, you don't like the idea of having multiple simple features, each
    with a well defined job that a compiler can check.

    Why do you think so.

    I merely noted that if you, as the language designer, let yourself
    get triggered by feature wishes (whether they fit in your language
    design or not) that this is not what I'd consider to be sensible.

    Huh? I have very ordinary 'for' statements that are similar to dozens of
    other languages.

    I said I tried one like C's, and it was never used. There is enough
    flexibility in the rest to deal with anything that comes up.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Mon Apr 21 00:29:52 2025
    On 20/04/2025 23:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }


    I might write it like this:

    for ( p = sqliteHashFirst(&pSchema->trigHash);
    p != NULL;
    p = sqliteHashNext(p) )
    {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    I have certain preferences (spaces around most operators, explicit
    comparison to NULL, willingness to split long lines) that other C
    programmers may or may not share.

    I rarely see complex loops split over multiple lines (mainly when they
    get so long that they'd overflow the line, but they can still be complex
    enough before then).

    But the thing is, once you split it into multiple lines, then there is
    little advantage over using a regular 'while' loop:

    p = sqliteHashFirst(&pSchema->trigHash);
    while (p != NULL)
    {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p = sqliteHashNext(p) )
    }

    The same number of lines, but now:

    * The one-time initialisatioin is isolated and out of the way

    * The execution order is more natural: the increment follows the body
    as it does at runtime.

    * It's clearly a while loop which repeats until some pointer is NULL

    (Note there can be minor differences in behaviour with statements like 'continue', or variable scope when the 'for' declares its variables.)


    It keeps it even more together, which you seem to like.

    That's something you invented. I find it ugly, and I presume you'd
    agree. The fact that you think that someone else would prefer it
    indicates that you don't understand how other people think.

    AFAIK it is legal C code, and I invented it because somebody said things
    that belong together should be together in one place. However, I have
    seen actual examples like that, in for-headers that that use
    comma-separated expressions.


    I'd rather not write `for (ch in 0..255)` because it's a syntax error.

    It's a syntax error because the form doesn't naturally exist in C; you'd
    have to emulate using macros, which is a poor solution.

    You have the luxury of using your own language.

    That 'ch in 0..255' form or close equivalent is supported by that long
    set of languages I listed earlier. It's not my invention, I just copied it.

    It is just something that is desirable. Look again at the C version: it
    looks off. (At least, you'd use a shorter loop index!)


    I said I tried one like C's, and it was never used. There is enough
    flexibility in the rest to deal with anything that comes up.

    It was never used by whom?

    By me. One use-case was porting code from C, but I didn't do much of
    that either.

    If you don't like C-style for loop, they absolutely should not
    exist in a language for which you are, if I understand correctly,
    the sole implementer and the sole user.

    But I hear so much about how wonderful it is, how multi-purpose, how indispensible, how superior to an ordinary 'for' (admittedly from people
    who don't have a choice) that I didn't want to miss out!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kenny McCormack@21:1/5 to Keith.S.Thompson+u@gmail.com on Sun Apr 20 23:19:37 2025
    In article <87ldruv65j.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    I understand and completely accept that you find the while loop
    clearer, and I have no interest in changing your mind.

    I find the for loop clearer. I won't speak for anyone else, but I
    suspect a lot of C programmers would also find the for loop clearer.

    I'm with Bart on this one. I think "for" loops that aren't simple
    iterations (i.e., do this thing 10 times), are harder to understand than
    the equivalent "while" loop. I.e., this:

    p = someComplexFunctionCall(this,that,the,other,thing);
    while (p) {
    do stuff;
    p = getNewValue(p);
    }

    is a lot easier to understand at first glance than the equivalent:

    for (p = someComplexFunctionCall(this,that,the,other,thing); p; p = getNewValue(p))
    do stuff;

    But, having said that, I'll always write the "for" version, because I like writing compact (some would say "cryptic") code. Job security, and all that...

    --
    Meatball Ron wants to replace the phrase "climate change" with the phrase "energy dominance" in policy discussions.

    Yeah, like that makes a lot of sense...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to bart on Mon Apr 21 03:07:20 2025
    bart <bc@freeuk.com> wrote:
    On 19/04/2025 20:22, James Kuyper wrote:
    On 4/19/25 12:36, Kaz Kylheku wrote:
    On 2025-04-19, Scott Lurndal <scott@slp53.sl.home> wrote:
    bart <bc@freeuk.com> writes:
    On 18/04/2025 19:10, James Kuyper wrote:
    ...
    If all you can do is "hope for the best", you're doing it wrong. It's >>>>>> your job to ensure that they are not arbitrary unrelated expressions, >>>>>> but correctly related expressions, and that's no different from your >>>>>> responsibility for all of the other expressions that make up your
    program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it >>>>> with this group?

    It's not an insult, it is a simple fact.

    It's not a fact that someone who finds tools problematic shouldn't
    be using them.

    I wasn't talking about him finding the tools problematic. I was talking
    aobut him find it difficult to ensure that the expressions are not
    arbitrary unrelated expressions, but are in fact correctly related
    expressions. If you cannot ensure that A, B, and C have the correct
    relationship to make for(A; B; C) work as needed, then you also lack to
    ability to make sure that the expressions in {A; B; C:} work together as
    needed, and that ability is fundamental to computer programming.

    In other words, the feature is dumb.

    The compiler cannot do any checking: for (i=0; i<n; ++n) is fine.

    Even in BASIC, if I do this:

    for i=1 to n
    next n

    it will say that n does not match. And here it is optional; in C that
    part is necessary.

    So, BASIC's for-loop is less dumb that C's.

    But, you have a bizarre take on this: if somebody calls it out, then
    rather than agree with them, you will personally insult the person who
    said it, and suggest that if they are incapable of such a simple check,
    then they shouldn't be coding.

    The fact is that people make typos (obviously, not you or JP or SL or
    KT!), and here you would really prefer that the compiler could report
    them, but with this feature, it often can't.

    There is low probablity of writing standard loop wrong and most
    people are not bothered that some errors are not detected at
    compile time. If you are trouble by this, solution is simple:
    do not write 'for' loops different than the simple one:

    for(int i = 0; i < B; ++i)

    or maybe a slightly more general form:

    for(int i = A; i < B; ++i)

    This restricition is easily checkable in mechanical way, checking
    it is a very small addition to C parser. You can modify your C
    compiler so that is will flag any "non simple" 'for' loop as an
    error. So, this is really non-issue for anybody who wants to
    use C, but is bothered by errors that you mention.

    If you are bothered that other people do not think that C
    flexibility is a problem, then you would need _much_ stronger
    argument, starting with some real data. And even then do not
    think that you will "win" the argument. Ada folks had strong
    arguments, namely there was a company having mixed codebase,
    partially in C, partially in Ada, with both parts of comparable
    size. They had various statistics inluding defects, showing
    that Ada was about twice time as productive as C, that is they
    were able to get the same functionality with significantly
    smaller (IIRC more than two times smaller) number of defects
    and at lower developement cost. Popularity of Ada should
    tell you how C programmers reacted to this data.

    Note: one can question validity of the Ada versus C data, in
    particular if it generalizes to other settings. However, this
    data is the best comparative data that I am aware of and I have
    little hope to see better comparison. There are also data
    about actual failures in C code. Here top issue was
    confusion between '=' and '==' in conditionals (this probably
    motivated warnings in gcc and clang about using naked assignment
    in comparisons). Guessing or hand picked examples are
    not a substitute for serious research. In particular, some
    potential issues seem to be no problem in practice, that
    is did not lead to known failure in a largish collection
    of C programs.

    BTW: In modern software number of defects due to issues that
    you discuss seem to be much lower than in the past, partially
    due to warnings from C compilers. OTOH memory errors seem to
    dominate and AFAICS you have nothing better than C have
    concering memory safety. In fact, one of most effective
    ways to improve memory safety of C programs is to use
    accessor macros or functions to check every array access.
    But this has acceptable cost only when one uses highly
    optimizing compiler.


    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Mon Apr 21 03:16:06 2025
    On 2025-04-20, bart <bc@freeuk.com> wrote:
    But the thing is, once you split it into multiple lines, then there is
    little advantage over using a regular 'while' loop:

    The advantage may be little, but there is some.

    p = sqliteHashFirst(&pSchema->trigHash);
    while (p != NULL)
    {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p = sqliteHashNext(p) )
    }

    - In a while loop, if you "continue", it will jump to the top of
    the loop, without executing the step.

    - The loop controls are not gathered in one place.

    - Because they are not gathered in one place, not only is it less
    readable, but we cannot use while write a macro such as:

    for_sqlite_hash (p, &pSchema->trigHash) {
    if (some_condition_over(p))
    continue; // doesn't stupidly repeat for the same p!
    }

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Mon Apr 21 12:57:13 2025
    On 21/04/2025 04:16, Kaz Kylheku wrote:
    On 2025-04-20, bart <bc@freeuk.com> wrote:
    But the thing is, once you split it into multiple lines, then there is
    little advantage over using a regular 'while' loop:

    The advantage may be little, but there is some.

    p = sqliteHashFirst(&pSchema->trigHash);
    while (p != NULL)
    {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p = sqliteHashNext(p) )
    }

    - In a while loop, if you "continue", it will jump to the top of
    the loop, without executing the step.

    I mentioned this. I would not call it an advantage, since it depends on
    the behaviour you want. It's just different.

    - The loop controls are not gathered in one place.

    The loop controls being .... the last line of the loop body?

    WHILE doesn't have the concept of a 'blob' that is a formal increment or
    step expression. Maybe that assignment to 'p' in the above example
    occurs in multiple places within the body.

    My own 'while' has such an optional step expression. It was intended to
    show how C could have implemented linked list traversal, since that's
    the go-to example of how flexible its 'for' is.

    I played with two kinds of syntax:

    while cond do
    body
    step
    incr # 'incr' represents anything
    end

    while cond, incr do
    body
    end

    When the experiment was over, I decided to keep that second syntax, and
    it is sometimes used. But I can't use it when the factors that will
    affect the next 'cond' are complex.

    Currently, from 20-30% of while loops use that form, almost exclusively
    for linked list traversal.

    It doesn't affect the normal while-loops. It doesn't impinge on normal
    for loops either.

    (My version of 'continue' will not skip the step part, but it is also
    very rarely used.)

    - Because they are not gathered in one place, not only is it less>
    readable, but we cannot use while write a macro such as:

    for_sqlite_hash (p, &pSchema->trigHash) {
    if (some_condition_over(p))
    continue; // doesn't stupidly repeat for the same p!
    }

    I can't write such macros at all. I'm not even sure what this does.

    I'd call that a win!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to bart on Mon Apr 21 07:34:11 2025
    bart <bc@freeuk.com> wrote:
    On 19/04/2025 20:22, James Kuyper wrote:
    ...
    I wasn't talking about him finding the tools problematic. I was talking
    aobut him find it difficult to ensure that the expressions are not
    arbitrary unrelated expressions, but are in fact correctly related
    expressions. If you cannot ensure that A, B, and C have the correct
    relationship to make for(A; B; C) work as needed, then you also lack to
    ability to make sure that the expressions in {A; B; C:} work together as
    needed, and that ability is fundamental to computer programming.

    In other words, the feature is dumb.

    The feature allows you to pack all of the loop management stuff together
    where it's easy to check and think about. It can be misused, by putting together stuff that has nothing to do with loop management, just as an assignment statement can be misused by writing, for instance

    annual_salary = current_income + age;

    The compiler cannot do any checking: for (i=0; i<n; ++n) is fine.

    The compiler cannot tell you what's wrong with that assignment
    statement, either.

    Even in BASIC, if I do this:

    for i=1 to n
    next n>
    it will say that n does not match. And here it is optional; in C that
    part is necessary.

    It's been a while since I've written basic, but looking at that syntax I believe it would be equally feasible to write

    for i=start_year to months_per_year

    Can BASIC protect you from misusing it's for statement by putting in the
    wrong expressions for the start and end of the loop? Then why would
    expect C's loop construct to do any better?

    But, you have a bizarre take on this: if somebody calls it out, then
    rather than agree with them, you will personally insult the person who
    said it, and suggest that if they are incapable of such a simple check,
    then they shouldn't be coding.

    How can I respond by agreeing with an incorrect assessment? And the
    insults are the consequence of your endlessly successful search to find
    new ways to misunderstand C.

    The fact is that people make typos (obviously, not you or JP or SL or

    I make typos all the time. I love language features that let me catch my
    typos. That's one reason why I like languages that provide features like
    "for each employee in employee_list", but I see little advantage to a
    for statement limited in the fashion you desire. It's easily emulated by
    the more flexible for-statement that also allows me to do many other
    things as well.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Mon Apr 21 12:26:53 2025
    On 21/04/2025 03:08, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:

    But I hear so much about how wonderful it is, how multi-purpose, how
    indispensible, how superior to an ordinary 'for' (admittedly from
    people who don't have a choice) that I didn't want to miss out!

    Again, stop misrepresenting what other people say.

    Wonderful? No, I don't recall anyone other than you using that word,
    and only sarcastically.

    I used 'wonderful' to summarise what people arguing against me have said
    about it. Am I not allowed to use an adjective unless it's one that
    somebody else has already used? If so, how come they're allowed to use
    it first?

    You're being silly here.


    Multi-purpose? Yes, absolutely.

    You hit the nail on the head. Take this previously posted example:

    for (character = 0; character <= 255; character++) {

    Such syntax for a trivial iteration seems to be tolerated; why? Because
    it can also be adapted to traversing linked lists? That's just irrational!

    Indispensible? No, I don't believe anyone has made that claim, and it
    would be inaccurate.

    Well, any control flow can be implemented with goto. But if you suggest
    to people that they lose those bizarre capabilities of 'for' they will
    be aghast. How on earth will they express all those weird and wonderful constructs.

    Just read the thread if you don't believe me!

    Superior to an ordinary 'for'? Certainly a lot of people think it is, because of its flexibility.

    Yes, some people have said some of these. Are you suggesting that
    everyone needs to have said all of those things before I can make such a remark?

    I think it's quite clear what the attitude of most here is.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to James Kuyper on Mon Apr 21 13:26:17 2025
    On 21/04/2025 12:34, James Kuyper wrote:
    bart <bc@freeuk.com> wrote:
    On 19/04/2025 20:22, James Kuyper wrote:
    ...
    I wasn't talking about him finding the tools problematic. I was talking
    aobut him find it difficult to ensure that the expressions are not
    arbitrary unrelated expressions, but are in fact correctly related
    expressions. If you cannot ensure that A, B, and C have the correct
    relationship to make for(A; B; C) work as needed, then you also lack to
    ability to make sure that the expressions in {A; B; C:} work together as >>> needed, and that ability is fundamental to computer programming.

    In other words, the feature is dumb.

    The feature allows you to pack all of the loop management stuff together where it's easy to check and think about. It can be misused, by putting together stuff that has nothing to do with loop management, just as an assignment statement can be misused by writing, for instance

    annual_salary = current_income + age;

    The compiler cannot do any checking: for (i=0; i<n; ++n) is fine.

    The compiler cannot tell you what's wrong with that assignment
    statement, either.

    You don't understand the issue. OK, that's fine. Because it is possible
    to make typos at any point in the source code, then it doesn't matter if
    the language provides unnecessary extra opportunities for those errors.

    All those languages with strict type systems to allow more compile-time error-checking are pointless, since nothing stops you writing 'a = 0'
    instead of 'a = 1'.

    But there is also the human aspect; which of these for-loops have typos
    (assume that 'i' and 'n' are the right spellings):

    for (i=0; i<n; ++n)
    for (i=0; i<n; --i)
    for (i=0; i<=n; ++i)
    for (i=0; i<n; ++i)

    That fact is, you can't tell. It depends on intention, which is unclear /because/ of the flexibility of the construct. That second example looks
    dodgy, but the compiler can't pick that up either.

    In that case, I have to ask, why even bother with such a construct. Just
    have:

    i = 0;
    L1:
    if (i<n) goto L2;
    ...
    ++i;
    goto L1
    L2:

    This is even more flexible.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Mon Apr 21 13:46:21 2025
    On 21/04/2025 04:07, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 19/04/2025 20:22, James Kuyper wrote:
    On 4/19/25 12:36, Kaz Kylheku wrote:
    On 2025-04-19, Scott Lurndal <scott@slp53.sl.home> wrote:
    bart <bc@freeuk.com> writes:
    On 18/04/2025 19:10, James Kuyper wrote:
    ...
    If all you can do is "hope for the best", you're doing it wrong. It's >>>>>>> your job to ensure that they are not arbitrary unrelated expressions, >>>>>>> but correctly related expressions, and that's no different from your >>>>>>> responsibility for all of the other expressions that make up your >>>>>>> program.



    If you find that problematic, you shouldn't be programming in
    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What is it >>>>>> with this group?

    It's not an insult, it is a simple fact.

    It's not a fact that someone who finds tools problematic shouldn't
    be using them.

    I wasn't talking about him finding the tools problematic. I was talking
    aobut him find it difficult to ensure that the expressions are not
    arbitrary unrelated expressions, but are in fact correctly related
    expressions. If you cannot ensure that A, B, and C have the correct
    relationship to make for(A; B; C) work as needed, then you also lack to
    ability to make sure that the expressions in {A; B; C:} work together as >>> needed, and that ability is fundamental to computer programming.

    In other words, the feature is dumb.

    The compiler cannot do any checking: for (i=0; i<n; ++n) is fine.

    Even in BASIC, if I do this:

    for i=1 to n
    next n

    it will say that n does not match. And here it is optional; in C that
    part is necessary.

    So, BASIC's for-loop is less dumb that C's.

    But, you have a bizarre take on this: if somebody calls it out, then
    rather than agree with them, you will personally insult the person who
    said it, and suggest that if they are incapable of such a simple check,
    then they shouldn't be coding.

    The fact is that people make typos (obviously, not you or JP or SL or
    KT!), and here you would really prefer that the compiler could report
    them, but with this feature, it often can't.

    There is low probablity of writing standard loop wrong and most
    people are not bothered that some errors are not detected at
    compile time. If you are trouble by this, solution is simple:
    do not write 'for' loops different than the simple one:

    What about when you're working with other people's code? Every for-loop
    you encounter is a little puzzle that you have to decode to find out its category! (There are about 4 categories plus 'free-style'.)

    If you are bothered that other people do not think that C
    flexibility is a problem, then you would need _much_ stronger
    argument, starting with some real data.

    I don't now think think there is any argument that will make any
    difference. People here genuinely think that writing:

    for (ch = 0; ch <= 255; ++ch)

    is far superior to this 'primitive' version:

    do ch = 0, 255

    No amount of discussion or arguments will make them change their minds.

    (BTW I had to fix two typos in the C, as in the first version I
    initially used 'ch, c and c'!)

    Apparently, the C form is superior because that construct can also be
    used to conveniently express link-list traversal, and a lot more.

    Even the idea of having *two* kinds of loop, one as it works now, and
    one more streamlined, was not acceptable: too much 'overloading' of the language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to bart on Mon Apr 21 13:51:04 2025
    bart <bc@freeuk.com> wrote:

    I don't know why people think that cramming as much code as possible
    into for(...) is a good style of coding. Either into one over-long line,
    or spilling over multiple lines; both should fail a code review.

    Actually here's a example from sqlite3.c:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    And this is how you might be forced to write it instead:

    p=sqliteHashFirst(&pSchema->trigHash);
    while (p) {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p=sqliteHashNext(p);
    }

    Yes, it's spread over two more lines, but so what? It's much clearer:
    the initialisation is done once and then it's out of the way. Setting p
    to the next value is now physically written after the body.

    Apparently you do not get why sqlite3.c version is better.
    In short, this is separation of concerns. The 'for' construct
    is responsible for iteration. Body of 'for' loop is responsible
    for computation. You may replace body by empty instruction,
    so there are no computation but the loop still correctly goes
    over the same sequence. Or you may add instructions to perform
    more computation. 'while' version mixes computation with
    stepping to the next element. Since in 'for' version all parts
    dealing with iteration are together it is easy to check that
    they are correct. With 'while' version probablity of forgeting
    to step to next element is higher.

    FYI: I do not remember making error in a simple 'for' loop.
    I do remember cases when I had to use 'while' for iteration
    (in non-C languages) and stepping was wrong/missing. So
    for me simple loops (your 98% of cases) are not an issue.
    The issue are remaining cases, and for them C 'for' works
    better.

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Mon Apr 21 16:36:01 2025
    On 21/04/2025 14:51, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    I don't know why people think that cramming as much code as possible
    into for(...) is a good style of coding. Either into one over-long line,
    or spilling over multiple lines; both should fail a code review.

    Actually here's a example from sqlite3.c:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    And this is how you might be forced to write it instead:

    p=sqliteHashFirst(&pSchema->trigHash);
    while (p) {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p=sqliteHashNext(p);
    }

    Yes, it's spread over two more lines, but so what? It's much clearer:
    the initialisation is done once and then it's out of the way. Setting p
    to the next value is now physically written after the body.

    Apparently you do not get why sqlite3.c version is better.
    In short, this is separation of concerns. The 'for' construct
    is responsible for iteration. Body of 'for' loop is responsible
    for computation. You may replace body by empty instruction,
    so there are no computation but the loop still correctly goes
    over the same sequence. Or you may add instructions to perform
    more computation. 'while' version mixes computation with
    stepping to the next element. Since in 'for' version all parts
    dealing with iteration are together it is easy to check that
    they are correct. With 'while' version probablity of forgeting
    to step to next element is higher.

    You have to analyse it first. The kind of loop this expresses is:

    p = startvalue()

    while (p) {
    <body>
    p = nextvalue()
    }

    Notice how I chose to express it: it reflects how I would describe it in English:

    * Set P to Start Value
    * While P isn't Null:
    * Execute the body
    * Set P to Next Value

    So, how would /you/ describe it in English? (Or in any language if like,
    as the ordering is more important.)

    In short, this is separation of concerns.

    You seem be picking and choosing which concerns are in need of separation!

    The example is this: for(A; B; C) D

    You are saying that D must be separate from A B C, but specifically from C.

    I'm asking, why shouldn't A B C also be separate from each other?

    Especially A, which is only executed once, after which it's no longer
    part of the loop.

    As C works now, the alternative might be: A; while (B) { D; C;}.

    I wouldn't have minded a syntax like: A; while (B; C) {D} but C doesn't
    have that. In that case, the 'while' version still wins over 'for' IMO.


    FYI: I do not remember making error in a simple 'for' loop.
    I do remember cases when I had to use 'while' for iteration
    (in non-C languages) and stepping was wrong/missing. So
    for me simple loops (your 98% of cases) are not an issue.

    The issue are remaining cases, and for them C 'for' works
    better.

    That's bizarre. It is exactly like saying you don't have a problem with
    writing (or forgetting to write) 'break' in 99% of switch-case blocks,
    because in those 1% of cases where you do want fallthroughit is 'automatic'.

    I expect you also either think that:

    for (ch = 0; ch <= 255; ++ch)

    is better than: 'do ch = 0, 255', or is much more tolerant of it than I am.

    Here's how that C for-loop works, in English:

    * Set ch to 0
    * While c is less than or equal to 255: (typo left in!)
    * Execute the body
    * Set ch to ch + 1

    Here is how that compact version works, in English:

    * For ch having the values 0 to 255 inclusive:
    * Execute the body

    However I see that nobody in this group has any objective interest in
    language ergonomics and aesthetics. They more interested in defending
    'their' language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Mon Apr 21 18:43:40 2025
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 04:16, Kaz Kylheku wrote:
    - Because they are not gathered in one place, not only is it less>
    readable, but we cannot use while write a macro such as:

    for_sqlite_hash (p, &pSchema->trigHash) {
    if (some_condition_over(p))
    continue; // doesn't stupidly repeat for the same p!
    }

    I can't write such macros at all. I'm not even sure what this does.

    Have you never worked with a large codebase written by someone other
    than you?

    When you open a random file in an unfamiliar code base, pretty
    much any function call that is not in the standard library triggers
    the "I don't know what this does" response.

    You have to learn some of that program's definitions in order to
    effectively work with that program. At least those which are relevant to
    your intended task. You set up your "jump to definition" editor-fu and
    start reading.

    A loop macro like for_sqlite_hash (p, &pSchema->trigHash) is so obvious
    that the only reason you'd look at its definition is to confirm that
    it's not doing something stupid (which can be defined as just about
    anything different from what it *looks* like it is doing).

    I'd call that a win!

    Now you're calling the inability of the programmer to implement a
    nice space-saving notation over something verbose a "win".

    If so, why isn't "for (a; b; c)" also a "win" over "do i = x, y".

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Mon Apr 21 20:57:13 2025
    On 21/04/2025 19:43, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 04:16, Kaz Kylheku wrote:
    - Because they are not gathered in one place, not only is it less>
    readable, but we cannot use while write a macro such as:

    for_sqlite_hash (p, &pSchema->trigHash) {
    if (some_condition_over(p))
    continue; // doesn't stupidly repeat for the same p!
    }

    I can't write such macros at all. I'm not even sure what this does.

    Have you never worked with a large codebase written by someone other
    than you?

    How large are we talking about?

    I've delved into largish apps in the context of getting my C compiler
    working. I would describe that experience as 'brutal'. If you need to
    debug someone else's codebase, not to find bugs in that program, but to
    find why your implementation is failing, then you want as conservative a
    coding style as possible.


    When you open a random file in an unfamiliar code base, pretty
    much any function call that is not in the standard library triggers
    the "I don't know what this does" response.

    Yes, a function call. Macros are in an entirely different, evil category.

    The Lua sources (only a mere 30Kloc), use macros extensively, but also
    have a habit of giving them ordinary looking names in lower case so that
    they look like function calls.

    Preprocessing such code doesn't help either, since a simple function
    call can expand into a horrendously complex expression that can be 100s
    of characters long and have parentheses nested 10 deep.

    You have to learn some of that program's definitions in order to
    effectively work with that program. At least those which are relevant to
    your intended task. You set up your "jump to definition" editor-fu and
    start reading.

    A loop macro like for_sqlite_hash (p, &pSchema->trigHash) is so obvious

    Please humour me: What Does It Do?

    that the only reason you'd look at its definition is to confirm that
    it's not doing something stupid (which can be defined as just about
    anything different from what it *looks* like it is doing).

    I'd call that a win!

    Now you're calling the inability of the programmer to implement a
    nice space-saving notation over something verbose a "win".

    If so, why isn't "for (a; b; c)" also a "win" over "do i = x, y".

    Your example is just this:

    X(Y, Z)

    and you're claiming it is something wonderful. Is it? I don't know. I
    might guess from its name that it is something to do with loops.

    So what do X and Y represent, and what do they expand to?

    What I might deduce, is that in C if you have a block of code like this:

    {body}

    You can turn that into a loop by putting a for-header to its left:

    for(...) {body}

    That for-header can come from a macro, so can be used to apply a loop to
    such a block, without the code block itself needing to be a macro argument.

    I will admit that is a useful side-effect of how a for-loop works, so
    that it becomes a helpful feature if you ever need to write such macros.

    I can't do that in my language; the macros are too simple, and the loop
    body would need to be an argument, requiring closures etc. But then, the existing loop features are adequate, and it is also easy to add new ones
    by changing the language.

    A macro solution would anyway be poor in terms of nice syntax, error
    reporting and so on.

    (I'm just remembered I have a visualisation that can turn C syntax into
    my syntax (but it's not good enough to compile). It turns:


    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    into:

    p := pSchema^.trigHash.first
    while p do
    sqlite3DeleteTrigger(db, ref Trigger(p^.data))
    p := p^.next
    od

    You can now see that the C version involves macros. The increment has
    now also been resolved into a simple member access.

    Turning it into decent syntax and GETTING RID of macros has produced
    cleaner looking code!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Mon Apr 21 20:25:58 2025
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 19:43, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 04:16, Kaz Kylheku wrote:
    - Because they are not gathered in one place, not only is it less>
    readable, but we cannot use while write a macro such as:

    for_sqlite_hash (p, &pSchema->trigHash) {
    if (some_condition_over(p))
    continue; // doesn't stupidly repeat for the same p!
    }

    I can't write such macros at all. I'm not even sure what this does.

    Have you never worked with a large codebase written by someone other
    than you?

    How large are we talking about?

    Several 100K to millions.

    I've delved into largish apps in the context of getting my C compiler working. I would describe that experience as 'brutal'.

    Well, that brutal experience is the job of the career software engineer, believe it or not. Very few work only on their own original code.

    If you need to
    debug someone else's codebase, not to find bugs in that program, but to
    find why your implementation is failing, then you want as conservative a coding style as possible.


    When you open a random file in an unfamiliar code base, pretty
    much any function call that is not in the standard library triggers
    the "I don't know what this does" response.

    Yes, a function call. Macros are in an entirely different, evil category.

    No, they aren't. They are just another definition to understand.

    They can be misused, and also used to make solutions that are more
    complicated than some great ideas that don't involve macros.

    So can anything: an open coded function can be misused to make some
    complicated solution that can be more nicely done with macros.

    The Lua sources (only a mere 30Kloc), use macros extensively, but also
    have a habit of giving them ordinary looking names in lower case so that
    they look like function calls.

    So does ISO C; e.g. assert (expr); offsetof (type, member). So what?

    Macros that provide syntax should blend into the language.

    There is some sense in upper case for preprocessor constants.

    Those that have short names can easily clash with variables.

    Preprocessor constants are often under-typed.

    Preprocessing such code doesn't help either, since a simple function
    call can expand into a horrendously complex expression that can be 100s
    of characters long and have parentheses nested 10 deep.

    You have to learn some of that program's definitions in order to
    effectively work with that program. At least those which are relevant to
    your intended task. You set up your "jump to definition" editor-fu and
    start reading.

    A loop macro like for_sqlite_hash (p, &pSchema->trigHash) is so obvious

    Please humour me: What Does It Do?

    It is intended to condense an interation that *you* open-coded, in this
    example upthread:

    p = sqliteHashFirst(&pSchema->trigHash);
    while (p != NULL)
    {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p = sqliteHashNext(p) )
    }

    So although I didn't show the definition, I think, of course the intent that it does this (i.e. is relevant to the discussion thread) and not something else.

    for_sqlite_hash (p, hashptr) stmet

    must initialize p using sqliteHashFirst(hashPtr); then
    execute stmt if p is not not null, and step to the next entry
    using sqliteHashNext(p), assigned back to p:

    #define for_sqlite_hash(P, H) \
    for ((P) = sqliteHashFirst(H); P; (P) = sqliteHashNext(P))

    I'm taking it for granted that sqliteHashFirst, which came from your
    post, initiates an iteration, etc. I intuited that without needing it explained.

    that the only reason you'd look at its definition is to confirm that
    it's not doing something stupid (which can be defined as just about
    anything different from what it *looks* like it is doing).

    I'd call that a win!

    Now you're calling the inability of the programmer to implement a
    nice space-saving notation over something verbose a "win".

    If so, why isn't "for (a; b; c)" also a "win" over "do i = x, y".

    Your example is just this:

    X(Y, Z)

    and you're claiming it is something wonderful. Is it?

    You're also claiming that "for X in A, B" (or what have you) is something wonderful compared to "for (X = A; X <= B; X++)".

    If I had to write 17 loops over SQLite hashes, I'd rather type for_sqlite_hash(p, hash) than
    for (p = sqliteHashFirst(hash); p; p = sqliteHashNext(hash)).

    I don't know. I
    might guess from its name that it is something to do with loops.

    You can guess from its name that it has something to do with loops
    over sqlite hashes.

    Just like I guessed from sqliteHashBegin that it has something to
    with initiating an iteration over a hash, using a pointer-typed
    cursor.

    So what do X and Y represent, and what do they expand to?

    What I might deduce, is that in C if you have a block of code like this:

    {body}

    You can turn that into a loop by putting a for-header to its left:

    for(...) {body}

    That for-header can come from a macro, so can be used to apply a loop to
    such a block, without the code block itself needing to be a macro argument.

    I will admit that is a useful side-effect of how a for-loop works, so
    that it becomes a helpful feature if you ever need to write such macros.

    I added a local variable binding extension to GNU Awk (in an Enhanced GNU Awk fork).

    I gave it this syntax;

    let (x = 0, y = 1, z) { ... body ...}

    guess why! This works with macros. This doesn't:

    { let x = 0, y = 1, z; ... body ...}

    I can't do that in my language; the macros are too simple, and the loop
    body would need to be an argument, requiring closures etc. But then, the existing loop features are adequate, and it is also easy to add new ones
    by changing the language.

    It's not easy to add new things by changing the language, when the language is widely deployed, and implemented by multiple vendors.

    Even the users who follow a single implementation might balk;
    "Sorry, it has to work with the language that is packaged for Ubuntu 20".

    It's a lot, lot better if a program can encode it sown language extension which works with all major implementations going back 20 years in their versions.

    A macro solution would anyway be poor in terms of nice syntax, error reporting and so on.

    Sure; but that can often be beaten by Works Everywhere.

    (I'm just remembered I have a visualisation that can turn C syntax into
    my syntax (but it's not good enough to compile). It turns:


    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    into:

    p := pSchema^.trigHash.first
    while p do
    sqlite3DeleteTrigger(db, ref Trigger(p^.data))
    p := p^.next
    od

    You can now see that the C version involves macros. The increment has
    now also been resolved into a simple member access.

    Turning it into decent syntax and GETTING RID of macros has produced
    cleaner looking code!)

    In a clean room language, you have an opportunity to make an excellent
    macro system which has answers for error reporting, identifier hygiene, multiple evaluation ...

    The weaknesses in C macros are a strawman against macros as such.

    Yet, I will take C macros over no macros.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to bart on Mon Apr 21 21:06:01 2025
    bart <bc@freeuk.com> wrote:
    On 21/04/2025 14:51, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    I don't know why people think that cramming as much code as possible
    into for(...) is a good style of coding. Either into one over-long line, >>> or spilling over multiple lines; both should fail a code review.

    Actually here's a example from sqlite3.c:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ >>> sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    And this is how you might be forced to write it instead:

    p=sqliteHashFirst(&pSchema->trigHash);
    while (p) {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p=sqliteHashNext(p);
    }

    Yes, it's spread over two more lines, but so what? It's much clearer:
    the initialisation is done once and then it's out of the way. Setting p
    to the next value is now physically written after the body.

    Apparently you do not get why sqlite3.c version is better.
    In short, this is separation of concerns. The 'for' construct
    is responsible for iteration. Body of 'for' loop is responsible
    for computation. You may replace body by empty instruction,
    so there are no computation but the loop still correctly goes
    over the same sequence. Or you may add instructions to perform
    more computation. 'while' version mixes computation with
    stepping to the next element. Since in 'for' version all parts
    dealing with iteration are together it is easy to check that
    they are correct. With 'while' version probablity of forgeting
    to step to next element is higher.

    You have to analyse it first. The kind of loop this expresses is:

    p = startvalue()

    while (p) {
    <body>
    p = nextvalue()
    }

    Notice how I chose to express it: it reflects how I would describe it in English:

    * Set P to Start Value
    * While P isn't Null:
    * Execute the body
    * Set P to Next Value

    So, how would /you/ describe it in English? (Or in any language if like,
    as the ordering is more important.)

    I would describe original sqlite3.c loop as "iteration over elements
    of hash table". That assumes that Sqlite folks choose sensible
    names. This is higher level view than you apparently have.

    BTW: I do not know how Sqlite folks implemented 'sqliteHashNext',
    but I would expect semi-random order of elements. What matters
    is that iteration goes over all elements in the hash table.

    BTW2: When looking at 'for' loop you are supposed to see pattern,
    without need to track all steps.

    In short, this is separation of concerns.

    You seem be picking and choosing which concerns are in need of separation!

    Yes.

    The example is this: for(A; B; C) D

    You are saying that D must be separate from A B C, but specifically from C.

    I'm asking, why shouldn't A B C also be separate from each other?

    The intent of 'for' is to iterate over some collection. Each of
    A, B, C is needed to know the collection.

    Especially A, which is only executed once, after which it's no longer
    part of the loop.

    Without A you do not know range of iteration. Putting A just before
    'while' loop is not too bad, as it is still pretty close to the
    loop and B. But when using 'while' C potentially could be quite
    far from A and B.

    As C works now, the alternative might be: A; while (B) { D; C;}.

    I wouldn't have minded a syntax like: A; while (B; C) {D} but C doesn't
    have that. In that case, the 'while' version still wins over 'for' IMO.


    FYI: I do not remember making error in a simple 'for' loop.
    I do remember cases when I had to use 'while' for iteration
    (in non-C languages) and stepping was wrong/missing. So
    for me simple loops (your 98% of cases) are not an issue.

    The issue are remaining cases, and for them C 'for' works
    better.

    That's bizarre. It is exactly like saying you don't have a problem with writing (or forgetting to write) 'break' in 99% of switch-case blocks, because in those 1% of cases where you do want fallthroughit is 'automatic'.

    No, this subtly different. I do not have problem with writing 'break',
    as it is mandatory in vast majority of C loops. You may think about
    it as mandatory sacrifice to gods of C. When you forget it you will
    be punished and after punishment you will remember to put it. Yes,
    it is silly but there is a lot of mandatory sillines in real life,
    one just adapts and goes on. The difference compared to 'for' is
    that there are easy alternatives to falltrough by default.

    I expect you also either think that:

    for (ch = 0; ch <= 255; ++ch)

    is better than: 'do ch = 0, 255', or is much more tolerant of it than I am.

    In 1975 C version was better: it allowed flexible loops using very
    simple compiler. If you do not mind some compiler complexity you
    can do better (I consider 'do ch = 0, 255' to be rather bad, IMO
    something like 'for ch in 0..255' or 'for ch := 0 to 255' is better).
    But IMO main reason that C won competition for system language was
    that C compiler could be quite simple while generating efficient
    code and allowing powerful constructs.

    IMO there are now good reasons to create a different system
    language. But C loops are tiny part of issues and alone (or
    even combined with other issues that you mentioned like 'break'-s
    in 'switch'-es and declaration syntax) not enough.

    Here's how that C for-loop works, in English:

    * Set ch to 0
    * While c is less than or equal to 255: (typo left in!)
    * Execute the body
    * Set ch to ch + 1

    Here is how that compact version works, in English:

    * For ch having the values 0 to 255 inclusive:
    * Execute the body

    However I see that nobody in this group has any objective interest in language ergonomics and aesthetics. They more interested in defending
    'their' language.

    Note that this is C group. If you find new way of writing C code
    which is more convenient and nicer than existing ways, then people
    here may be interested. Or if you propose a compatible extention.

    But saying that C is bad rarely brings someting new, people here
    know most of C warts and have ways to cope with them. If they
    thought that some other language is really better they would use
    it instead of C. FYI, I do probably majority of my coding in
    different languages. However, "better" includes factors as
    availability of optimizing compilers and libraries. And
    availabiity of skill: language which has interesting features
    that you do not understand is not good for you.

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Keith Thompson on Tue Apr 22 00:14:44 2025
    On 21.04.2025 23:21, Keith Thompson wrote:
    [...]

    C-style for loops have been used successfully for decades, and have
    been adopted by other languages (including bash, which isn't
    particularly C-like).

    I have to disagree on that. First I'm positive that Bash adopted
    the Ksh loops (but incompletely!), and not the "C" loops.

    And, as opposed to Ksh (and "C"), Bash doesn't support FP valued
    loops.

    (As previously said, Unix shell in general and Bash specifically
    is not a good comparison WRT "C" loops.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Mon Apr 21 22:16:54 2025
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    I don't now think think there is any argument that will make any
    difference. People here genuinely think that writing:

    for (ch = 0; ch <= 255; ++ch)

    is far superior to this 'primitive' version:

    do ch = 0, 255

    Obviously, the former is more primitive, because the second can
    be made out of the first with a preprocessor, whereas the converse
    is not true. If A can be made out of B, but B not out of A,
    B is more primitive.

    The former is undeniably more verbose for the uses provided by the
    second.

    It is also much more flexible.

    Thanks to the macro preprocessor, it can almost express the second form,
    just with more punctuation:

    for_range (ch, 0, 255)

    If a built-in "do" range loop existed in C, it would likely have
    the parentheses.

    No amount of discussion or arguments will make them change their minds.

    Mostly, you are projecting onto people opinions they don't actually
    have.

    (BTW I had to fix two typos in the C, as in the first version I
    initially used 'ch, c and c'!)

    Apparently, the C form is superior because that construct can also be
    used to conveniently express link-list traversal, and a lot more.

    It has superior flexibility. Flexible is not a synonym for superior; flexibility doesn't make something unequivocally superior, unless we can
    hold "all else equal". We can almost never do that. Here, the flexible
    thing is more verbose, and there are challenges implementing a simple
    range iteration that can go (for instance) all the way to INT_MAX,
    whereas the less primitive loop can get that right and completely hide
    it from the programmer.

    Even the idea of having *two* kinds of loop, one as it works now, and
    one more streamlined, was not acceptable: too much 'overloading' of the language.

    You're also not a fan of unbridled language extension, based on your
    past opinions about, oh, C++ and whatnot.

    Your primary reaction to some new idea is to reject it as complex
    fluff that you'd rather not undertand.

    How brushed up are you in using C17 or C23?

    You've also expressed oppositions to extending C, because
    development of C makes it a moving target for your projects.

    Of course people are going to push back on the idea of making new
    statements, if they can be decently obtained or simulated using
    preprocessing.

    Would you support an "unless" statement being added to C, given
    that we can just:

    #define unless(x) if(!(x))

    Or, unless which does not take else:

    #define unless(x) if (x) { } else

    Adding a new statement to C is a big deal, compared to someone
    adding a macro to their code.

    Literally the first question about any proposal for a new language
    feature is going to be: can obtain that, or substantially obtain it
    using existing features

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Janis Papanagnou on Tue Apr 22 00:19:50 2025
    On 22.04.2025 00:14, Janis Papanagnou wrote:
    On 21.04.2025 23:21, Keith Thompson wrote:
    [...]

    C-style for loops have been used successfully for decades, and have
    been adopted by other languages (including bash, which isn't
    particularly C-like).

    I have to disagree on that. First I'm positive that Bash adopted
    the Ksh loops (but incompletely!), and not the "C" loops.

    And, as opposed to Ksh (and "C"), Bash doesn't support FP valued
    loops.

    Ah, I forgot; but Bash seems to support comma-subexpressions in
    loops (as opposed to Ksh). - So this is even more valid (given
    all the inconsistencies and differences across shells and "C"):

    (As previously said, Unix shell in general and Bash specifically
    is not a good comparison WRT "C" loops.)

    Janis


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Mon Apr 21 23:54:21 2025
    On 21/04/2025 22:06, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    t iteration goes over all elements in the hash table.

    BTW2: When looking at 'for' loop you are supposed to see pattern,
    without need to track all steps.

    That's one of the disadvantages of using the same, often /inappropriate/ keyword for every kind of pattern.

    This is the original C again:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    This is the version that my visualisation tool produced (where C source
    is visualised in my syntax); posted earlier but it's worth posting again:

    p := pSchema^.trigHash.first
    while p do
    sqlite3DeleteTrigger(db, ref Trigger(p^.data))
    p := p^.next
    od

    While the C version looks intimidating, this looks much cleaner and
    simpler (expanding those macros helped).

    The intent of 'for' is to iterate over some collection. Each of
    A, B, C is needed to know the collection.

    Sure, but ALL ON THE SAME LINE? All within the same parentheses? Putting multiple things on the same line is usually frowned upon. Look at these ludicrous examples:

    for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){

    for (yoffset = coef->MCU_vert_offset; yoffset <
    coef->MCU_rows_per_iMCU_row; yoffset++) {

    for (bi = 0; bi < num_blocks; bi++, start_col +=
    compptr->DCT_h_scaled_size) {....}

    I /think/ the last two are simple iterations!

    Notice that that last bit of the last example is nothing to do with the mechanics of the iteration; it's to do with the body.

    Especially A, which is only executed once, after which it's no longer
    part of the loop.

    Without A you do not know range of iteration.

    I've seen plenty of for-loops that start with 'for (;...)'; that doesn't
    seem to worry anyone! Which is not surprising; nobody seems to care
    anything here.

    I expect you also either think that:

    for (ch = 0; ch <= 255; ++ch)

    is better than: 'do ch = 0, 255', or is much more tolerant of it than I am.

    In 1975 C version was better: it allowed flexible loops using very
    simple compiler.

    How complicated was a 1950s Fortran compiler? A 1964 BASIC interpreter?
    My own 1981 compiler implemented in 8KB? All supported such loops.

    There is no excuse. This is a Pascal program with such a loop:

    program loop(output);
    var c:integer;
    begin
    for c := 0 to 255 do
    writeln(c);
    end.

    I can run it with a toy Pascal compiler that is 22KB (of x64 code).

    But saying that C is bad rarely brings someting new, people here
    know most of C warts and have ways to cope with them. If they
    thought that some other language is really better they would use
    it instead of C. FYI, I do probably majority of my coding in
    different languages.

    And yet, even within the limitations of C, people favour writing
    appalling code, when it could be much cleaner. So (1) they don't care;
    and (2) try to justify that bad code as being better.

    Here's that visualisation example above, converted into C:

    p = pSchema->trigHash.first;
    while (p) {
    sqlite3DeleteTrigger(db, ref Trigger(p->data));
    p = p->next;
    }

    Compare with the original C at the top.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Mon Apr 21 23:46:40 2025
    bart <bc@freeuk.com> writes:
    On 21/04/2025 21:25, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:

    op_arith(L, l_addi, luai_numadd);

    Innocent-looking isn't it? It expands to this:

    Doesn't matter, nobody will ever look at the expansion. It's
    actually a good thing, since it found a bug in your compiler.


    Given that, do you /really/ need that extra layer of complexity via that >macro?

    If I had to write 17 loops over SQLite hashes, I'd rather type
    for_sqlite_hash(p, hash) than
    for (p = sqliteHashFirst(hash); p; p = sqliteHashNext(hash)).

    I guess that answers that question! I'd use macros only as a last
    resort; you would use them at the first opportunity.


    Obviously the entire world-wide programming community
    disagrees with your opinions.

    Here's a very large C project that heavily uses
    a for-based macro.

    $ grep for_each kernel/*.c |wc -l
    284
    $ grep for_each kernel/*.c |head
    kernel/acct.c: for_each_vma(vmi, vma)
    kernel/audit_tree.c: list_for_each_entry_rcu(p, list, hash) { kernel/audit_tree.c: list_for_each_entry(owner, &new->trees, same_root) kernel/audit_tree.c: list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
    kernel/audit_tree.c: list_for_each_entry(node, &tree->chunks, list) {
    kernel/audit_tree.c: list_for_each_entry(tree, &tree_list, list) { kernel/audit_tree.c: list_for_each_entry(node, &tree->chunks, list) kernel/audit_tree.c: list_for_each_entry(node, &tree->chunks, list)
    kernel/audit_watch.c: list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
    kernel/audit_watch.c: list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {

    $ grep for_each */*.c |wc -l
    1599
    $ grep for_each */*/*.c | wc -l
    12015
    $ grep for_each */*/*/*.c | wc -l
    9077

    include/linux/list.h:

    /**
    * list_prev_entry_circular - get the prev element in list
    * @pos: the type * to cursor.
    * @head: the list head to take the element from.
    * @member: the name of the list_head within the struct.
    *
    * Wraparound if pos is the first element (return the last element).
    * Note, that list is expected to be not empty.
    */
    #define list_prev_entry_circular(pos, head, member) \
    (list_is_first(&(pos)->member, head) ? \
    list_last_entry(head, typeof(*(pos)), member) : list_prev_entry(pos, member))

    /**
    * list_for_each - iterate over a list
    * @pos: the &struct list_head to use as a loop cursor.
    * @head: the head for your list.
    */
    #define list_for_each(pos, head) \
    for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next)

    /**
    * list_for_each_rcu - Iterate over a list in an RCU-safe fashion
    * @pos: the &struct list_head to use as a loop cursor.
    * @head: the head for your list.
    */
    #define list_for_each_rcu(pos, head) \
    for (pos = rcu_dereference((head)->next); \
    !list_is_head(pos, (head)); \
    pos = rcu_dereference(pos->next))

    /**
    * list_for_each_continue - continue iteration over a list
    * @pos: the &struct list_head to use as a loop cursor.
    * @head: the head for your list.
    *
    * Continue to iterate over a list, continuing after the current position.
    */
    #define list_for_each_continue(pos, head) \
    for (pos = pos->next; !list_is_head(pos, (head)); pos = pos->next)

    ....

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Tue Apr 22 00:33:48 2025
    On 21/04/2025 21:25, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 19:43, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 04:16, Kaz Kylheku wrote:
    - Because they are not gathered in one place, not only is it less>
    readable, but we cannot use while write a macro such as:

    for_sqlite_hash (p, &pSchema->trigHash) {
    if (some_condition_over(p))
    continue; // doesn't stupidly repeat for the same p!
    }

    I can't write such macros at all. I'm not even sure what this does.

    Have you never worked with a large codebase written by someone other
    than you?

    How large are we talking about?

    Several 100K to millions.

    Characters, lines or files of source code, or bytes of binary?


    I've delved into largish apps in the context of getting my C compiler
    working. I would describe that experience as 'brutal'.

    Well, that brutal experience is the job of the career software engineer, believe it or not. Very few work only on their own original code.

    If you need to
    debug someone else's codebase, not to find bugs in that program, but to
    find why your implementation is failing, then you want as conservative a
    coding style as possible.


    When you open a random file in an unfamiliar code base, pretty
    much any function call that is not in the standard library triggers
    the "I don't know what this does" response.

    Yes, a function call. Macros are in an entirely different, evil category.

    No, they aren't. They are just another definition to understand.

    I've seen a 33KB C file that expanded to 4MB after preprocessing. Macros
    are evil.


    They can be misused, and also used to make solutions that are more complicated than some great ideas that don't involve macros.

    You can tell when there is abuse going on, because you find that instead
    of optimising doubling the speed of a program, it will make it 3-4 times
    as fast. Because layers of macros hide the fact that that there are also multiple layers of functions which need serious inlining.

    So can anything: an open coded function can be misused to make some complicated solution that can be more nicely done with macros.

    The Lua sources (only a mere 30Kloc), use macros extensively, but also
    have a habit of giving them ordinary looking names in lower case so that
    they look like function calls.

    So does ISO C; e.g. assert (expr); offsetof (type, member). So what?

    Macros that provide syntax should blend into the language.

    These didn't provide syntax.

    Here's a nice example:

    op_arith(L, l_addi, luai_numadd);

    Innocent-looking isn't it? It expands to this:


    {TValue*v1=(&((base+((((int)((((i)>>((((0+7)+8)+1)))&((~((~(Instruction)0)<<(8)))<<(0)))))))))->val);TValue*v2=(&((base+((((int)((((i)>>(((((0+7)+8)+1)+8)))&((~((~(Instruction)0)<<(8)))<<(0)))))))))->val);{StkId
    ra=(base+(((int)((((i)>>((0+7)))&((~((~(Instruction)0)<<(8)))<<(0)))))));if(((((v1))->tt_)==(((3)|((0)<<4))))&&((((v2))->tt_)==(((3)|((0)<<4))))){lua_Integer
    i1=(((v1)->value_).i);lua_Integer i2=(((v2)->value_).i);pc++;{TValue*io=((&(ra)->val));((io)->value_).i=(((lua_Integer)(((lua_Unsigned)(i1))+((lua_Unsigned)(i2)))));((io)->tt_=(((3)|((0)<<4))));};}else{lua_Number
    n1;lua_Number n2;if((((((v1))->tt_)==(((3)|((1)<<4))))?((n1)=(((v1)->value_).n),1):(((((v1))->tt_)==(((3)|((0)<<4))))?((n1)=((lua_Number)(((((v1)->value_).i)))),1):0))&&(((((v2))->tt_)==(((3)|((1)<<4))))?((n2)=(((v2)->value_).n),1):(((((v2))->tt_)==(((3)|((0)<<4))))?((
    n2)=((lua_Number)(((((v2)->value_).i)))),1):0))){pc++;{TValue*io=((&(ra)->val));((io)->value_).n=(((n1)+(n2)));((io)->tt_=(((3)|((1)<<4))));};}};};};

    From this, I had to find the bug in my compiler.

    (Lua is an interpreter; I write interpreters and they are several times
    faster than Lua for equivalant inputs. I don't need to use such tricks.)

    Please humour me: What Does It Do?

    It is intended to condense an interation that *you* open-coded, in this example upthread:

    p = sqliteHashFirst(&pSchema->trigHash);
    while (p != NULL)
    {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    p = sqliteHashNext(p) )
    }

    So although I didn't show the definition, I think, of course the intent that it
    does this (i.e. is relevant to the discussion thread) and not something else.

    for_sqlite_hash (p, hashptr) stmet

    must initialize p using sqliteHashFirst(hashPtr);

    This sounds a very specific type of macro, just to replace a simple
    loop. And it is simple; those identifiers make it look scary. This is
    the loop:

    p = a;
    while (p) {
    stmt;
    p = next(); // which turns out to be p = p->next
    }


    Given that, do you /really/ need that extra layer of complexity via that
    macro?

    If I had to write 17 loops over SQLite hashes, I'd rather type for_sqlite_hash(p, hash) than
    for (p = sqliteHashFirst(hash); p; p = sqliteHashNext(hash)).

    I guess that answers that question! I'd use macros only as a last
    resort; you would use them at the first opportunity.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Tue Apr 22 01:12:46 2025
    On 21/04/2025 23:16, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    I don't now think think there is any argument that will make any
    difference. People here genuinely think that writing:

    for (ch = 0; ch <= 255; ++ch)

    is far superior to this 'primitive' version:

    do ch = 0, 255

    Obviously, the former is more primitive, because the second can
    be made out of the first with a preprocessor, whereas the converse
    is not true. If A can be made out of B, but B not out of A,
    B is more primitive.

    The former is undeniably more verbose for the uses provided by the
    second.

    It is also much more flexible.

    Thanks to the macro preprocessor, it can almost express the second form,
    just with more punctuation:

    for_range (ch, 0, 255)

    If a built-in "do" range loop existed in C, it would likely have
    the parentheses.

    No amount of discussion or arguments will make them change their minds.

    Mostly, you are projecting onto people opinions they don't actually
    have.

    Read the thread. Nobody has changed their opinion on C for-loops, or
    agreed with its various problems, or thought that a streamlined loop
    would be a welcome.

    (Only Keith cautiously welcome the idea of such a feature, while MS said
    he would vote against it, and JP said they would have proposed it on
    April 1st.)



    You're also not a fan of unbridled language extension, based on your
    past opinions about, oh, C++ and whatnot.

    I don't agree with language-building features. You just end up with a monstrosity like C++.

    Your primary reaction to some new idea is to reject it as complex
    fluff that you'd rather not undertand.

    How brushed up are you in using C17 or C23?

    C23 is nothing particularly interesting. A few features I wont't be able
    to rely on until I'm dead.


    You've also expressed oppositions to extending C, because
    development of C makes it a moving target for your projects.

    As I said, development of is not that interesting. Basically sticking
    plaster fixes.

    Of course people are going to push back on the idea of making new>
    statements, if they can be decently obtained or simulated using
    preprocessing.

    Would you support an "unless" statement being added to C, given
    that we can just:

    #define unless(x) if(!(x))

    Or, unless which does not take else:

    #define unless(x) if (x) { } else

    Adding a new statement to C is a big deal, compared to someone
    adding a macro to their code.

    You can't /just/ add such a macro. To be useful, it has to be
    standardised. And then, you'd probably need #include <stdunless.h> to
    use it.

    Literally the first question about any proposal for a new language
    feature is going to be: can obtain that, or substantially obtain it
    using existing features

    I think C's macros are the main thing that have hindered its development.

    Why add a new core feature, when some tacky, half-assed macro can be
    used? Or, sometimes, a typedef.

    At one time, every other app I looked at defined its own ARRAYLEN macro,
    or MIN/MAX, or STREQ.

    There is no need to add a formal lengthof() operator when every user can
    create their own variation of ARRAYLEN in a few seconds.

    Result: most people still end up writing
    sizeof(myarray)/sizeof(myarray[0]). In the meantime, I'm been able to
    write myarray.len for 43 years, and also:

    print a, b # who cares about format codes

    As for MIN/MAX, I routinely use:

    max(a, b)
    max(x, y) # overloaded per type
    a max:=b # augmented assignment
    a.max # maximum value of a's type
    T.max # maximum value of type T

    Oh, and I already have Unless:

    unless a then b end
    return 0 unless cond

    It is not a macro.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to bart on Tue Apr 22 01:06:53 2025
    bart <bc@freeuk.com> wrote:
    On 21/04/2025 21:25, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 19:43, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 04:16, Kaz Kylheku wrote:
    - Because they are not gathered in one place, not only is it less>
    readable, but we cannot use while write a macro such as:

    for_sqlite_hash (p, &pSchema->trigHash) {
    if (some_condition_over(p))
    continue; // doesn't stupidly repeat for the same p!
    }

    I can't write such macros at all. I'm not even sure what this does.

    Have you never worked with a large codebase written by someone other
    than you?

    How large are we talking about?

    Several 100K to millions.

    Characters, lines or files of source code, or bytes of binary?

    I would say lines of code. In modern time 1 million characters
    codebase is not big. I hope that we are not in era of 1 million
    files codebases, but who knows, we may be there in few years.

    I've delved into largish apps in the context of getting my C compiler
    working. I would describe that experience as 'brutal'.

    Well, that brutal experience is the job of the career software engineer,
    believe it or not. Very few work only on their own original code.

    If you need to
    debug someone else's codebase, not to find bugs in that program, but to
    find why your implementation is failing, then you want as conservative a >>> coding style as possible.


    When you open a random file in an unfamiliar code base, pretty
    much any function call that is not in the standard library triggers
    the "I don't know what this does" response.

    Yes, a function call. Macros are in an entirely different, evil category. >>
    No, they aren't. They are just another definition to understand.

    I've seen a 33KB C file that expanded to 4MB after preprocessing. Macros
    are evil.

    If macros were forbiden authors would probably write 4MB "by hand"
    (or rather using editor cut and paste). Actually, creating first
    version probably would be not that hard, but maintanence would
    take a lot of effort (due to volume).

    Of course, macro generated code is likely to contain significant
    fraction of useless instructions, but removing them by hand would
    be substantial work. And trying to directly produce trimmed
    version would need a lot of work. It is much cheaper to
    depend on optimizer to remove redundancies and useless instructions.

    Assuming that hand written version would be 80% smaller, you would
    have 800KB to write, that is more than 20 times the original
    source. So in this case macros probably saved about 95% of
    work needed when coding without macros.

    They can be misused, and also used to make solutions that are more
    complicated than some great ideas that don't involve macros.

    You can tell when there is abuse going on, because you find that instead
    of optimising doubling the speed of a program, it will make it 3-4 times
    as fast. Because layers of macros hide the fact that that there are also multiple layers of functions which need serious inlining.

    Your abuse is another person "taking advantage of available technology".
    One can write code in C so that rather dumb compiler will generate
    reasobly fast program. But such code is harder to write and
    error prone. Instead, one can write higher level code and
    depend on optimizer to get good efficiency.

    So can anything: an open coded function can be misused to make some
    complicated solution that can be more nicely done with macros.

    The Lua sources (only a mere 30Kloc), use macros extensively, but also
    have a habit of giving them ordinary looking names in lower case so that >>> they look like function calls.

    So does ISO C; e.g. assert (expr); offsetof (type, member). So what?

    Macros that provide syntax should blend into the language.

    These didn't provide syntax.

    Here's a nice example:

    op_arith(L, l_addi, luai_numadd);

    Innocent-looking isn't it? It expands to this:


    {TValue*v1=(&((base+((((int)((((i)>>((((0+7)+8)+1)))&((~((~(Instruction)0)<<(8)))<<(0)))))))))->val);TValue*v2=(&((base+((((int)((((i)>>(((((0+7)+8)+1)+8)))&((~((~(Instruction)0)<<(8)))<<(0)))))))))->val);{StkId
    ra=(base+(((int)((((i)>>((0+7)))&((~((~(Instruction)0)<<(8)))<<(0)))))));if(((((v1))->tt_)==(((3)|((0)<<4))))&&((((v2))->tt_)==(((3)|((0)<<4))))){lua_Integer
    i1=(((v1)->value_).i);lua_Integer i2=(((v2)->value_).i);pc++;{TValue*io=((&(ra)->val));((io)->value_).i=(((lua_Integer)(((lua_Unsigned)(i1))+((lua_Unsigned)(i2)))));((io)->tt_=(((3)|((0)<<4))));};}else{lua_Number
    n1;lua_Number n2;if((((((v1))->tt_)==(((3)|((1)<<4))))?((n1)=(((v1)->value_).n),1):(((((v1))->tt_)==(((3)|((0)<<4))))?((n1)=((lua_Number)(((((v1)->value_).i)))),1):0))&&(((((v2))->tt_)==(((3)|((1)<<4))))?((n2)=(((v2)->value_).n),1):(((((v2))->tt_)==(((3)|((0)<<4))))?
    ((n2)=((lua_Number)(((((v2)->value_).i)))),1):0))){pc++;{TValue*io=((&(ra)->val));((io)->value_).n=(((n1)+(n2)));((io)->tt_=(((3)|((1)<<4))));};}};};};

    From this, I had to find the bug in my compiler.

    Not bad, I sometimes had to look for bugs in much bigger piece of
    code.

    (Lua is an interpreter; I write interpreters and they are several times faster than Lua for equivalant inputs. I don't need to use such tricks.)

    IIUC Lua has some interesting properties. Above I see masking and
    tag manipulations, presumably this is needed to implement Lua
    properties. I would expect that Lua has more than one artithemetic
    operation, so sharing code saves coding effort (actually, most
    of tag mainipulations probably can be shared by all Lua instructions).

    In many cases one can use functions instead of macros, but sometimes
    macros depend on variable capture, so can not be replaced by functions. Similarly, gotos (to label outside of a macro) and case labels
    do not work well in inline functions. And in the past some compilers
    were rather shy with inlining, which could significantly reduce speed.

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Tue Apr 22 01:26:39 2025
    On 22/04/2025 00:12, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 21/04/2025 22:06, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    t iteration goes over all elements in the hash table.
    BTW2: When looking at 'for' loop you are supposed to see pattern,
    without need to track all steps.

    That's one of the disadvantages of using the same, often
    /inappropriate/ keyword for every kind of pattern.

    You think it's inappropriate.

    Would your objections go away if a different keyword were used?

    I already said that I would have prefered if 'while' was used.

    Then either 'for' wasn't used, or was used for the kind of for-loop that
    is common in other languages.

    *You* find it much cleaner and simpler. I don't. What makes you right
    and everyone else wrong?

    This is an interesting point: too much stuff on one line is usually
    frowned upon: multiple statements, multiple variables being declared etc.

    But when it's a for-loop, then apparently anything goes.

    All three would be IMHO clearer if each of the three clauses were on a separate line. The fact that you can write a badly formatted C-style
    for loop is not an argument against C-style for loops.

    Complex loops are nearly always badly formatted and written on one line.
    Nobody cares. As you've demonstrated.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Tue Apr 22 02:21:32 2025
    On 21/04/2025 22:06, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    You have to analyse it first. The kind of loop this expresses is:

    p = startvalue()

    while (p) {
    <body>
    p = nextvalue()
    }

    Notice how I chose to express it: it reflects how I would describe it in
    English:

    * Set P to Start Value
    * While P isn't Null:
    * Execute the body
    * Set P to Next Value

    So, how would /you/ describe it in English? (Or in any language if like,
    as the ordering is more important.)

    I would describe original sqlite3.c loop as "iteration over elements
    of hash table". That assumes that Sqlite folks choose sensible
    names. This is higher level view than you apparently have.

    You're guessing based on the identifiers chosen. But that lump of code
    has this shape:

    for(A; B; C)

    which is equivalent to: A; while (B) { body; C}

    However, you can see that A and C are assignments to the same variable,
    so you can reasonably refine to what I wrote above. But perhaps the
    English should have been 'While P is True' to avoid the assumption it is
    a pointer.

    You can't go beyond that however /from the shape of the code/.

    Remember, C-for is 'flexible'. That means it can literally be anything,
    but the general pattern of any such loop can be expressed with 'while'.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Tue Apr 22 02:24:22 2025
    On 22/04/2025 02:06, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 21/04/2025 21:25, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 19:43, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 04:16, Kaz Kylheku wrote:
    - Because they are not gathered in one place, not only is it less> >>>>>> readable, but we cannot use while write a macro such as:

    for_sqlite_hash (p, &pSchema->trigHash) {
    if (some_condition_over(p))
    continue; // doesn't stupidly repeat for the same p! >>>>>>> }

    I can't write such macros at all. I'm not even sure what this does. >>>>>
    Have you never worked with a large codebase written by someone other >>>>> than you?

    How large are we talking about?

    Several 100K to millions.

    Characters, lines or files of source code, or bytes of binary?

    I would say lines of code. In modern time 1 million characters
    codebase is not big. I hope that we are not in era of 1 million
    files codebases, but who knows, we may be there in few years.

    I think it was 20 years ago that I read somewhere that the MS Visual
    Studio codebase was 1.5 million files. IIRC, it took 11 hours to build, non-optimised, and 60 hours optimised.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Tue Apr 22 03:31:39 2025
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    On 21/04/2025 23:16, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    No amount of discussion or arguments will make them change their minds.

    Mostly, you are projecting onto people opinions they don't actually
    have.

    Read the thread. Nobody has changed their opinion on C for-loops, or
    agreed with its various problems, or thought that a streamlined loop
    would be a welcome.

    If a streamlined loop were added to C, you'd be among the last coders
    to use it.

    (Only Keith cautiously welcome the idea of such a feature, while MS said
    he would vote against it, and JP said they would have proposed it on
    April 1st.)


    You're also not a fan of unbridled language extension, based on your
    past opinions about, oh, C++ and whatnot.

    I don't agree with language-building features. You just end up with a monstrosity like C++.

    But C++ is becoming more and more of a monstrosity specifically by
    acquiring numerous features that /cannot/ be achieved with its existing language-building features. (Sure, the language-building ones too,
    on the library side.)

    Your primary reaction to some new idea is to reject it as complex
    fluff that you'd rather not undertand.

    How brushed up are you in using C17 or C23?

    C23 is nothing particularly interesting. A few features I wont't be able
    to rely on until I'm dead.

    Thus if C got, today, the loop features you advocate for, you wouldn't
    use them; they would necessarily be after C23.

    The time to lobby for them was 30-40 years ago, and in the right way.

    You've also expressed oppositions to extending C, because
    development of C makes it a moving target for your projects.

    As I said, development of is not that interesting. Basically sticking
    plaster fixes.

    But that's exactly what some for loop from A to B would be, though.

    Of course people are going to push back on the idea of making new>
    statements, if they can be decently obtained or simulated using
    preprocessing.

    Would you support an "unless" statement being added to C, given
    that we can just:

    #define unless(x) if(!(x))

    Or, unless which does not take else:

    #define unless(x) if (x) { } else

    Adding a new statement to C is a big deal, compared to someone
    adding a macro to their code.

    You can't /just/ add such a macro. To be useful, it has to be
    standardised.

    No; it just has to be defined at the top of a file which needs it.

    All of a sudden, something has to be in a document you can't be
    bothered to read in order to be useful?

    Your own stuff is not standardized; presumably you worked on
    it because you find it useful.

    Literally the first question about any proposal for a new language
    feature is going to be: can obtain that, or substantially obtain it
    using existing features

    I think C's macros are the main thing that have hindered its development.

    C macros definitely hinder all kinds of tooling.

    Why add a new core feature, when some tacky, half-assed macro can be
    used? Or, sometimes, a typedef.

    But, tacky as the macro is, it only pollutes the program where it is
    used, not the entire language.

    A badly designed macro getting into a program is less harmful than a
    badly designed feature getting into the language. (Where we recognize
    that such a feature could be a macro.)

    There is no need to add a formal lengthof() operator when every user can create their own variation of ARRAYLEN in a few seconds.

    Result: most people still end up writing
    sizeof(myarray)/sizeof(myarray[0]).

    This leads to a bug when myarray is actually a pointer.

    GCC has a warning for sizeof ptr / sizeof ptr[0] specifically
    to catch bugs in this idiom.

    It's pretty gross. To my understanding there is some initiative
    to get some array length operator.

    Of course, you will never use it.

    In the meantime, I'm been able to
    write myarray.len for 43 years, and also:

    print a, b # who cares about format codes

    As for MIN/MAX, I routinely use:

    max(a, b)
    max(x, y) # overloaded per type
    a max:=b # augmented assignment
    a.max # maximum value of a's type
    T.max # maximum value of type T

    Oh, and I already have Unless:

    unless a then b end
    return 0 unless cond

    Not only you, but countless term projects in undergraduate compiler
    class. So what?

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Tue Apr 22 09:14:22 2025
    On 20.04.2025 21:51, bart wrote:
    On 20/04/2025 17:46, Janis Papanagnou wrote:
    On 20.04.2025 13:43, bart wrote:
    On 20/04/2025 11:18, Janis Papanagnou wrote:
    On 19.04.2025 15:05, bart wrote:

    But overloading in the form of 30-40 integer types to represent the 8
    types i8-i64 and u8-u64, plus the 16 different combinations of writing
    'unsigned long long int', and so on, is fine. As are the dozens
    (hundreds?) of macros in stdint.h/inttypes.h.

    I haven't said this "is fine". It wasn't at all the topic here.

    Sorry, I forgot the rules. [...]

    What rules? You're again making up things. - Instead of arguing on
    the topic you switched to something else that you dislike about "C".


    In C? I don't recall any examples in C that could be written without 'for'.

    (We've obviously been speaking about different things.)


    It makes not much sense to spread them across a multi-line block
    of statements. - If you haven't ever experienced that, and still
    cannot see and understand that if explained to you, then I can't
    help you.[*]

    Here's the example you snipped:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    In my opinion, that for-header is too complex. You can barely make out
    the condition (that lonely 'p' which you have to hunt for).

    You find (and can make up) arbitrary examples of badly written code.

    How is that 'for' loop with all in one line worse than the respective
    'while' loop if stupidly written in one line.

    If you have complex expressions you format it accordingly. Moreover,
    you choose appropriate names for your variables and functions.


    The point is that if you have programming elements that are
    related to a loop construct (initialization, exit condition,
    update for next iteration) it makes sense to keep them together.

    So what about this then (another example you snipped):

    for(p=sqliteHashFirst(&pSchema->trigHash); p; sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)), p=sqliteHashNext(p));

    It keeps it even more together, which you seem to like.

    You are talking nonsense. Again; how is that better than a 'while'
    loop where everything is on one line. - Are you deliberately playing
    the stupid?

    To keep things together means that you have the controlling elements
    together. To not have parts of the controlling elements at the very
    end of the block that the control construct controls.

    (From the other posts I see that the folks here understand that; so
    why are you playing the stupid?)

    [...]

    I think it is YOU whose brain is so bound to having just the ONE kind of
    loop to do half a dozen different jobs, none of them well.

    (I didn't say that. - Stop such misinterpretations and imputations!)

    [...]

    Why do you again make
    up things. - The point is to keep things together that belong
    together.

    Why are you so crazy about putting everything onto one line? [...]

    (I haven't said that. - Stop it!)

    You're
    saying that:

    ONE; TWO; THREE

    is always better than:

    ONE;
    TWO;
    THREE;

    (No I haven't said that. - Stop it!)

    [...]

    This is an example which I started off trying to simplify:

    for (monthIdx = 0; monthIdx < 12 && yearDay >=
    yearDays[leapYear][monthIdx]; monthIdx++) ;

    I simply can't see it.

    You can simply (and obviously) format it appropriately...

    for (monthIdx = 0;
    monthIdx < 12 && yearDay >= yearDays[leapYear][monthIdx];
    monthIdx++)
    ;

    So the first step is to turn it into a while loop:

    Why? It's completely unnecessary to _rewrite_ that. A _reformat_ is
    not only simpler (and safer to do), it's the straightforward way.

    And if it still appears too complicated a style for your perception
    (or liking) you can also keep the 'for' loop just iterating over the
    'monthIdx' and put the exit condition explicitly in the controlled
    block with a 'break' if you prefer that.

    for (monthIdx = 0; monthIdx < 12; monthIdx++)
    if (yearDay < yearDays[leapYear][monthIdx])
    break;

    Both presented forms are IMO much better structured (and most easily recognizable) than your code following here...


    monthIdx = 0;
    while (monthIdx < 12 && yearDay >= yearDays[leapYear][monthIdx])
    monthIdx++;

    Now at least I can see the condition! I'm sorry, but if prefer the
    original, then I don't want to have to debug or maintain your code.

    (Above "the original" was the 'for' loop.)

    [...]

    I just don't get the love. Or maybe, nobody here (perhaps apart from
    Keith) is willing to admit that there's anything wrong with 'for'.

    You don't like it. Fine. (I don't like a lot about "C".) Who cares?

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Tue Apr 22 09:54:36 2025
    On 21.04.2025 17:36, bart wrote:
    On 21/04/2025 14:51, Waldek Hebisch wrote:

    [ sqlite3.c code ]

    You have to analyse it first. The kind of loop this expresses is:

    No. That's just *your* _transcription_ of the original code

    p = startvalue()

    while (p) {
    <body>
    p = nextvalue()
    }

    Notice how I chose to express it: it reflects how I would describe it in English:

    You are *not* describing _the task_, you are merely translating the
    _chosen commands_ of the procedural language [that you have chosen]


    * Set P to Start Value
    * While P isn't Null:
    * Execute the body
    * Set P to Next Value

    Whatever programming language and constructs you use, this is not
    more than a rephrasing the used language constructs (as opposed to
    the task).

    (It's not surprising; you can observe that folks that are familiar
    only with imperative languages tend to this sort of fallacy.)

    So, how would /you/ describe it in English? (Or in any language if like,
    as the ordering is more important.)

    Iterate over the elements and sequentially perform <the task> on
    the elements. Or a bit more formally

    iterate (elements, task)

    in some functional programming language. Or any other variant on
    any abstraction level that is appropriate.

    [...]

    However I see that nobody in this group has any objective interest in language ergonomics and aesthetics.

    Nonsense.

    They more interested in defending 'their' language.

    Nonsense.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Keith Thompson on Tue Apr 22 10:12:19 2025
    On 22.04.2025 00:39, Keith Thompson wrote:
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 21.04.2025 23:21, Keith Thompson wrote:
    [...]
    C-style for loops have been used successfully for decades, and have
    been adopted by other languages (including bash, which isn't
    particularly C-like).

    I have to disagree on that. First I'm positive that Bash adopted
    the Ksh loops (but incompletely!), and not the "C" loops.

    Bash has two kinds of for loops. From the bash manual:
    for NAME [ [in WORDS ...] ; ] do COMMANDS; done

    This is the historic and standard form in all POSIX shells.

    and
    for (( EXPR1 ; EXPR2 ; EXPR3 )) [;] do COMMANDS ; done

    I'm referring to the second form, as I'm sure you know.

    Yes, of course.

    I see that ksh has something very similar.

    Ksh invented it, along with the "arithmetic command" ((...)), as
    addition to the (standard) arithmetic substitution $((...)) .

    I have no idea which shell
    added the second form earlier, but both are clearly derived from C,
    directly or indirectly.

    Yes. - In the sense of having this three-part separation.

    [...]

    [...]
    [...] But you can still do things that
    you can't do with a simple counted for loop, for example printing
    powers of 3:

    for (( i = 1; i < 1000; i *= 3 )) ; do echo $i ; done

    Indeed. Because of the three-part separation of building blocks
    you can do similar things as in "C" (modulo FP in Bash).

    It's something you cannot do, e.g., with Pascal- or "bart-loops".

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Tue Apr 22 09:32:32 2025
    On 21.04.2025 01:29, bart wrote:
    On 20/04/2025 23:36, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:

    for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ >>> sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }


    I might write it like this:

    for ( p = sqliteHashFirst(&pSchema->trigHash);
    p != NULL;
    p = sqliteHashNext(p) )
    {
    sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
    }

    I have certain preferences (spaces around most operators, explicit
    comparison to NULL, willingness to split long lines) that other C
    programmers may or may not share.

    I rarely see complex loops split over multiple lines

    (There's obviously a lot you haven't seen.)

    (mainly when they
    get so long that they'd overflow the line, but they can still be complex enough before then).

    But the thing is, once you split it into multiple lines, then there is
    little advantage over using a regular 'while' loop:

    You still have the controlling elements in one place with 'for'.

    [...]

    It keeps it even more together, which you seem to like.

    That's something you invented. I find it ugly, and I presume you'd
    agree. The fact that you think that someone else would prefer it
    indicates that you don't understand how other people think.

    AFAIK it is legal C code, and I invented it because somebody said things
    that belong together should be together in one place.

    Yes, that's a commonplace. (But "one place" doesn't mean "stuffed" or
    "all in one line".)

    However, I have
    seen actual examples like that, in for-headers that that use
    comma-separated expressions.

    (You can see and find arbitrary code, better or worse.)



    I'd rather not write `for (ch in 0..255)` because it's a syntax error.

    It's a syntax error because the form doesn't naturally exist in C; you'd
    have to emulate using macros, which is a poor solution.

    Yes, and that's his point; it's not "C".

    If I want abstractions I don't (unless I have to) use "C". If I want to
    have clean concepts, say iterating over an indexed array, I can use in
    "C"

    for (i=0; i<N; i++)
    arr[i] = fun (arr[i]);

    which is clean enough for me. But I might prefer (with other languages)
    to not care about the bounds in the first place, and use

    for (i := lwb(arr) to upb(arr)) # not "C"
    arr[i] := fun (arr[i]);

    if I'd want to avoid errors with the bounds. But the real thing I'd want
    is a functional approach where I don't need indices at all

    iterate (arr, fun); # not "C"


    You have the luxury of using your own language.

    That 'ch in 0..255' form or close equivalent is supported by that long
    set of languages I listed earlier. It's not my invention, I just copied it.

    It is just something that is desirable. Look again at the C version: it
    looks off. (At least, you'd use a shorter loop index!)

    There's a lot I'd like to have that I don't find in the "C" language.

    If I choose to use (or have to use) "C" I use the options I have to best
    solve my tasks.

    [...]

    If you don't like C-style for loop, they absolutely should not
    exist in a language for which you are, if I understand correctly,
    the sole implementer and the sole user.

    But I hear so much about how wonderful it is, how multi-purpose, how indispensible, how superior to an ordinary 'for' (admittedly from people
    who don't have a choice) that I didn't want to miss out!

    No one said that. - You should stop your regular misrepresentations and
    also your misinterpretations! - STOP IT, stupid!

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Scott Lurndal on Tue Apr 22 10:32:20 2025
    On 22.04.2025 01:46, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:

    I guess that answers that question! I'd use macros only as a last
    resort; you would use them at the first opportunity.

    (Again exaggerating and imputations. *sigh* - Abandon all hope, ye
    who enter here.)

    Obviously the entire world-wide programming community
    disagrees with your opinions.

    Well, I certainly disagree with the (so well known) exaggerations of
    bart, but I have a similar principle here; I avoid macros if I can.
    I like languages where every construct is under "direct control" of
    the compiler with a single abstraction principle (as opposed to
    two-step interpretations). It's all not worth a discussion, I think,
    and I certainly see and acknowledge "valid" applications of macros.
    Just saying that I understand his reluctance here.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Tue Apr 22 10:19:15 2025
    On 22.04.2025 00:54, bart wrote:
    On 21/04/2025 22:06, Waldek Hebisch wrote:
    [...]

    The intent of 'for' is to iterate over some collection. Each of
    A, B, C is needed to know the collection.

    Sure, but ALL ON THE SAME LINE?

    No one suggested (or forces you) to do that.

    All within the same parentheses?

    It makes sense in programming languages to have a syntactic frame
    for things that belong together.

    Putting multiple things on the same line is usually frowned upon.

    There's of course exceptions but basically yes.

    Look at these ludicrous examples:

    I suggest to just not make up ludicrous examples. We would certainly
    all be happy if you'd stop that.

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Waldek Hebisch on Tue Apr 22 10:47:25 2025
    On 22.04.2025 03:06, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 21/04/2025 21:25, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    On 21/04/2025 19:43, Kaz Kylheku wrote:

    Have you never worked with a large codebase written by someone other >>>>> than you?

    How large are we talking about?

    Several 100K to millions.

    Characters, lines or files of source code, or bytes of binary?

    I would say lines of code. In modern time 1 million characters
    codebase is not big. I hope that we are not in era of 1 million
    files codebases, but who knows, we may be there in few years.

    I've been already in the 1990's. (A huge years-long reorganization
    project of a telecommunication company. - A lot of companies and
    people were involved. It was, at least on our part, a C++ project.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to bart on Tue Apr 22 10:40:55 2025
    On 22.04.2025 02:26, bart wrote:
    On 22/04/2025 00:12, Keith Thompson wrote:
    [...]

    This is an interesting point: too much stuff on one line is usually
    frowned upon: multiple statements, multiple variables being declared etc.

    But when it's a for-loop, then apparently anything goes.

    You have no fantasy about sensible code patterns but when it goes
    to imputations and misrepresentations your fantasy is limitless.


    All three would be IMHO clearer if each of the three clauses were on a
    separate line. The fact that you can write a badly formatted C-style
    for loop is not an argument against C-style for loops.

    Complex loops are nearly always badly formatted and written on one line. Nobody cares. As you've demonstrated.

    Take your meds and recognize that the world is different than how
    your fantasy deludes you.

    And stop making such nonsensical claims like "nearly always" without
    any evidence.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Tue Apr 22 11:28:56 2025
    On 22/04/2025 02:06, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    I've seen a 33KB C file that expanded to 4MB after preprocessing. Macros
    are evil.

    If macros were forbiden authors would probably write 4MB "by hand"
    (or rather using editor cut and paste). Actually, creating first
    version probably would be not that hard, but maintanence would
    take a lot of effort (due to volume).


    It would probably be done by a script. This resulting code is not
    something to be written or consumed by a human. Which is an odd thing to
    say about a HLL.

    The example below is not as bad: the lines are only up to 1K chars
    instead of 50K.

    (I thought my own generated C code was poor; it's actually a million
    times more readable.)

    Of course, macro generated code is likely to contain significant
    fraction of useless instructions, but removing them by hand would
    be substantial work. And trying to directly produce trimmed
    version would need a lot of work. It is much cheaper to
    depend on optimizer to remove redundancies and useless instructions.

    How about writing decent, sensible code in the first place?

    Assuming that hand written version would be 80% smaller, you would
    have 800KB to write, that is more than 20 times the original
    source. So in this case macros probably saved about 95% of
    work needed when coding without macros.

    You haven't seen this example, you don't know how bad it is, or how
    effective it was as a solution to whatever problem it was trying to
    solve, and yet YOU'RE MAKING EXCUSES FOR IT!

    This is a really odd phenomenon: is there no C code on the planet, that
    anybody here will admit that is badly written? Or that might be forced
    into being badly written due to shortcomings of the language?

    Here's a challenge for everyone here: please post an example, or a link
    to an example, that you think is truly appalling code.


    Here's a nice example:

    op_arith(L, l_addi, luai_numadd);

    Innocent-looking isn't it? It expands to this:


    {TValue*v1=(&((base+((((int)((((i)>>((((0+7)+8)+1)))&((~((~(Instruction)0)<<(8)))<<(0)))))))))->val);TValue*v2=(&((base+((((int)((((i)>>(((((0+7)+8)+1)+8)))&((~((~(Instruction)0)<<(8)))<<(0)))))))))->val);{StkId
    ra=(base+(((int)((((i)>>((0+7)))&((~((~(Instruction)0)<<(8)))<<(0)))))));if(((((v1))->tt_)==(((3)|((0)<<4))))&&((((v2))->tt_)==(((3)|((0)<<4))))){lua_Integer
    i1=(((v1)->value_).i);lua_Integer
    i2=(((v2)->value_).i);pc++;{TValue*io=((&(ra)->val));((io)->value_).i=(((lua_Integer)(((lua_Unsigned)(i1))+((lua_Unsigned)(i2)))));((io)->tt_=(((3)|((0)<<4))));};}else{lua_Number
    n1;lua_Number
    n2;if((((((v1))->tt_)==(((3)|((1)<<4))))?((n1)=(((v1)->value_).n),1):(((((v1))->tt_)==(((3)|((0)<<4))))?((n1)=((lua_Number)(((((v1)->value_).i)))),1):0))&&(((((v2))->tt_)==(((3)|((1)<<4))))?((n2)=(((v2)->value_).n),1):(((((v2))->tt_)==(((3)|((0)<<4))))
    ?((n2)=((lua_Number)(((((v2)->value_).i)))),1):0))){pc++;{TValue*io=((&(ra)->val));((io)->value_).n=(((n1)+(n2)));((io)->tt_=(((3)|((1)<<4))));};}};};};

    From this, I had to find the bug in my compiler.

    Not bad, I sometimes had to look for bugs in much bigger piece of
    code.

    So that means there's nothing wrong with it? Remember this is one
    expression.


    (Lua is an interpreter; I write interpreters and they are several times
    faster than Lua for equivalant inputs. I don't need to use such tricks.)

    IIUC Lua has some interesting properties. Above I see masking and
    tag manipulations, presumably this is needed to implement Lua
    properties.

    Here you are making excuses again. Yes, Lua uses tags on some 64-bit
    value; so what? That can be done using ordinary code. Or if macros have
    to be used, they can be simple too.

    My own product uses apparently inefficient 128-bit values, it does
    everything 'wrong' but it uses readable HLL code with minimal use of
    macros, and yet it can run at several times the speed of Lua even
    unoptimised. You don't need to write gobbledygook.

    BTW here is that macro definition from Lua:

    #define op_arith(L,iop,fop) { \
    TValue *v1 = vRB(i); \
    TValue *v2 = vRC(i); \
    op_arith_aux(L, v1, v2, iop, fop); }

    It calls yet more macros, and those in turn call others; here are a few
    for vRB:

    #define vRB(i) s2v(RB(i))
    #define s2v(o) (&(o)->val)
    #define RB(i) (base+GETARG_B(i))
    #define GETARG_A(i) getarg(i, POS_A, SIZE_A)
    #define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0)))
    #define cast_int(i) cast(int, (i))
    #define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p))
    #define cast(t, exp) ((t)(exp))

    I think the maximum depth here is 7-deep:

    op_arith -> vRB -> RB -> GETARG -> getarg -> cast_int -> cast

    This is not normal coding; it has replaced using functions to build
    programs, with macros. And it has replaced coding in C, with
    functional-style coding via the macro language.

    So what language would say this program is written in?

    I would expect that Lua has more than one artithemetic
    operation, so sharing code saves coding effort (actually, most
    of tag mainipulations probably can be shared by all Lua instructions).

    Any reason to uses *seven* levels of macro invocation? That is all in
    one branch.

    Do you think that's too many? Perhaps only 3 levels would have sufficed.
    Or would you automatically say it was reasonable no matter how many
    levels there were, just to disagee with me and to side with a fellow C programmer?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Tue Apr 22 11:43:09 2025
    On 22/04/2025 02:22, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 22/04/2025 00:12, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 21/04/2025 22:06, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    t iteration goes over all elements in the hash table.
    BTW2: When looking at 'for' loop you are supposed to see pattern, >>>>> without need to track all steps.

    That's one of the disadvantages of using the same, often
    /inappropriate/ keyword for every kind of pattern.
    You think it's inappropriate.
    Would your objections go away if a different keyword were used?

    I already said that I would have prefered if 'while' was used.

    Then either 'for' wasn't used, or was used for the kind of for-loop
    that is common in other languages.

    So you wouldn't mind if C had both `while (expr)` and
    `while (expr1; expr2; expr3)`, with the latter having the semantics
    of C's current for loop?

    At least the keyword would now be 'appropriate'.

    But that doesn't answer my question. You'd prefer "while", but would
    using "while" rather than "for" resolve your objections?

    If a separate 'for' didn't exist, then there'd be mostly the same
    problems, but it would be slightly less annoying: at least there is no
    pretence that linked-list traversal is anything to with iterating from A
    to B.

    But ideally 'for' would exist and be used only for simple iterations,
    even if it was the same for(a;b;c) style as now. Then when you see
    'for....', you will know instantly what you're looking at.

    For example, in my post to which you replied, I discussed at
    some length how I like to split for loops if they're too long.
    You snipped that discussion *and then* insinuated that I don't care
    about complex loops written on one line. Please stop doing things
    like that.

    Well I care about it too, and I would write such things more sensibly as
    well. But so what? Most code I see tends to be badly formatted.
    For-headers are not split up unless they're long enough to overflow the
    line.

    It's something about the culture behind 'for' that encourages poor
    coding style.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Janis Papanagnou on Tue Apr 22 12:39:30 2025
    On 22/04/2025 09:19, Janis Papanagnou wrote:
    On 22.04.2025 00:54, bart wrote:

    Look at these ludicrous examples:

    I suggest to just not make up ludicrous examples. We would certainly
    all be happy if you'd stop that.

    They were real examples. The first from SQLite3, the next two from LIBJPEG.

    But thanks anyway, you've just agreed that those are ludicrous.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Tue Apr 22 12:33:14 2025
    On 22/04/2025 04:31, Kaz Kylheku wrote:
    On 2025-04-22, bart <bc@freeuk.com> wrote:

    C23 is nothing particularly interesting. A few features I wont't be able
    to rely on until I'm dead.

    Thus if C got, today, the loop features you advocate for, you wouldn't
    use them; they would necessarily be after C23.

    I don't actually write much raw C. When I generate C, especially if I
    want someone else to compile the code, then it needs to be conservative.

    But most of my complaints have been do with other people's code. They're
    the ones that need to use those features!

    In any case, for-loops account for 1% of what I find painful about C.

    The time to lobby for them was 30-40 years ago, and in the right way.

    I'm pretty sure I started complaining here 20 years ago! Perhaps more.


    You've also expressed oppositions to extending C, because
    development of C makes it a moving target for your projects.

    As I said, development of is not that interesting. Basically sticking
    plaster fixes.

    But that's exactly what some for loop from A to B would be, though.

    Most of my replies haven't been about the feature itself: it's about
    people's attitudes to it, defending appalling coding styles, pretending
    the primitive C feature is superior to anything else, and generally
    refuting every point I try to make.

    And when they run out of arguments, they start personal insults.

    No; it just has to be defined at the top of a file which needs it.

    Either it's in the language or it isn't. It is unacceptable to me to
    require headers for fundamental language features.

    All of a sudden, something has to be in a document you can't be
    bothered to read in order to be useful?

    Do you think I haven't played around with such macros? Here's some from
    2014:

    #define PUTS puts
    #define PRINTF printf
    #define TO(i,x) for (i=x; i; --i)
    #define FOR(i,a,b) for (i=a; i<=b; ++i)
    #define FORD(i,a,b) for (i=a; i>=b; --i)
    #define UPB(a) (sizeof(a)/sizeof(a[0]))
    #define UPB0(a) (sizeof(a)/sizeof(a[0])-1)
    #define LEN(a) (sizeof(a)/sizeof(a[0]))

    But if writing a code fragment to post in a forum, for example, you
    can't use any of this stuff. People arren't going to download some
    separate header for these macros, and I don't want them plastered all
    over my example. It would also be silly ate to use that FOR macro for
    that /one/ for-loop in my code.

    This stuff does need to be standardised to be useful.

    Your own stuff is not standardized; presumably you worked on
    it because you find it useful.

    It is standardised in that no basic language feature, no standard
    library function, needs some declaration to be used. Example:

    proc main =
    puts("hello"
    end

    In C that would need '#include <stdio>'. Here, 'puts' is defined in a
    file which is part of my standard library which is automatically
    included by default.


    I think C's macros are the main thing that have hindered its development.

    C macros definitely hinder all kinds of tooling.

    Just C syntax does that by itself! My editor uses Ctrl-PageUp/Down to
    step between functions. But it doesn't work for C source code: you need
    half a C compiler to figure out where each function starts.

    Result: most people still end up writing
    sizeof(myarray)/sizeof(myarray[0]).

    This leads to a bug when myarray is actually a pointer.

    GCC has a warning for sizeof ptr / sizeof ptr[0] specifically
    to catch bugs in this idiom.

    It's pretty gross. To my understanding there is some initiative
    to get some array length operator.

    Of course, you will never use it.

    After nearly 50 years of using alternative languages? Probably not. By
    the time it became standard, I'd be dead.

    In the meantime, I'm been able to
    write myarray.len for 43 years, and also:

    print a, b # who cares about format codes

    As for MIN/MAX, I routinely use:

    max(a, b)
    max(x, y) # overloaded per type
    a max:=b # augmented assignment
    a.max # maximum value of a's type
    T.max # maximum value of type T

    Oh, and I already have Unless:

    unless a then b end
    return 0 unless cond

    Not only you, but countless term projects in undergraduate compiler
    class. So what?

    Well, exactly. So how come we ended up with C as the world's primary
    systems language? Why hasn't C long acquired such useful core features?

    However those undergraduates probably moved on to use a mainstream
    language, while I've successfully used mine to do 99% of my coding over decades.

    (Actually, I've looked at countless amateur language projects over on
    Reddit. Most of them would be hopeless as systems languages. And half of
    them look like C!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Tue Apr 22 14:36:52 2025
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    On 22/04/2025 04:31, Kaz Kylheku wrote:
    The time to lobby for them was 30-40 years ago, and in the right way.

    I'm pretty sure I started complaining here 20 years ago! Perhaps more.

    That's not the "right way" though; that has no hope of producing
    results.

    Your own stuff is not standardized; presumably you worked on
    it because you find it useful.

    It is standardised in that no basic language feature, no standard
    library function, needs some declaration to be used.

    I like that. I would never design a language like Python where you need
    to "import" stuff that is already built in.

    That is not a language.

    Before speaking to you, I don't need to say, "from English import
    articles; from articles import the, a".

    I hope you are remembering all the times I agree with you.

    (I don't agree with your definition of "standardized"; that refers
    to being documented, in detail, so that multiple implementations
    are encouraged to interoperate (exchange source code)).

    proc main =
    puts("hello"
    end

    In C that would need '#include <stdio>'. Here, 'puts' is defined in a
    file which is part of my standard library which is automatically
    included by default.

    In a Lisp system, all standard functions, variables, macros and
    everything else are present in the image and can just be used.

    Not only you, but countless term projects in undergraduate compiler
    class. So what?

    Well, exactly. So how come we ended up with C as the world's primary
    systems language? Why hasn't C long acquired such useful core features?

    The most actively developed dialect of C is C++.

    C is kind of a still backwaters in comparison.

    C++ has acquired all sorts of features and continues to do so.
    Including in the area of iteration.

    This is valid C++, as of C++11, which was 14 years ago:

    int a[] = {0, 1, 2, 3, 4, 5};

    for (int n : a) {
    // ...
    }

    C tends not to take on this kind of stuff.

    But remembrer, you don't like C++ because it's big and full of cruft
    that would take you years to understand, not to mention me.

    _ You don't like gatekeeping against features, like in the case of C standardization.

    - You don't like more open gate, like C++, which leads to a Borg-like assimilation of cruft over years and decades.

    You want the gate to be open only for you, where you get to decide on
    some dozen features (or what have you) which are then frozen, so that
    nobody else gets to add anything that you would have to learn.

    It's as if you should be developing your own language and not bothering
    wth any other, and perhaps using C as a code generation back end,
    whereby you are grateful that at least it's not such a moving target, in
    spite of its warts.

    I'm the same way! I'm against the floodgates being open, yet I don't
    absolutely zero progress either, like Common Lisp (ratified by ANSI
    in 1994, and nothing since then). Make your own Lisp; then you can
    experiment, without other cooks spoiling the sauce.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Kaz Kylheku on Tue Apr 22 16:10:31 2025
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    On 22/04/2025 04:31, Kaz Kylheku wrote:
    The time to lobby for them was 30-40 years ago, and in the right way.

    I'm pretty sure I started complaining here 20 years ago! Perhaps more.

    That's not the "right way" though; that has no hope of producing
    results.

    And even then, his complaints would never have gained traction;
    the basic syntax of C hasn't changed for forty years, particularly
    with respect to the syntax related to the 'for' keyword.

    Offering suggestions, rather than chronic complaining would have
    been a better track, but still wouldn't have likely resulted in
    changes that would satisfy bart.


    Your own stuff is not standardized; presumably you worked on
    it because you find it useful.

    It is standardised in that no basic language feature, no standard
    library function, needs some declaration to be used.

    I like that. I would never design a language like Python where you need
    to "import" stuff that is already built in.

    That is not a language.

    Before speaking to you, I don't need to say, "from English import
    articles; from articles import the, a".

    I hope you are remembering all the times I agree with you.

    (I don't agree with your definition of "standardized"; that refers
    to being documented, in detail, so that multiple implementations
    are encouraged to interoperate (exchange source code)).

    proc main =
    puts("hello"
    end

    In C that would need '#include <stdio>'. Here, 'puts' is defined in a
    file which is part of my standard library which is automatically
    included by default.

    Which precludes user overrides of the standard library at compile
    time or run-time.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Tue Apr 22 17:53:20 2025
    On 22/04/2025 02:12, bart wrote:
    On 21/04/2025 23:16, Kaz Kylheku wrote:
    On 2025-04-21, bart <bc@freeuk.com> wrote:
    I don't now think think there is any argument that will make any
    difference. People here genuinely think that writing:

        for (ch = 0; ch <= 255; ++ch)

    is far superior to this 'primitive' version:

        do ch = 0, 255

    Obviously, the former is more primitive, because the second can
    be made out of the first with a preprocessor, whereas the converse
    is not true. If A can be made out of B, but B not out of A,
    B is more primitive.

    The former is undeniably more verbose for the uses provided by the
    second.

    It is also much more flexible.

    Thanks to the macro preprocessor, it can almost express the second form,
    just with more punctuation:

       for_range (ch, 0, 255)

    If a built-in "do" range loop existed in C, it would likely have
    the parentheses.

    No amount of discussion or arguments will make them change their minds.

    It is very rare that rants, exaggerations, and highly subjective
    opinions change anyone's opinions. You have presented no evidence or
    rational argument for your own viewpoint - merely an opinion that you
    don't like C's for-loop syntax.

    It is not news to any C programmer that C's for-loop syntax is different
    to that of a number of other languages - and that like a lot of C
    syntax, its flexibility has its advantages and disadvantages.

    But if you want to show that C's for-loop syntax is /bad/, not just say
    that you don't like it (which is a subjective opinion, and as such you
    are free to hold whatever views you like), you have to demonstrate that
    there are clear and significant issues with it. You have to show that
    it is a problem for C programmers. It is not enough to show that it
    takes more keystrokes or tokens than some alternatives, or that there
    are people other than yourself who dislike it. It is not enough to show
    that some C programmers make macros for their own convenience, or that
    most for-loops in C are simple counters that have a shorter syntax in
    many languages.

    If you want to demonstrate that C's for-loop syntax is objectively a bad design, you need to show that it is a source of real-world errors or
    real-world lack of productivity. That means you need to point to errors
    in the way for-loops are written being behind a statistically
    significant fraction of CVE entries, or research papers or surveys
    showing that it is something people regularly get wrong in C
    programming. Or you can point to studies showing that using a language
    similar to C, but with a different loop syntax, is measurably more
    productive. (Ironically for you, the nearest here would be the C++
    syntax for for-loops over containers.)

    I don't believe you will be able to provide any such reference. If you
    could, then I am sure at least some people here would accept that C's for-loops are a dangerous and therefore poor choice of syntax - though
    personal preference is still personal preference.

    Until then, your posts are as convincing as someone claiming strawberry
    is a terrible flavour for ice cream.

    Had you picked another aspect of C, such as the ease of writing code
    with buffer overflows, you could provide objective proof that the C way
    of handling arrays and strings is a lot more dangerous than modern C++,
    Python, or even old BASIC in that respect.



    Mostly, you are projecting onto people opinions they don't actually
    have.

    Read the thread. Nobody has changed their opinion on C for-loops, or
    agreed with its various problems, or thought that a streamlined loop
    would be a welcome.

    I don't see anyone disagreeing with you about the claim that no one has
    changed their opinion as a result of your rants. But I regularly see
    you making claims about what other people have said or meant, without justification.


    (Only Keith cautiously welcome the idea of such a feature, while MS said
    he would vote against it, and JP said they would have proposed it on
    April 1st.)


    I don't recall reading Keith saying any such thing. He said he would be willing to nit-pick a proposal for a new "for-loop" syntax - not that he
    would welcome it. Perhaps he just thinks he would enjoy nit-picking
    such a paper. As for using a feature if it were added to C, I know I
    probably would do so in my own code - that does not imply that I think
    such a feature is needed, or that I have any trouble using C's current
    syntax for simple loops. (I find C++'s alternative for-loop syntax
    nicer for iterating over containers, but that is not as easily
    translatable into C.)



    You're also not a fan of unbridled language extension, based on your
    past opinions about, oh, C++ and whatnot.

    I don't agree with language-building features. You just end up with a monstrosity like C++.

    C++ has, as noted above, an alternative for-loop syntax that is a lot
    simpler for some uses - "for (auto x : vec) { ... }" iterates over a
    vector, C++ array, or other container.


    Your primary reaction to some new idea is to reject it as complex
    fluff that you'd rather not undertand.

    How brushed up are you in using C17 or C23?

    C23 is nothing particularly interesting. A few features I wont't be able
    to rely on until I'm dead.


    You've also expressed oppositions to extending C, because
    development of C makes it a moving target for your projects.

    As I said, development of is not that interesting. Basically sticking
    plaster fixes.

    Of course people are going to push back on the idea of making new>
    statements, if they can be decently obtained or simulated using
    preprocessing.

    Would you support an "unless" statement being added to C, given
    that we can just:

    #define unless(x) if(!(x))

    Or, unless which does not take else:

    #define unless(x) if (x) { } else

    Adding a new statement to C is a big deal, compared to someone
    adding a macro to their code.

    You can't /just/ add such a macro. To be useful, it has to be
    standardised. And then, you'd probably need #include <stdunless.h> to
    use it.


    You can, if fact, simply add such a macro if that is something you want
    to do. If you find it useful, use it. That is part of the beauty of
    /not/ putting this kind of thing into the core language - it is
    completely optional, and people can make their own choices.

    Literally the first question about any proposal for a new language
    feature is going to be: can obtain that, or substantially obtain it
    using existing features

    I think C's macros are the main thing that have hindered its development.


    I think you are wrong.

    And I think you haven't the slightest shred of evidence to support your opinion. I, on the other hand, have at least some justification - the C standards committee have written that they intentionally change the C
    language slowly, valuing stability of the language and compatibility
    with existing code over new features and language changes.

    Why add a new core feature, when some tacky, half-assed macro can be
    used? Or, sometimes, a typedef.


    A good guideline for language design is that you /never/ change core
    features if you can implement the feature you want as part of the
    language library. For established languages, the main motivation for
    changing the language is to provide better support for features in the
    standard library - to make them more efficient, or significantly easier
    to use.

    You live in a very different world from serious, mainstream languages, libraries and programming. In your world, it's as easy to add a
    function to the core language as it is to add it to the user application
    code, so you have a very different balance. Other language designers,
    language implementers, and language users do not work that way.

    At one time, every other app I looked at defined its own ARRAYLEN macro,
    or MIN/MAX, or STREQ.


    I guess I am the exception - I've never needed any of these. But for
    your information, C23 has a _Lengthof operator as well as features
    making it easier to make a better min or max macro, and C++ has all of
    these features defined in its standard library. I assume, however, that
    you feel C++ is evil for implementing min and max as library template
    functions that are easy to use and do not conflict with programmer's
    choices to use those same identifiers themselves. You would rather fill
    the core language with an increasingly large number of junk functions
    that cause more and more compatibility issues with user code.

    There is no need to add a formal lengthof() operator when every user can create their own variation of ARRAYLEN in a few seconds.


    Correct. And most people don't create their own ARRAYLEN - why do so
    when you can write the same expression clearly and simply in a few
    seconds when you need it? And why even do that, when you almost always
    know the length of the array you are dealing with in the first place?

    Result: most people still end up writing
    sizeof(myarray)/sizeof(myarray[0]).

    I think most people write "n", or "buffer_size", or whatever expression
    they already have for the array in question.

    In the meantime, I'm been able to
    write myarray.len for 43 years, and also:

       print a, b       # who cares about format codes

    Convenient print formatting is one area where I agree C is poor.


    As for MIN/MAX, I routinely use:

       max(a, b)
       max(x, y)        # overloaded per type
       a max:=b         # augmented assignment
       a.max            # maximum value of a's type
       T.max            # maximum value of type T


    I personally don't see "max" or "min" operations coming up very often in
    my code. And when I do, it is often not by itself :

    if (x[i] > max) {
    max = x[i];
    max_index = i;
    show_new_max_value(max);
    }

    A built-in "max" function or operator would mean I needed a different identifier, and it would not be of any use in such code anyway.

    It is, at most, a trivial thing.

    Oh, and I already have Unless:

       unless a then b end
       return 0 unless cond

    It is not a macro.

    It is not good either - IMHO. You end up with time flowing forwards in
    some bits of your code, and backwards in other bits, which makes it significantly harder to follow.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Tue Apr 22 17:27:28 2025
    On 22/04/2025 17:10, Scott Lurndal wrote:

    proc main =
    puts("hello"
    end

    In C that would need '#include <stdio>'. Here, 'puts' is defined in a
    file which is part of my standard library which is automatically
    included by default.

    Which precludes user overrides of the standard library at compile
    time or run-time.

    I said 'by default'. Obviously there are ways of replacing the library
    or leaving it out completely.

    Or it can be left out and the library imported explicitly like this:

    import msyswin

    Only one such line is needed for everything, and it is only needed in
    the lead module of any project. But normally not that even that is required.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Tue Apr 22 17:48:17 2025
    bart <bc@freeuk.com> writes:
    On 22/04/2025 17:10, Scott Lurndal wrote:

    proc main =
    puts("hello"
    end

    In C that would need '#include <stdio>'. Here, 'puts' is defined in a
    file which is part of my standard library which is automatically
    included by default.

    Which precludes user overrides of the standard library at compile
    time or run-time.

    I said 'by default'. Obviously there are ways of replacing the library
    or leaving it out completely.

    I find it useful that APIs are distributed amongst many, many
    header files. The windows "all-in-one" header is fundamentally
    broken, as would be any implementation that followed that paradigm.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Tue Apr 22 19:19:47 2025
    On 22/04/2025 12:28, bart wrote:
    On 22/04/2025 02:06, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    I've seen a 33KB C file that expanded to 4MB after preprocessing. Macros >>> are evil.

    If macros were forbiden authors would probably write 4MB "by hand"
    (or rather using editor cut and paste).  Actually, creating first
    version probably would be not that hard, but maintanence would
    take a lot of effort (due to volume).


    It would probably be done by a script. This resulting code is not
    something to be written or consumed by a human. Which is an odd thing to
    say about a HLL.

    The example below is not as bad: the lines are only up to 1K chars
    instead of 50K.

    (I thought my own generated C code was poor; it's actually a million
    times more readable.)

    Of course, macro generated code is likely to contain significant
    fraction of useless instructions, but removing them by hand would
    be substantial work.  And trying to directly produce trimmed
    version would need a lot of work.  It is much cheaper to
    depend on optimizer to remove redundancies and useless instructions.

    How about writing decent, sensible code in the first place?

    Assuming that hand written version would be 80% smaller, you would
    have 800KB to write, that is more than 20 times the original
    source.  So in this case macros probably saved about 95% of
    work needed when coding without macros.

    You haven't seen this example, you don't know how bad it is, or how
    effective it was as a solution to whatever problem it was trying to
    solve, and yet YOU'RE MAKING EXCUSES FOR IT!

    This is a really odd phenomenon: is there no C code on the planet, that anybody here will admit that is badly written? Or that might be forced
    into being badly written due to shortcomings of the language?

    Here's a challenge for everyone here: please post an example, or a link
    to an example, that you think is truly appalling code.


    Here's a nice example:

             op_arith(L, l_addi, luai_numadd);

    Innocent-looking isn't it? It expands to this:

    {TValue*v1=(&((base+((((int)((((i)>>((((0+7)+8)+1)))&((~((~(Instruction)0)<<(8)))<<(0)))))))))->val);TValue*v2=(&((base+((((int)((((i)>>(((((0+7)+8)+1)+8)))&((~((~(Instruction)0)<<(8)))<<(0)))))))))->val);{StkId
    ra=(base+(((int)((((i)>>((0+7)))&((~((~(Instruction)0)<<(8)))<<(0)))))));if(((((v1))->tt_)==(((3)|((0)<<4))))&&((((v2))->tt_)==(((3)|((0)<<4))))){lua_Integer
    i1=(((v1)->value_).i);lua_Integer
    i2=(((v2)->value_).i);pc++;{TValue*io=((&(ra)->val));((io)->value_).i=(((lua_Integer)(((lua_Unsigned)(i1))+((lua_Unsigned)(i2)))));((io)->tt_=(((3)|((0)<<4))));};}else{lua_Number
    n1;lua_Number
    n2;if((((((v1))->tt_)==(((3)|((1)<<4))))?((n1)=(((v1)->value_).n),1):(((((v1))->tt_)==(((3)|((0)<<4))))?((n1)=((lua_Number)(((((v1)->value_).i)))),1):0))&&(((((v2))->tt_)==(((3)|((1)<<4))))?((n2)=(((v2)->value_).n),1):(((((v2))->tt_)==(((3)|((0)<<4)))
    )?((n2)=((lua_Number)(((((v2)->value_).i)))),1):0))){pc++;{TValue*io=((&(ra)->val));((io)->value_).n=(((n1)+(n2)));((io)->tt_=(((3)|((1)<<4))));};}};};};

     From this, I had to find the bug in my compiler.

    Not bad, I sometimes had to look for bugs in much bigger piece of
    code.

    So that means there's nothing wrong with it? Remember this is one
    expression.


    (Lua is an interpreter; I write interpreters and they are several times
    faster than Lua for equivalant inputs. I don't need to use such tricks.)

    IIUC Lua has some interesting properties.  Above I see masking and
    tag manipulations, presumably this is needed to implement Lua
    properties.

    Here you are making excuses again. Yes, Lua uses tags on some 64-bit
    value; so what? That can be done using ordinary code. Or if macros have
    to be used, they can be simple too.

    My own product uses apparently inefficient 128-bit values, it does
    everything 'wrong' but it uses readable HLL code with minimal use of
    macros, and yet it can run at several times the speed of Lua even unoptimised. You don't need to write gobbledygook.

    BTW here is that macro definition from Lua:

     #define op_arith(L,iop,fop) {  \
       TValue *v1 = vRB(i);  \
       TValue *v2 = vRC(i);  \
       op_arith_aux(L, v1, v2, iop, fop); }

    It calls yet more macros, and those in turn call others; here are a few
    for vRB:

      #define vRB(i)    s2v(RB(i))
      #define s2v(o)    (&(o)->val)
      #define RB(i)    (base+GETARG_B(i))
      #define GETARG_A(i)    getarg(i, POS_A, SIZE_A)
      #define getarg(i,pos,size)    (cast_int(((i)>>(pos)) & MASK1(size,0)))
      #define cast_int(i)    cast(int, (i))
      #define MASK1(n,p)    ((~((~(Instruction)0)<<(n)))<<(p))
      #define cast(t, exp)    ((t)(exp))

    I think the maximum depth here is 7-deep:

      op_arith -> vRB -> RB -> GETARG -> getarg -> cast_int -> cast

    This is not normal coding; it has replaced using functions to build
    programs, with macros. And it has replaced coding in C, with
    functional-style coding via the macro language.

    So what language would say this program is written in?

     I would expect that Lua has more than one artithemetic
    operation, so sharing code saves coding effort (actually, most
    of tag mainipulations probably can be shared by all Lua instructions).

    Any reason to uses *seven* levels of macro invocation? That is all in
    one branch.

    Do you think that's too many? Perhaps only 3 levels would have sufficed.
    Or would you automatically say it was reasonable no matter how many
    levels there were, just to disagee with me and to side with a fellow C programmer?



    I don't see any serious problem with this. It's not the way /I/ would
    code things, but I have different aims for my code than the Lua folks
    have for theirs. I don't know what all these macros do, or what all the abbreviations are - but that's because I don't know anything about the internals of the Lua byte-code interpreter and virtual machine.

    What I /do/ see here is that everything is built up with small parts
    combined and layered - that's how you do structured programming. It's a
    bit excessive IMHO in how much it is split up (perhaps the programmers
    are used to Forth), but that's a matter of taste.

    It doesn't matter that it is macros rather than functions - except that
    macros will probably give more efficient end results than functions
    would on weaker compilers that can't handle inlining well. (The
    compiler still needs to do good expression optimisation for efficient
    results.) Lua is intended to be portable to a wide range of different compilers of different capabilities.

    The Lua programmers never intend humans to read the expansion of the
    macros - that is completely unnecessary. Get each macro right
    individually, and the final result is correct - again, that's the way structured programming is done.

    The cryptic names do mean it would take more effort to learn to
    understand what's going on here for people involved in maintaining the
    code, but that only applies to a very few people. It doesn't even apply
    to most C compiler implementers - they just need to read the C standards
    and write a compiler that follows the C rules, and it should have no
    problem compiling the Lua virtual machine.


    Instead of thinking of this as some kind of abuse of C macros or incomprehensible expanded expressions, consider it more as a
    domain-specific language written in C macros with the intention of
    making it easier to write the higher level parts of the Lua virtual
    machine. You are not expected to be able to read the expanded C code
    any more than the average C programmer is expected to be able to read generating binary images.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Tue Apr 22 19:54:01 2025
    On 22/04/2025 19:16, David Brown wrote:
    On 22/04/2025 09:54, Janis Papanagnou wrote:
    On 21.04.2025 17:36, bart wrote:
    On 21/04/2025 14:51, Waldek Hebisch wrote:

    [ sqlite3.c code ]

    You have to analyse it first. The kind of loop this expresses is:

    No. That's just *your* _transcription_ of the original code

        p = startvalue()

        while (p) {
           <body>
           p = nextvalue()
        }

    Notice how I chose to express it: it reflects how I would describe it in >>> English:

    You are *not* describing _the task_, you are merely translating the
    _chosen commands_ of the procedural language [that you have chosen]


        * Set P to Start Value
        * While P isn't Null:
          * Execute the body
          * Set P to Next Value

    Whatever programming language and constructs you use, this is not
    more than a rephrasing the used language constructs (as opposed to
    the task).

    (It's not surprising; you can observe that folks that are familiar
    only with imperative languages tend to this sort of fallacy.)

    So, how would /you/ describe it in English? (Or in any language if like, >>> as the ordering is more important.)

    Iterate over the elements and sequentially perform <the task> on
    the elements. Or a bit more formally

       iterate (elements, task)

    in some functional programming language. Or any other variant on
    any abstraction level that is appropriate.


    Alternatively, you might describe it as "Perform the task on each
    element" :

        task(e) for e in elements

    Sometimes you want to emphasise moving through the elements, sometimes
    you want to emphasise what you are doing with them - but either way is
    fine.

    You may or may not include an order in the iteration, depending on what
    you actually want to do here (I have no idea of the purpose of the
    original code).

    I would suggest Bart thinks this through using a real-world task.
    Consider making a cake by mixing the ingredients you have laid out on
    your kitchen top.  Would you use Janis' formulation?

        Go through the ingredients, putting each in the bowl.

    Or mine?

        Put in the bowl each of the ingredients.

    Or Bart's ?

        Stand in front of the first ingredient.
        While you have an ingredient in front of you :
            Put the ingredient in the bowl.
            Move to the next ingredient.

    Well C's would be:

    For (first ingredient; ingredient; next ingredient)

    We /are/ still about expressing a loop in C, yes? At least mine directly translates to C:

    x = first_ingredient(); // C needs some state
    while (x != empty) {
    put_ingredient();
    x = next_ingredient();
    }

    I'd be interested in how your 'Put in the bowl each of the ingredients' translates into:

    FOR(W; X; Y) {Z;}

    There is also nothing about this syntax that directly indicates the
    middle term X is the terminating condition; it is just expression #2 of 3.

    It doesn't read as English; not in this form. Whereas FOR I IN A TO B is already most of the way there, as is WHILE (CONDITION).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Janis Papanagnou on Tue Apr 22 20:16:13 2025
    On 22/04/2025 09:54, Janis Papanagnou wrote:
    On 21.04.2025 17:36, bart wrote:
    On 21/04/2025 14:51, Waldek Hebisch wrote:

    [ sqlite3.c code ]

    You have to analyse it first. The kind of loop this expresses is:

    No. That's just *your* _transcription_ of the original code

    p = startvalue()

    while (p) {
    <body>
    p = nextvalue()
    }

    Notice how I chose to express it: it reflects how I would describe it in
    English:

    You are *not* describing _the task_, you are merely translating the
    _chosen commands_ of the procedural language [that you have chosen]


    * Set P to Start Value
    * While P isn't Null:
    * Execute the body
    * Set P to Next Value

    Whatever programming language and constructs you use, this is not
    more than a rephrasing the used language constructs (as opposed to
    the task).

    (It's not surprising; you can observe that folks that are familiar
    only with imperative languages tend to this sort of fallacy.)

    So, how would /you/ describe it in English? (Or in any language if like,
    as the ordering is more important.)

    Iterate over the elements and sequentially perform <the task> on
    the elements. Or a bit more formally

    iterate (elements, task)

    in some functional programming language. Or any other variant on
    any abstraction level that is appropriate.


    Alternatively, you might describe it as "Perform the task on each element" :

    task(e) for e in elements

    Sometimes you want to emphasise moving through the elements, sometimes
    you want to emphasise what you are doing with them - but either way is fine.

    You may or may not include an order in the iteration, depending on what
    you actually want to do here (I have no idea of the purpose of the
    original code).

    I would suggest Bart thinks this through using a real-world task.
    Consider making a cake by mixing the ingredients you have laid out on
    your kitchen top. Would you use Janis' formulation?

    Go through the ingredients, putting each in the bowl.

    Or mine?

    Put in the bowl each of the ingredients.

    Or Bart's ?

    Stand in front of the first ingredient.
    While you have an ingredient in front of you :
    Put the ingredient in the bowl.
    Move to the next ingredient.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Tue Apr 22 21:11:54 2025
    On 22/04/2025 20:54, bart wrote:
    On 22/04/2025 19:16, David Brown wrote:
    On 22/04/2025 09:54, Janis Papanagnou wrote:
    On 21.04.2025 17:36, bart wrote:
    On 21/04/2025 14:51, Waldek Hebisch wrote:

    [ sqlite3.c code ]

    You have to analyse it first. The kind of loop this expresses is:

    No. That's just *your* _transcription_ of the original code

        p = startvalue()

        while (p) {
           <body>
           p = nextvalue()
        }

    Notice how I chose to express it: it reflects how I would describe
    it in
    English:

    You are *not* describing _the task_, you are merely translating the
    _chosen commands_ of the procedural language [that you have chosen]


        * Set P to Start Value
        * While P isn't Null:
          * Execute the body
          * Set P to Next Value

    Whatever programming language and constructs you use, this is not
    more than a rephrasing the used language constructs (as opposed to
    the task).

    (It's not surprising; you can observe that folks that are familiar
    only with imperative languages tend to this sort of fallacy.)

    So, how would /you/ describe it in English? (Or in any language if
    like,
    as the ordering is more important.)

    Iterate over the elements and sequentially perform <the task> on
    the elements. Or a bit more formally

       iterate (elements, task)

    in some functional programming language. Or any other variant on
    any abstraction level that is appropriate.


    Alternatively, you might describe it as "Perform the task on each
    element" :

         task(e) for e in elements

    Sometimes you want to emphasise moving through the elements, sometimes
    you want to emphasise what you are doing with them - but either way is
    fine.

    You may or may not include an order in the iteration, depending on
    what you actually want to do here (I have no idea of the purpose of
    the original code).

    I would suggest Bart thinks this through using a real-world task.
    Consider making a cake by mixing the ingredients you have laid out on
    your kitchen top.  Would you use Janis' formulation?

         Go through the ingredients, putting each in the bowl.

    Or mine?

         Put in the bowl each of the ingredients.

    Or Bart's ?

         Stand in front of the first ingredient.
         While you have an ingredient in front of you :
             Put the ingredient in the bowl.
             Move to the next ingredient.

    Well C's would be:

       For (first ingredient; ingredient; next ingredient)

    The point was that you claimed your loop matches how you would describe
    things in English. That was nonsense. Your loop - whether it is in
    your language or your preference for C loops - is no closer to a normal
    English language description than C's for-loops are.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Tue Apr 22 21:03:21 2025
    On 22/04/2025 20:26, Kaz Kylheku wrote:
    On 2025-04-22, bart <bc@freeuk.com> wrote:

    Or would you automatically say it was reasonable no matter how many
    levels there were, just to disagee with me and to side with a fellow C
    programmer?

    You're trying to say that C is a bad language because you can have
    7 or more layers of macro expansion, but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    Here, I'm trying to determine if this is the poster's honest, objective opinion, or whether they'd always going to be defend such code no matter
    what.

    14 levels of macros? No problem; I'm sure there was a good reason!

    I did ask at one point whether anybody could link to some truly terrible
    C code; nobody has so far.

    I just want to find out the threshold at which some will actually agree
    that macros have been abused or their use is over the top and unjustified.

    There doesn't seem to be any limit - or not any that they want to admit
    to me.


    but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    There WILL be a cap. Some deep nesting might be justified in special
    cases, for example some recursive macro that builds a string a character
    at a time.

    But this was not such a case; it was simply decided to make it work
    using macros instead of functions.

    As for being crippling: I've written all sorts of language apps,
    including interpreters like this, without ever using more than one
    level, and for several decades, zero levels.

    A language like C provides all these odd-ball features, people are going
    to use them.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Tue Apr 22 20:43:45 2025
    On 22/04/2025 20:11, David Brown wrote:
    On 22/04/2025 20:54, bart wrote:

    Well C's would be:

        For (first ingredient; ingredient; next ingredient)

    The point was that you claimed your loop matches how you would describe things in English.

    And it does exactly that. I get why people decide to go up several
    levels to try score some points, but we're not talking about AI here
    where we are trying to extract the exact algorithm that might have been
    in the mind of the programmer.

    This:
    a=b;
    while (c) {
    d;
    e;
    }

    can alway be directly translated to English, a line at a time:

    Assign b to a; While c: (Do d, Do e)

    The only liberty taken is turning ") {}" into ": ()".

    Now try that with the equivalent "for (a=b; c; e;) {d;}. There is no
    direct mapping.

    But if you want do it your way, what algorithm ss being expressed here:

    for(a; b; c) {d}

    You can't do it; there isn't enough information, or you'd have to
    analyse it more deeply. However you CAN describe the outline of what is
    being executed, and you CAN port that to a different language, just about.

    Here it is in Python (it may need the details tweaked):

    a
    while b:
    d
    c

    And guess what - it's a WHILE loop!

    Whichever way you want to slice it, FOR(A;B;C) is a glorified WHILE
    loop. And a lot of the time it is much better suited as such.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Tue Apr 22 19:26:19 2025
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    BTW here is that macro definition from Lua:

    #define op_arith(L,iop,fop) { \
    TValue *v1 = vRB(i); \
    TValue *v2 = vRC(i); \
    op_arith_aux(L, v1, v2, iop, fop); }

    I'm assuming that op_arith is called numerous times to define handling
    for various VM opcodes.

    It *reliably* writes a bunch of code that would otherwise require a lot
    of error-prone copy and paste.

    This is language extension; the LUA maintainers have written
    themselves an op_arith language feature.

    The generated codee is large and complex, but at least you can see it.

    If that language feature were wired into the compiler, it would only
    be harder to work with. All that morass of code would be hidden
    inside, generated into some intermediate representation (that you
    can perhaps intercept and get in some readable form, in a
    language/notation you will have to learn).

    It calls yet more macros, and those in turn call others; here are a few
    for vRB:

    #define vRB(i) s2v(RB(i))
    #define s2v(o) (&(o)->val)
    #define RB(i) (base+GETARG_B(i))
    #define GETARG_A(i) getarg(i, POS_A, SIZE_A)
    #define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0)))
    #define cast_int(i) cast(int, (i))
    #define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p))
    #define cast(t, exp) ((t)(exp))

    Some of these look like low value. For instance cast_int(x) saves no characters over cast(int,x), and ony one character over cast(int, x),
    and that is longer than just (int)(x), not to mention (int)x
    situations where you can omit parentheses.

    I've only defined cast macros for the purpose of switching between
    C casts and C++ casts. If that's not going on here, it's just
    gratuitous macrology.

    The switching I'm talking about is this:

    #ifdef __cplusplus
    #define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
    #define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
    #define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
    #else
    #define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
    #define convert(TYPE, EXPR) ((TYPE) (EXPR))
    #define coerce(TYPE, EXPR) ((TYPE) (EXPR))
    #endif

    The purpose is to gain access to the finer-grained C++ casts when
    the code is compiled as C++, but fall back on the C casts when it
    is compiled as C. These macros *do* something, so they are needed.

    I don't want to have #ifdef __cplusplus all over the place and write
    the same expressions twice with different casts.

    So what language would say this program is written in?

    Obviously C. C has preprocessing and so, the above is what C sometimes
    looks like.

    It's obviously not written in the C-without-preprocessing subset of C.

    I would expect that Lua has more than one artithemetic
    operation, so sharing code saves coding effort (actually, most
    of tag mainipulations probably can be shared by all Lua instructions).

    Any reason to uses *seven* levels of macro invocation? That is all in
    one branch.

    It allows the code to be built up in small chunks that are easy
    to understand (when looking at the macro definitions).

    If all else is equal, such as the sizes of the code mountains, one layer
    of macro to generate the mountain of code is almost always going to be objectively worse than a macro defined in several hierarchical levels
    that offer some meaningful "chunking" to someone reading the code.

    The definition will likely be more condensed, due to certain lower level
    macros are used more than once in the higher level ones.

    Do you think that's too many? Perhaps only 3 levels would have sufficed.

    Low-value macros that only add levels of expansion without payoff should
    be avoided. If there are 7 levels, but 4 of them are some low-value
    syntactic sugar, a case can be made for reducing.

    If we go by the chunking concept in cognitive psychology, that people
    do well with an abstraction layer that has about 7 chunks of content,
    in 7 layers of 7 chunks, we get a hierarchy with 800,000 items at the
    leaf level, which is an improbable morass.

    In 7 layers of macros, some of the layers are going to have low
    branching factors, just providing some minor notations, sometimes
    of little value.

    Or would you automatically say it was reasonable no matter how many
    levels there were, just to disagee with me and to side with a fellow C programmer?

    You're trying to say that C is a bad language because you can have
    7 or more layers of macro expansion, but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Tue Apr 22 21:40:28 2025
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    On 22/04/2025 20:26, Kaz Kylheku wrote:
    On 2025-04-22, bart <bc@freeuk.com> wrote:

    Or would you automatically say it was reasonable no matter how many
    levels there were, just to disagee with me and to side with a fellow C
    programmer?

    You're trying to say that C is a bad language because you can have
    7 or more layers of macro expansion, but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    Here, I'm trying to determine if this is the poster's honest, objective opinion, or whether they'd always going to be defend such code no matter what.

    I identified some macros in there that look gratuitous; you just snipped
    that part.

    but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    There WILL be a cap. Some deep nesting might be justified in special
    cases, for example some recursive macro that builds a string a character
    at a time.

    But this was not such a case; it was simply decided to make it work
    using macros instead of functions.

    If you're going to criticize the macros, then hold the code constant.

    If it is a given requirement that some code is to be written or
    generated, and we have some macros which do that, are those macros a
    "good" or "bad" solution?

    If you think some other code shoud be written or generated, and not
    the code produced by those macros, or equivalent to it, then that
    doesn't speak to those macros.

    It looks like that Lua VM is doing way too much work just to dispatch
    an opcode, but if we take that crud as a given, the layers of macros may
    be a bad way to obtain it, out of all the alternatives. A somewhat
    cleaned up version of those macros would likely be better.

    I don't think Lua is very good; I would never choose it for anything, or basically go anywhere near it. I'm not even slightly surprised the code
    is grotty.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Keith Thompson on Tue Apr 22 22:39:25 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    scott@slp53.sl.home (Scott Lurndal) writes:
    [...]
    And even then, his complaints would never have gained traction;
    the basic syntax of C hasn't changed for forty years, particularly
    with respect to the syntax related to the 'for' keyword.

    That's not *quite* true. The syntax of the for loop changed
    significantly in C99, allowing for a declaration as the first clause
    (a feature borrowed from C++).

    Yes, that's true. It's more a logical extension, however, than a change IMO. Your point is taken.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Tue Apr 22 23:52:05 2025
    On 22/04/2025 22:15, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    On 22/04/2025 02:22, Keith Thompson wrote:
    [...]
    For example, in my post to which you replied, I discussed at
    some length how I like to split for loops if they're too long.
    You snipped that discussion *and then* insinuated that I don't care
    about complex loops written on one line. Please stop doing things
    like that.

    Well I care about it too, and I would write such things more sensibly
    as well. But so what? Most code I see tends to be badly
    formatted. For-headers are not split up unless they're long enough to
    overflow the line.

    It's something about the culture behind 'for' that encourages poor
    coding style.

    Did you miss my point, or did you deliberately ignore it?

    You snipped part of my text in which I discussed how I like to split
    long for loops. You then insinuated that I personally don't care
    about complex loops written on one line, after I clearly demonstrated
    that I do, and you hid the evidence.

    I'm asking you to stop doing that kind of thing.

    I'm making a point, not about technical disagreements, but about you, deliberately or otherwise, misrepresenting what I've written.


    I think my comments above stand.

    Of course, everybody here (me included) will claim their own code is
    cleanly laid out; it's everybody else's that is the problem.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Wed Apr 23 00:43:23 2025
    On 22/04/2025 22:40, Kaz Kylheku wrote:
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    On 22/04/2025 20:26, Kaz Kylheku wrote:
    On 2025-04-22, bart <bc@freeuk.com> wrote:

    Or would you automatically say it was reasonable no matter how many
    levels there were, just to disagee with me and to side with a fellow C >>>> programmer?

    You're trying to say that C is a bad language because you can have
    7 or more layers of macro expansion, but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    Here, I'm trying to determine if this is the poster's honest, objective
    opinion, or whether they'd always going to be defend such code no matter
    what.

    I identified some macros in there that look gratuitous; you just snipped
    that part.

    but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    There WILL be a cap. Some deep nesting might be justified in special
    cases, for example some recursive macro that builds a string a character
    at a time.

    But this was not such a case; it was simply decided to make it work
    using macros instead of functions.

    If you're going to criticize the macros, then hold the code constant.

    If it is a given requirement that some code is to be written or
    generated, and we have some macros which do that, are those macros a
    "good" or "bad" solution?

    Why use macros at all?

    They might be a big deal in your own language, but in my experience,
    largely in C, they seem to cause nothing but grief.

    Here, it produces neither faster code nor smaller.

    It makes debugging, porting, or anything requiring deep understanding, a nightmare.

    This project uses approx 500 macros that look like functions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Wed Apr 23 00:01:09 2025
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    If you're going to criticize the macros, then hold the code constant.

    If it is a given requirement that some code is to be written or
    generated, and we have some macros which do that, are those macros a
    "good" or "bad" solution?

    Why use macros at all?

    You need to repeat some verbose coding pattern without copy-and-paste
    mistakes. If that coding pattern has a bug or has to be revised for any
    reason, you want to do it in one place.

    You need to control the evaluation of an argument expression, rather
    than just receive its value.

    You need to set up some code that declares variables or interacts
    with declared identifiers in scope.

    They might be a big deal in your own language, but in my experience,
    largely in C, they seem to cause nothing but grief.

    But:

    for_sqlite_hash(p, hash) { ... }

    has only one simple level of expansion; saves typing, no grief.

    The fact that Lua has some grotty macros in its VM doesn't speak
    to a nice use of macros, like what I was talking about.

    You comitted a slippery slope type fallacy, or similar, by bringing
    that up. "Macros /can/ be layered to 10 layers deeper and make the logic inscrutable, therefore all macros are a bad idea, including a simple, single-expansion iteration macro for sqlite hashes."

    Here, it produces neither faster code nor smaller.

    That's neither here nor there; all that matters is whether it's a good
    way to produce the code that the author wanted.

    Additionally, it may be possible to replace the implementation of the
    macro such that it generates some other code that is faster, and such
    that it remains compatible; all the calls to the macro remain valid, and
    so new code for handling all the opcodes is generated.

    The macro is called like this:

    op_arith(L, l_addi, luai_numadd);

    that's pretty abstract; chances are it could be preserved if
    the implementation strategy were substantially altered.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Kaz Kylheku on Wed Apr 23 09:01:20 2025
    On 22/04/2025 21:26, Kaz Kylheku wrote:
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    BTW here is that macro definition from Lua:

    #define op_arith(L,iop,fop) { \
    TValue *v1 = vRB(i); \
    TValue *v2 = vRC(i); \
    op_arith_aux(L, v1, v2, iop, fop); }

    I'm assuming that op_arith is called numerous times to define handling
    for various VM opcodes.

    It *reliably* writes a bunch of code that would otherwise require a lot
    of error-prone copy and paste.

    This is language extension; the LUA maintainers have written
    themselves an op_arith language feature.


    That's a good way to describe it.

    The generated codee is large and complex, but at least you can see it.

    Yes, but that is only needed by the people writing and debugging the
    macros involved.


    If that language feature were wired into the compiler, it would only
    be harder to work with. All that morass of code would be hidden
    inside, generated into some intermediate representation (that you
    can perhaps intercept and get in some readable form, in a
    language/notation you will have to learn).

    It calls yet more macros, and those in turn call others; here are a few
    for vRB:

    #define vRB(i) s2v(RB(i))
    #define s2v(o) (&(o)->val)
    #define RB(i) (base+GETARG_B(i))
    #define GETARG_A(i) getarg(i, POS_A, SIZE_A)
    #define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0)))
    #define cast_int(i) cast(int, (i))
    #define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p))
    #define cast(t, exp) ((t)(exp))

    Some of these look like low value. For instance cast_int(x) saves no characters over cast(int,x), and ony one character over cast(int, x),
    and that is longer than just (int)(x), not to mention (int)x
    situations where you can omit parentheses.

    It is certainly split up more than I would have written, but there are
    perhaps good reasons for the style. I haven't seen any more of the code
    than what Bart has quoted here - perhaps there are other situations in
    which "cast_int" is being passed as a parameter in another macro. Or
    maybe there are historical reasons - "cast_int" came first, then there
    were other "cast_X" macros added later, then a generic "cast" macro and "cast_int" was redefined in terms of the generic one. Maybe there are development or test versions of some of these macros where the plain
    casts are replaced by runtime checks before the conversion, and what we
    see here is just the release versions without the checks.

    Or maybe they were just written by someone who likes to divide things up
    a bit more, or they were mixed from different sources or authors with
    minimal changes (that might explain the different capitalisation styles).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Wed Apr 23 11:15:01 2025
    On 23/04/2025 01:01, Kaz Kylheku wrote:
    On 2025-04-22, bart <bc@freeuk.com> wrote:
    If you're going to criticize the macros, then hold the code constant.

    If it is a given requirement that some code is to be written or
    generated, and we have some macros which do that, are those macros a
    "good" or "bad" solution?
    The fact that Lua has some grotty macros in its VM doesn't speak
    to a nice use of macros, like what I was talking about.

    You comitted a slippery slope type fallacy, or similar, by bringing
    that up. "Macros /can/ be layered to 10 layers deeper and make the logic inscrutable, therefore all macros are a bad idea, including a simple, single-expansion iteration macro for sqlite hashes."

    Here, it produces neither faster code nor smaller.

    That's neither here nor there; all that matters is whether it's a good
    way to produce the code that the author wanted.

    IMV, macros generally are a bad idea. They are especially bad with how
    they are implemented in C:

    * Their implementation is complex and poorly defined.

    * It is a language within a language: a quite different one that can be
    very challenging to code in, and even more challenging trying to
    understand or debug it

    * They make hard to port software or to convert APIs if they are full of
    C macros (GTK2 headers use 4000 macros)

    * Compiler error messages can get weird and confusing

    * In C, macros can generate random, unbalanced bits of syntax

    * They cause problems for tools such as smart editors

    * Macros don't obey normal scope rules.

    * Macros tend to get abused or over-used, and people try to be too clever

    * Macro solutions tend to be ugly and tacky (see X-macros)

    * Macro expansion can do too much:

    #define length 200
    #define width 100

    struct {char* str; int length;} s;
    s.length = 0; // oops!

    Additionally, it may be possible to replace the implementation of the
    macro such that it generates some other code that is faster, and such
    that it remains compatible; all the calls to the macro remain valid, and
    so new code for handling all the opcodes is generated.

    The macro is called like this:

    op_arith(L, l_addi, luai_numadd);

    that's pretty abstract; chances are it could be preserved if
    the implementation strategy were substantially altered.

    What's the problem with using a function here?

    Why use macros at all?

    You need to repeat some verbose coding pattern without copy-and-paste mistakes. If that coding pattern has a bug or has to be revised for any reason, you want to do it in one place.

    You need to control the evaluation of an argument expression, rather
    than just receive its value.

    You need to set up some code that declares variables or interacts
    with declared identifiers in scope.
    They might be a big deal in your own language, but in my experience,
    largely in C, they seem to cause nothing but grief.

    But:

    for_sqlite_hash(p, hash) { ... }

    has only one simple level of expansion; saves typing, no grief.

    Most languages don't have C-style macros; how do they manage?

    Some may not have macros at all; I think D, Java, Zig, Go.

    I admit there are some use-cases that cannot easily be achieved by other
    means. For that reason I experimented with macros in my own two
    languages a few years ago. But those have a much smaller scope than C
    macros, while also being more integrated:

    * A macro, which can take parameters, can only be an alias for an
    expression term, not random syntax

    * Macro expansion takes place at a late stage, so it cannot define new
    symbol names

    * Macro expansion only occurs for top-level names, so the M in M.A.B is expanded, but not in A.M.B.

    * Macro names have normal scope rules

    * Macro names can be imported and exported like any other named entity

    Even with such a limited scheme, it can cover your examples, except for abstracting loops. But, given that the loop body in this case is only a
    single function call, that can easily be handled by a function.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Wed Apr 23 10:58:12 2025
    On Wed, 23 Apr 2025 11:15:01 +0100
    bart <bc@freeuk.com> wibbled:
    IMV, macros generally are a bad idea. They are especially bad with how
    they are implemented in C:

    C macros do essentially 4 different things:
    1) Provide a way to pass compilation data directly into the code via compiler
    switches and #ifdef
    2) Allow conditional compilation for different OS's
    3) Allow repeating blocks of code to be compacted into a single macro when
    having a function instead would be more complicated and/or inefficient.
    4) An alternative to inline functions. Probably the least useful.

    * Their implementation is complex and poorly defined.

    Maybe to you.

    * Compiler error messages can get weird and confusing

    If you think C errors are confusing try C++ with template errors.

    * They cause problems for tools such as smart editors

    Any "smart" editor that can't cope with macros isn't smart.

    * Macros don't obey normal scope rules.

    They're not supposed to.

    * Macro solutions tend to be ugly and tacky (see X-macros)

    So can any code.

    * Macro expansion can do too much:

    #define length 200
    #define width 100

    struct {char* str; int length;} s;
    s.length = 0; // oops!

    So what? You'd get a compilation error.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Muttley@DastardlyHQ.org on Wed Apr 23 14:50:22 2025
    On 23/04/2025 11:58, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 11:15:01 +0100
    bart <bc@freeuk.com> wibbled:
    IMV, macros generally are a bad idea. They are especially bad with how
    they are implemented in C:

    C macros do essentially 4 different things:
    1) Provide a way to pass compilation data directly into the code via compiler
    switches and #ifdef
    2) Allow conditional compilation for different OS's

    That does not need expandable macros.

    3) Allow repeating blocks of code to be compacted into a single macro when
    having a function instead would be more complicated and/or inefficient. 4) An alternative to inline functions. Probably the least useful.

    * Their implementation is complex and poorly defined.

    Maybe to you.

    Have you ever implemented a C preprocessor?

    * Macros don't obey normal scope rules.

    They're not supposed to.

    So, is that good or bad? (Let me guess: it's good that it works like that!)

    So what? You'd get a compilation error.

    If you're lucky. Or you get a silent, undetectable bug, since any
    alphanumeric token: identifier, type, or reserved word, gets expanded,
    no matter what the context.

    (Let me guess again: that's still fine!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Wed Apr 23 17:41:39 2025
    On 22/04/2025 21:43, bart wrote:
    On 22/04/2025 20:11, David Brown wrote:
    On 22/04/2025 20:54, bart wrote:

    Well C's would be:

        For (first ingredient; ingredient; next ingredient)

    The point was that you claimed your loop matches how you would
    describe things in English.

    And it does exactly that. I get why people decide to go up several
    levels to try score some points, but we're not talking about AI here
    where we are trying to extract the exact algorithm that might have been
    in the mind of the programmer.


    I think it was Djikstra who said that one of the most important skills
    for a programmer is a mastery of your mother tongue. You seem to be
    failing here.

    No one is doubting your ability to translate some code directly into
    English words. What you are failing to do, however, is write a
    sensible, normal English language description of the task for the code,
    and then translate that into code. You can't expect people to take you seriously when you say a C for-loop does not match a normal English
    description when your own looping alternatives are equally bad matches.

    Let me put it simply for you:

    It is true that no one uses C for-loops in normal English.

    It is equally true that no one uses while-loops in normal English.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Wed Apr 23 17:31:29 2025
    On 22/04/2025 22:03, bart wrote:
    On 22/04/2025 20:26, Kaz Kylheku wrote:
    On 2025-04-22, bart <bc@freeuk.com> wrote:

    Or would you automatically say it was reasonable no matter how many
    levels there were, just to disagee with me and to side with a fellow C
    programmer?

    You're trying to say that C is a bad language because you can have
    7 or more layers of macro expansion, but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    Here, I'm trying to determine if this is the poster's honest, objective opinion, or whether they'd always going to be defend such code no matter what.

    14 levels of macros? No problem; I'm sure there was a good reason!

    If there is good reason for 14 levels of macros, then fine.

    If there are not /good/ reasons for multiple levels, but the result is
    correct code that compiles efficiently (on reasonable compilers with
    reasonable options), then maybe it is appropriate to leave it untouched.

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter) makes code hard
    to write and hard to get correct - you are doing too much at a time.
    Splitting things up - divide and conquer - is a big win. But too many
    levels also makes it hard to see what is going on and can be a
    maintenance challenge.

    So once you first have too many levels - for whatever reasons - and the
    code is correct and does the job, you have to decide whether or not to
    refactor into simpler, neater and clearer code. The result would be
    easier to maintain in the future, but it has a cost in time, effort and
    the risk of making mistakes.


    I did ask at one point whether anybody could link to some truly terrible
    C code; nobody has so far.

    There are probably two reasons for that. One is that everyone, except
    perhaps you, understands that this is very subjective. I've seen plenty
    of code posted in this group, written by regulars whose programming
    skill and knowledge I highly respect, and yet which I would classify as
    "truly terrible" and reject it immediately if it were presented to me
    for code review in my work. The other reason is that nobody else is particularly interested in seeing bad code, or going out of their way to
    look for it.


    I just want to find out the threshold at which some will actually agree
    that macros have been abused or their use is over the top and unjustified.


    Why?

    We are all going to have different first-glance opinions on different
    bits of code. But to form a solid, justifiable opinion I would want to
    see a lot more of the code in question. I'd want to look at the macro definitions, and how they are used in the code - the macros alone are
    far from enough. I'd want to know the history of the project. I'd want
    to know the target usage of the code. I'd want to see its
    documentation, its roadmap for the future, its history of bugs and other problems. I'd want to know more about the developers behind the code.
    I'd want to know if other people are expected to read the code, to work
    with it, to re-use it, or if they would simply see it as a finished
    product. I'd want to know if it is targeting a specific device, OS,
    processor, compiler, or if it is intended to be portable. I'd want to
    know how it is tested. I'd want to know if it is viewed as low-risk,
    low-cost software, or intended to be secure or highly reliable.

    Clearly, I haven't the slightest interest in going to that effort just
    to please you.

    So the best I can offer you is a very cursory glance at the code, and
    the opinion that - in the case of the Lua source code snippet - it's
    probably fine, but a bit more finely divided than I would like myself,
    though there may be good reasons behind that.

    I really can't see what any of that gives you.

    We all know that some people write bad code, or have written bad code.
    I don't think anyone will deny that. We also all have different
    thoughts and experiences on what makes code good or bad, or when bad
    code might be perfectly acceptable - all such judgements are very
    subjective, and therefore of little use here.

    And we all know this is entirely independent of programming language.


    There doesn't seem to be any limit - or not any that they want to admit
    to me.

    It is absolutely correct that there is no dividing line between "good
    code" and "bad code", or "use" and "abuse".



    but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    There WILL be a cap.

    No.

    Very few things in this world are black-or-white.

    Some deep nesting might be justified in special
    cases, for example some recursive macro that builds a string a character
    at a time.

    But this was not such a case; it was simply decided to make it work
    using macros instead of functions.

    How do you know that?


    As for being crippling: I've written all sorts of language apps,
    including interpreters like this, without ever using more than one
    level, and for several decades, zero levels.


    And how do you know that is a good choice, or would be better in this case?

    A language like C provides all these odd-ball features, people are going
    to use them.

    Macros are hardly odd-ball.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Wed Apr 23 16:00:16 2025
    On Wed, 23 Apr 2025 14:50:22 +0100
    bart <bc@freeuk.com> wibbled:
    On 23/04/2025 11:58, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 11:15:01 +0100
    bart <bc@freeuk.com> wibbled:
    IMV, macros generally are a bad idea. They are especially bad with how
    they are implemented in C:

    C macros do essentially 4 different things:
    1) Provide a way to pass compilation data directly into the code via compiler

    switches and #ifdef
    2) Allow conditional compilation for different OS's

    That does not need expandable macros.

    It needs something so why not use macros.

    3) Allow repeating blocks of code to be compacted into a single macro when >> having a function instead would be more complicated and/or inefficient. >> 4) An alternative to inline functions. Probably the least useful.

    * Their implementation is complex and poorly defined.

    Maybe to you.

    Have you ever implemented a C preprocessor?

    No, have you? I've not built a smartphone either but I don't find them complex to use.

    * Macros don't obey normal scope rules.

    They're not supposed to.

    So, is that good or bad? (Let me guess: it's good that it works like that!)

    Why would you want scoping with macros FFS? They need to be consistent and available everywhere in a piece of source code.

    So what? You'd get a compilation error.

    If you're lucky. Or you get a silent, undetectable bug, since any

    No, not if you're lucky - you WILL get an error with that example. Why don't you try it instead of gassing.

    alphanumeric token: identifier, type, or reserved word, gets expanded,
    no matter what the context.

    Yes, thats whole the fucking point. If you don't want that don't use them!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Keith Thompson on Wed Apr 23 19:05:01 2025
    On 23/04/2025 00:02, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 22/04/2025 02:12, bart wrote:
    [...]
    (Only Keith cautiously welcome the idea of such a feature, while MS
    said he would vote against it, and JP said they would have proposed
    it on April 1st.)

    I don't recall reading Keith saying any such thing. He said he would
    be willing to nit-pick a proposal for a new "for-loop" syntax - not
    that he would welcome it. Perhaps he just thinks he would enjoy
    nit-picking such a paper. As for using a feature if it were added to
    C, I know I probably would do so in my own code - that does not imply
    that I think such a feature is needed, or that I have any trouble
    using C's current syntax for simple loops. (I find C++'s alternative
    for-loop syntax nicer for iterating over containers, but that is not
    as easily translatable into C.)

    Here's what I wrote:

    """
    Again, I would not object to adding a new kind of for loop,
    similar to what you would prefer, and visually distinct from the
    existing for loop, in a new version of the C standard. But that's
    not likely to happen because there doesn't seem to be much demand
    for it (for reasons that I know make you angry), and I don't care
    enough to write a proposal. If someone else does write a proposal,
    I'll be glad to help out by nitpicking it.
    """

    I'll accept that "cautiously accept" is close enough to "would not
    object".


    I had considered them as noticeably different, but I will of course
    accept your opinion here! To me, "cautiously accept" is a sceptical
    "yes" vote, while "would not object" is an "abstain".

    [...]

    I guess I am the exception - I've never needed any of these. But for
    your information, C23 has a _Lengthof operator

    C23 does not have _Lengthof. It's proposed for C2y.


    Sorry, yes. The pdf I was viewing was the latest draft for post-C23
    rather than C23. My mistake.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Muttley@DastardlyHQ.org on Wed Apr 23 17:39:18 2025
    On 23/04/2025 17:00, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 14:50:22 +0100
    bart <bc@freeuk.com>:
    On 23/04/2025 11:58, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 11:15:01 +0100
    bart <bc@freeuk.com>:

    * Their implementation is complex and poorly defined.

    Maybe to you.

    Have you ever implemented a C preprocessor?

    No, have you?

    Yes.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Wed Apr 23 18:43:14 2025
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in
    their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary
    block of syntax:

    #define INDEX(a, b, y) a y b
    INDEX(a, i, [) ];

    I did ask at one point whether anybody could link to some truly
    terrible C code; nobody has so far.

    There are probably two reasons for that.  One is that everyone, except perhaps you, understands that this is very subjective.  I've seen plenty
    of code posted in this group, written by regulars whose programming
    skill and knowledge I highly respect, and yet which I would classify as "truly terrible" and reject it immediately if it were presented to me
    for code review in my work.  The other reason is that nobody else is particularly interested in seeing bad code, or going out of their way to
    look for it.


    I just want to find out the threshold at which some will actually
    agree that macros have been abused or their use is over the top and
    unjustified.


    Why?

    We are all going to have different first-glance opinions on different
    bits of code.

    What's your initial opinion of this 500-line example:

    https://github.com/sal55/langs/blob/master/lisp.c

    Here's one of the functions from it:

    lval rest(lval *h, lval *g) { lval *f = h-1; lval r = 0; for (; f>=g;
    f--)
    r = cons(h, *f, r); return r; }

    Here's what my visualisation tool produces:

    global function rest(ref i32 h, g)i64 =
    ref i32 f
    i32 r

    f := h-1
    r := 0
    while f >= g do
    r := cons(h,f^,r)
    f--
    od
    return r
    end

    Yes, you might apply a C formatter too, and keep it in C, it won't fix
    that for-loop though.


      But to form a solid, justifiable opinion I would want to
    see a lot more of the code in question.


    Suppose this is a class of program which you have extensive experience
    of writing, but you see extra layers of complications that you'd never
    needed in yours, and the other program doesn't work any better either.

    In fact it is poorer, and looks worse.

    Would you still be as tolerant?

    but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    There WILL be a cap.

    No.

    OK. I haven't been able to find a limit for nested, non-recursive
    macros. And I don't know how to set up a test for recursive macros (I'm
    not even sure they exist in C).

    (I can do that my language, and that needs a cap since there are no
    conditional elements that would stop recursion. So this fails:

    macro M = M + 1

    But the same in C works, sort of, in that the second M here:

    #define M M + 1

    is not expanded.)


    Very few things in this world are black-or-white.

    Some deep nesting might be justified in special cases, for example
    some recursive macro that builds a string a character at a time.

    But this was not such a case; it was simply decided to make it work
    using macros instead of functions.

    How do you know that?

    By the 500 such macro definitions, and the EXTENSIVE use of such macro invocations instead of functions, in a class of application I'm very
    familiar with.



    As for being crippling: I've written all sorts of language apps,
    including interpreters like this, without ever using more than one
    level, and for several decades, zero levels.


    And how do you know that is a good choice, or would be better in this case?

    Near 40 years' experience of implementing interpreters? On some very resource-limited systems too. Ones that have always run rings around
    other products, until more recently when people are trying harder.

    But those efforts are now centred on JIT-based products. This Lua
    product however is not JIT-based. (There is a separate LuaJIT project.)

    (My latest interpreter does use macros. But there are only 25 across the project, which is for a bigger and richer language than Lua, and for an interpreter that runs faster. None of those are nested.

    That product can be transpiled to C, and then it uses 0 C macros.)


    A language like C provides all these odd-ball features, people are
    going to use them.

    Macros are hardly odd-ball.

    C ones are.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Wed Apr 23 18:52:34 2025
    On 23/04/2025 18:05, David Brown wrote:
    On 23/04/2025 00:02, Keith Thompson wrote:

    C23 does not have _Lengthof.  It's proposed for C2y.


    Sorry, yes.  The pdf I was viewing was the latest draft for post-C23
    rather than C23.  My mistake.


    Actually, my C compiler has 'lengthof'. I'd got rid of most experimental
    bits in the lastest version, but that got left in:

    #include <stdio.h>

    int main(void) {
    int A[100];

    printf("%zu\n", lengthof(A)); # shows 100
    }

    Looking at the sources, it is a sub-operator of 'sizeof' and its
    implementation took under 30 extra lines.

    It works for expressions and types, just like sizeof.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Wed Apr 23 18:43:33 2025
    On 2025-04-23, bart <bc@freeuk.com> wrote:
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary
    block of syntax:

    #define INDEX(a, b, y) a y b
    INDEX(a, i, [) ];

    While that's terrible, I've never seen anything like it in the wild.

    Macros which open a brace, relying on the invocation of a paired
    macro to close it, are reasonably common.

    The macro we had been discussing whereby the for (..) part of
    a loop is also an example of something which generates a syntactic
    fragment, which must be completed by something which follows
    the macro, namely a statement.

    Speaking purely in terms of formal syntqx, this is exactly what is going
    on in your example with the completing closing bracket. In that
    situation, it gives us a useful technique whose use is clear.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Wed Apr 23 21:49:03 2025
    On 23/04/2025 19:43, Kaz Kylheku wrote:
    On 2025-04-23, bart <bc@freeuk.com> wrote:
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in
    their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary
    block of syntax:

    #define INDEX(a, b, y) a y b
    INDEX(a, i, [) ];

    While that's terrible, I've never seen anything like it in the wild.

    Macros which open a brace, relying on the invocation of a paired
    macro to close it, are reasonably common.

    So you /have/ seen things like that. There are entire libraries built
    solely with the C processor, some even implement languages; they will
    use every trick they can.

    My example was only for illustrating my claim that macros work with
    blobs of syntax, that may be malformed and unbalanced.

    They can also work at the sub-token level:

    #define O(x) 0##x

    printf("%d\n", 100); # 100
    printf("%d\n", O(100)); # 64



    The macro we had been discussing whereby the for (..) part of
    a loop is also an example of something which generates a syntactic
    fragment, which must be completed by something which follows
    the macro, namely a statement.

    Speaking purely in terms of formal syntqx, this is exactly what is going
    on in your example with the completing closing bracket. In that
    situation, it gives us a useful technique whose use is clear.

    Such libraries as I mentioned for embedded languages or syntax wrapping
    are clever, but usually impractical, unwieldy and inefficient.

    If you want a new language, do it properly! Or use a more appropriate
    base language.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Thu Apr 24 07:40:52 2025
    On Wed, 23 Apr 2025 18:43:33 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wibbled:
    On 2025-04-23, bart <bc@freeuk.com> wrote:
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in
    their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary
    block of syntax:

    #define INDEX(a, b, y) a y b
    INDEX(a, i, [) ];

    While that's terrible, I've never seen anything like it in the wild.

    He loves coming up with unrealistic code examples that no decent programmer would ever write then points and says look how bad macros must be. Using that approach you can easily come up with highly contorted code that no one can read as the Obfuscated C contest proves.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Thu Apr 24 07:41:25 2025
    On Wed, 23 Apr 2025 17:39:18 +0100
    bart <bc@freeuk.com> wibbled:
    On 23/04/2025 17:00, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 14:50:22 +0100
    bart <bc@freeuk.com>:
    On 23/04/2025 11:58, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 11:15:01 +0100
    bart <bc@freeuk.com>:

    * Their implementation is complex and poorly defined.

    Maybe to you.

    Have you ever implemented a C preprocessor?

    No, have you?

    Yes.

    Well thats nice. No doubt no one has ever seen it except you.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Muttley@DastardlyHQ.org on Thu Apr 24 09:31:21 2025
    On 24/04/2025 08:41, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 17:39:18 +0100
    bart <bc@freeuk.com> wibbled:
    On 23/04/2025 17:00, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 14:50:22 +0100
    bart <bc@freeuk.com>:
    On 23/04/2025 11:58, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 11:15:01 +0100
    bart <bc@freeuk.com>:

    * Their implementation is complex and poorly defined.

    Maybe to you.

    Have you ever implemented a C preprocessor?

    No, have you?

    Yes.

    Well thats nice.


    Oh, thank you, you're so kind.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Muttley@DastardlyHQ.org on Thu Apr 24 09:26:23 2025
    On 24/04/2025 08:40, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 18:43:33 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wibbled:
    On 2025-04-23, bart <bc@freeuk.com> wrote:
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in >>> their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary
    block of syntax:

    #define INDEX(a, b, y) a y b
    INDEX(a, i, [) ];

    While that's terrible, I've never seen anything like it in the wild.

    He loves coming up with unrealistic code examples that no decent programmer would ever write then points and says look how bad macros must be. Using that approach you can easily come up with highly contorted code that no one can read
    as the Obfuscated C contest proves.


    And you do like totally ignoring the context. This was an example of how
    macros work compared with how functions work.

    Functions return a value of some type; macros yield a bunch of lexical
    tokens.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Thu Apr 24 10:52:35 2025
    On Thu, 24 Apr 2025 09:26:23 +0100
    bart <bc@freeuk.com> wibbled:
    On 24/04/2025 08:40, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 18:43:33 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wibbled:
    On 2025-04-23, bart <bc@freeuk.com> wrote:
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in >>>> their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary >>>> block of syntax:

    #define INDEX(a, b, y) a y b
    INDEX(a, i, [) ];

    While that's terrible, I've never seen anything like it in the wild.

    He loves coming up with unrealistic code examples that no decent programmer >> would ever write then points and says look how bad macros must be. Using that

    approach you can easily come up with highly contorted code that no one can >read
    as the Obfuscated C contest proves.


    And you do like totally ignoring the context. This was an example of how >macros work compared with how functions work.

    You think anyone in this group needed to be told? Macros arn't supposed to
    work the same way as functions or there'd be no point having them!

    Functions return a value of some type;

    Not always. Heard of void?

    macros yield a bunch of lexical
    tokens.

    Not always. Eg if used in #ifdef.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Muttley@DastardlyHQ.org on Thu Apr 24 12:44:48 2025
    On 24/04/2025 11:52, Muttley@DastardlyHQ.org wrote:
    On Thu, 24 Apr 2025 09:26:23 +0100
    bart <bc@freeuk.com> wibbled:
    On 24/04/2025 08:40, Muttley@DastardlyHQ.org wrote:
    On Wed, 23 Apr 2025 18:43:33 -0000 (UTC)
    Kaz Kylheku <643-408-1753@kylheku.com> wibbled:
    On 2025-04-23, bart <bc@freeuk.com> wrote:
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in >>>>> their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary >>>>> block of syntax:

    #define INDEX(a, b, y) a y b
    INDEX(a, i, [) ];

    While that's terrible, I've never seen anything like it in the wild.

    He loves coming up with unrealistic code examples that no decent programmer >>> would ever write then points and says look how bad macros must be. Using that

    approach you can easily come up with highly contorted code that no one can >> read
    as the Obfuscated C contest proves.


    And you do like totally ignoring the context. This was an example of how
    macros work compared with how functions work.

    You think anyone in this group needed to be told? Macros arn't supposed to work the same way as functions or there'd be no point having them!

    I was replying to this which implies the opposite:

    DB:
    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    MD:
    Not always. Heard of void?

    I /knew/ you seize upon that! Then I might also say: "You think anyone
    in this group needed to be told?".

    FWIW, in my language, and a few others, 'functions' ALWAYS return values.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Thu Apr 24 15:12:50 2025
    On 23/04/2025 22:49, bart wrote:
    On 23/04/2025 19:43, Kaz Kylheku wrote:
    On 2025-04-23, bart <bc@freeuk.com> wrote:
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in >>> their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary
    block of syntax:

          #define INDEX(a, b, y) a y b
          INDEX(a, i, [) ];

    While that's terrible, I've never seen anything like it in the wild.

    Macros which open a brace, relying on the invocation of a paired
    macro to close it, are reasonably common.

    So you /have/ seen things like that.

    He said he had /not/ seen things like your example. Your example is
    very different from what he described.

    Your example is unbalanced - most real-world macros which are not "brace complete" come in matched pairs. And passing an arbitrary token such as
    "[" as a macro parameter is extremely unusual.


    As an example of macros with more complex structure, look at the
    "protothreads" library: <https://dunkels.com/adam/pt/>



    #include "pt.h"

    struct pt pt;
    struct timer timer;

    PT_THREAD(example(struct pt *pt))
    {
    PT_BEGIN(pt);

    while(1) {
    if(initiate_io()) {
    timer_start(&timer);
    PT_WAIT_UNTIL(pt,
    io_completed() ||
    timer_expired(&timer));
    read_data();
    }
    }
    PT_END(pt);
    }



    The PT_BEGIN and PT_END macros each have unbalanced braces, but they
    balance when used correctly in pairs as shown above :

    #define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)

    #define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
    PT_INIT(pt); return PT_ENDED; }



    There are entire libraries built
    solely with the C processor, some even implement languages; they will
    use every trick they can.

    Would you think it was better if they were bigger, slower, or less
    functional because they did /not/ use every trick?

    You seem to have this bizarre paranoia about macros, as though they are
    only used specifically to cause you personal grief. In reality, there
    are perhaps three main good reasons macros are used in C coding :

    1. When they are the best, or perhaps only, way to achieve the goal for
    the code.

    2. When they make code clearer, neater and more maintainable.

    3. When the code is written for older C standards or older or weaker
    compilers and can't make use of safer alternatives (such as inline
    functions, static const's, constexpr values, etc.)

    They are also often used by programmer habit when they are not
    necessary, but that is rarely harmful (such as using #define'd constants
    when an enum constant might be considered better).


    So if someone builds an entire library from macros, it is because macros
    are the best or only way to build a library with that kind of
    functionality. Protothreads is a fine example of this. That is a
    /good/ thing, not a bad thing.


    My example was only for illustrating my claim that macros work with
    blobs of syntax, that may be malformed and unbalanced.

    They can also work at the sub-token level:

        #define O(x) 0##x

        printf("%d\n", 100);             # 100
        printf("%d\n", O(100));          #  64


    Why do you think this is a bad thing? This is one of the points of C
    macros - they are text substitution macros, precisely so that you can do
    things like that.



    The macro we had been discussing whereby the for (..) part of
    a loop is also an example of something which generates a syntactic
    fragment, which must be completed by something which follows
    the macro, namely a statement.

    Speaking purely in terms of formal syntqx, this is exactly what is going
    on in your example with the completing closing bracket. In that
    situation, it gives us a useful technique whose use is clear.

    Such libraries as I mentioned for embedded languages or syntax wrapping
    are clever, but usually impractical, unwieldy and inefficient.

    And as usual, I question your basis for making such wild general claims.


    If you want a new language, do it properly!

    Let's compare alternatives here. If I want to make a little bit of
    embedded language, with C macros I have :

    + The implementation is in a language I already know
    + I can probably implement it in a few hundred lines of code
    + It will work with any C compiler, any target, and any C code
    + It mixes freely with other C code
    - Debugging it can be a bit of a pain
    - Complicated things can get a bit ugly with macro tricks
    - C macros are not Turing complete (no loops, recursion, etc.)

    Doing it "properly" means :

    + The language can support anything I want it to
    - I have to design a whole language
    - I have to document a whole language
    - I have to implement a whole language and all the tools
    - It only works for the targets I bother supporting
    - No one else can use it without all the tools
    - It has to be a complete language on its own
    - Integration with other code is a PITA at best
    - The implementation in C probably uses lots of macros...

    The suggestion that making your own language and tools instead of a
    macro library is clearly absurd.

    Or use a more appropriate
    base language.

    That is sometimes a much better option. In particular, moving to C++
    rather than C gives you templates and compile-time execution that
    greatly reduce the need for macros, and provide a safer solution that is
    more flexible in many ways (but less flexible in others).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Thu Apr 24 14:25:38 2025
    On 23/04/2025 19:43, bart wrote:
    On 23/04/2025 16:31, David Brown wrote:
    On 22/04/2025 22:03, bart wrote:

    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    There is a great deal of difference. Functions tend to be well-formed in their inputs and outputs.

    Macros take some abitrary blocks of syntax and return another arbitrary
    block of syntax:

        #define INDEX(a, b, y) a y b
        INDEX(a, i, [) ];


    I know perfectly well that there are differences between what you can do
    with macros in C, and what you can do with functions.

    In terms of dividing up code into manageable parts that fit together as
    a whole - and in doing so too much or too little - there is no
    conceptual difference between macros and functions.


    I did ask at one point whether anybody could link to some truly
    terrible C code; nobody has so far.

    There are probably two reasons for that.  One is that everyone, except
    perhaps you, understands that this is very subjective.  I've seen
    plenty of code posted in this group, written by regulars whose
    programming skill and knowledge I highly respect, and yet which I
    would classify as "truly terrible" and reject it immediately if it
    were presented to me for code review in my work.  The other reason is
    that nobody else is particularly interested in seeing bad code, or
    going out of their way to look for it.


    I just want to find out the threshold at which some will actually
    agree that macros have been abused or their use is over the top and
    unjustified.


    Why?

    We are all going to have different first-glance opinions on different
    bits of code.

    What's your initial opinion of this 500-line example:

      https://github.com/sal55/langs/blob/master/lisp.c

    You missed the bit where I said I am not interested in examining bad
    code. Nor am I interested in Lisp, so I have no interest in looking at
    that.


    Here's one of the functions from it:

      lval rest(lval *h, lval *g) { lval *f = h-1; lval r = 0; for (; f>=g; f--)
        r = cons(h, *f, r); return r; }


    Presumably that makes sense to the people who wrote the code. But it
    makes no sense to me. That is /not/ because of some syntax or
    formatting issue, or the missing clause in the "for" loop - it is
    because I don't know the types, the functions (or macros) used, the
    purpose of this function, the way memory and resource management is
    handled in this code, the meaning of the single-letter identifiers, or
    anything else about it.

    How the code is formatted is a drop in the ocean in the effort needed to understand the code, what it does, and where it fits with everything
    else in the code base.

    Here's what my visualisation tool produces:

        global function rest(ref i32 h, g)i64 =
            ref i32 f
            i32 r

            f := h-1
            r := 0
            while f >= g do
                r := cons(h,f^,r)
                f--
            od
            return r
        end

    Yes, you might apply a C formatter too, and keep it in C, it won't fix
    that for-loop though.


    The for-loop is basically irrelevant for understanding the code.

    I fully agree that your "visualisation" here - or a re-factoring in C to
    use a "while" loop rather than a "for" loop - makes the code easier to
    read and makes it more obvious what the mechanics of the function are.
    And if I were writing the same function myself, I'd use a while loop
    rather than a for loop. So don't misunderstand me here - I am not a fan
    of the way that function is written. But I can't judge the format
    without a lot more context, and such judgement would be highly
    subjective. And the formatting is a very minor aspect of understanding
    the code.



      But to form a solid, justifiable opinion I would want to see a lot
    more of the code in question.


    Suppose this is a class of program which you have extensive experience
    of writing, but you see extra layers of complications that you'd never
    needed in yours, and the other program doesn't work any better either.

    In fact it is poorer, and looks worse.

    Would you still be as tolerant?

    You want me to suppose that I know for sure that the code is more
    complex than it needs to be, and then you are asking me if I'll say it
    is more complex than it needs to be? Yes, under those circumstances I'd
    say it was more complex than it needs to be.

    Would I be tolerant of it? That depends on why it is so complex, what
    the consequences of that complexity are, and the consequences of
    refactoring it to reduce the complexity. For single-use code that is
    unlikely to ever need to be changed or fixed, and which results in
    object code that is efficient enough for the task, it is not going to be
    worth the effort or risk to change. If the code is expected to be
    maintained over a long time period, re-used in other projects, or if
    many people need to understand it, then the balance could be very different.


    Your questions here are like presenting someone with a picture and
    asking if it is good or not, without saying whether it was made by your six-year-old grandkid or hanging in an art gallery.


    but you're not considering how
    bizarre and crippling restriction it would be to put a cap on it.

    There WILL be a cap.

    No.

    OK. I haven't been able to find a limit for nested, non-recursive
    macros. And I don't know how to set up a test for recursive macros (I'm
    not even sure they exist in C).


    I'd expect most experienced C programmers to be able to answer that.
    I'd certainly expect anyone who claimed to have implemented a C
    preprocessor to be able to answer it. No, C does not have recursive
    macros (or any other kind of pre-processing loop), which is a
    significant limitation for some uses.

    There are some limits for aspects of C given in the "translation limits" section of the standards, such as 4095 macro identifiers in a
    translation unit, which are minimum limits for conforming compilers. In practice, pretty much all C compilers have no caps or limits on these
    things other than the memory (or other limits) of the host computer.

    If a language or tool supports recursion or loops during translation,
    then I agree a cap of some sort is a good idea. Alternatively there
    could be other detection of infinite loops, or a timeout. In C
    preprocessing, you can have recursion if a file includes itself
    (directly or indirectly), so a limit on file inclusion nesting makes
    sense. (For reference, gcc has 200 by default, but it is changeable by
    a command-line flag. The C standard requires a minimum of 15 levels.)


    (I can do that my language, and that needs a cap since there are no conditional elements that would stop recursion. So this fails:

       macro M = M + 1

    But the same in C works, sort of, in that the second M here:

       #define M M + 1

    is not expanded.)


    Very few things in this world are black-or-white.

    Some deep nesting might be justified in special cases, for example
    some recursive macro that builds a string a character at a time.

    But this was not such a case; it was simply decided to make it work
    using macros instead of functions.

    How do you know that?

    By the 500 such macro definitions, and the EXTENSIVE use of such macro invocations instead of functions, in a class of application I'm very
    familiar with.


    So you don't know. You guessed.

    You don't have any idea /why/ the developers choose to use macros like
    this - you simply assume that because you have written an interpreter
    with little use of macros, anyone else using macros for an interpreter
    (no matter how similar or different) must be doing something wrong.

    (Again, I have no idea whether or not these macros are a good idea in
    the Lua source code - I am merely saying that your opinion here is
    highly subjective and is not based on any kind of objective rationale or
    full knowledge of the situation.)



    As for being crippling: I've written all sorts of language apps,
    including interpreters like this, without ever using more than one
    level, and for several decades, zero levels.


    And how do you know that is a good choice, or would be better in this
    case?

    Near 40 years' experience of implementing interpreters? On some very resource-limited systems too. Ones that have always run rings around
    other products, until more recently when people are trying harder.

    I know you have written interpreters for your own languages. I know you
    say they are fantastic and better than anything else in existence -
    since no one else has ever used them, we have only your word for that,
    but I'll assume it is true.

    You /know/ I know that.

    And yet I still asked you how you thought you were in a position to
    judge the way the Lua developers implemented Lua in such a categorical
    manner.

    What your experience tells you is that is that it is /possible/ to
    implement a little virtual machine for a simple language without using C macros. It tells you nothing about whether or not it is a good idea,
    because you have not tried it out for comparison. It tells you nothing
    about how best to implement Lua in C, because that is a very different
    language from your languages. It tells you nothing about the best
    structure for a core project written by multiple people, with extensions written by hundreds or thousands of people, and with many orders of
    magnitude more end users - because you just have a one-person language.

    And to cap it all, you (AFAIUI) don't even use C to implement any of
    this stuff - you use your own languages. (Those may well be a better
    choice than C for implementing virtual machines.)


    The way you could /know/ the best way to implement a Lua virtual machine
    in C would be to investigate if the Lua developers, or any other groups,
    have tried to implement the Lua VM in different ways and seen how well
    they work. Or you could find books or articles that discuss different
    ways of implementing VMs.

    There are perhaps a half-dozen basic ways of implementing language
    virtual machines. There are a very large number of interpreted or
    byte-coded languages. You have experience of implementing a couple of
    simple languages, for personal use, using either a strangely restricted
    subset of C or one of your own languages. Your experience tells you
    about your own experience - it tells you nothing about anyone else's experiences.



    But those efforts are now centred on JIT-based products. This Lua
    product however is not JIT-based. (There is a separate LuaJIT project.)

    (My latest interpreter does use macros. But there are only 25 across the project, which is for a bigger and richer language than Lua, and for an interpreter that runs faster. None of those are nested.

    That product can be transpiled to C, and then it uses 0 C macros.)


    A language like C provides all these odd-ball features, people are
    going to use them.

    Macros are hardly odd-ball.

    C ones are.



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Thu Apr 24 14:51:12 2025
    On 24/04/2025 13:25, David Brown wrote:
    On 23/04/2025 19:43, bart wrote:

    By the 500 such macro definitions, and the EXTENSIVE use of such macro
    invocations instead of functions, in a class of application I'm very
    familiar with.


    So you don't know.  You guessed.

    Why are you automatically sticking up for THEM and not ME?

    What qualifications and what experience would somebody need for David
    Brown to give credence to their opinion?

    I'm sure there are lots projects you can look at and know straight off
    that its uses of macros or whatever is over the top.

    Suppose you reported that here, but I suggested that you don't know
    that; you're only guessing?


    You don't have any idea /why/ the developers choose to use macros like
    this - you simply assume that because you have written an interpreter
    with little use of macros,

    I've written a million lines of code with little use of macros.

    They are prevalent in C simply because the language has them and people
    will use them. Even if you ignore the ones that only exist people
    because don't like to use enums for named constants.


    What your experience tells you is that is that it is /possible/ to
    implement a little virtual machine for a simple language without using C macros.

    It tells you nothing about whether or not it is a good idea,
    because you have not tried it out for comparison.  It tells you nothing about how best to implement Lua in C, because that is a very different language from your languages.

    The example I gave was from ADD; my language has ADD too! Except that
    Lua's ADD works between Ints and Floats (Floats only before 5.1?); mine
    works between Ints, Floats, Strings, Bignums and Sets.

    So, how different is it really?

      It tells you nothing about the best
    structure for a core project written by multiple people, with extensions written by hundreds or thousands of people, and with many orders of
    magnitude more end users - because you just have a one-person language.

    You forgot the bit where I said I've been doing this since the 1980s, on
    a few languages of my own, both dynamic and statically typed. And I've
    looked at lots of others including their implementations.

    I've also got my C compiler to build and run some of those (Lua and
    Seed7 among them).

    I even created a C interpreter.

    I've experimented with half a dozen kinds of bytecode dispatcher, and
    several methods of type dispatching, and tried out AST tree-walkers.

    Some of my interpreters were embedded, and run within commercial
    products, and used by other people to create their own add-on programs.

    And to cap it all, you (AFAIUI) don't even use C to implement any of
    this stuff - you use your own languages.  (Those may well be a better
    choice than C for implementing virtual machines.)

    I did try C at one point. That didn't use macros either.

    The way you could /know/ the best way to implement a Lua virtual machine
    in C would be to investigate if the Lua developers, or any other groups,
    have tried to implement the Lua VM in different ways and seen how well
    they work.  Or you could find books or articles that discuss different
    ways of implementing VMs.

    Maybe /I/ should write a book or article instead!


    There are perhaps a half-dozen basic ways of implementing language
    virtual machines.  There are a very large number of interpreted or byte- coded languages.  You have experience of implementing a couple of simple languages, for personal use, using either a strangely restricted subset
    of C or one of your own languages.

    How many interpreters do you think the developers of Lua have worked on?
    (And how many of those developers also devised and programmed its
    implemenation language?)

    You describe my languages as 'simple'; how much more complex do you
    think Lua is?

    I find it disappointing that you don't want to acknowledge that I might
    know something of this field, that I have extensive experience of it,
    and that my opinions might be valid.

    More so that you seem to know little about Lua, but decide to give them
    the benefit of a doubt anyway.

    /Maybe/ they had good reasons for using so many macros, but /maybe/ so
    do I for having so few!

    So why are you automatically assuming they must be right, and I must be
    wrong?

    As it happens, my main scripting language is bigger and richer than Lua.
    And yet, my implementation is somewhat smaller, and most programs run
    faster. It's a paradox.

    Here:

    c:\cx>bcc -i lua hello.lua
    Compiling lua.c to lua.(int)
    Hello from Lua

    This is my C interpreter, interpreting lua.c (a one-file version), which
    then runs hello.c.

    Further, this is part of a survey of interpreters running a recursive
    Fibonacci benchmark:

    Lang Implem Type Category Millions of Calls/second

    Bash Bash ? Int 0.0014
    C Pico C S Int 0.7
    Seed7 s7 S Int 3.5
    Algol68 A68G S Int 5
    Python CPython 3.14 D Int 11
    Lox Clox D Int 17
    Lua Lua 5.4 D Int 22
    Q DD D Int 73

    PyPy PyPy 7.3.19 D JIT 128
    JavaScript NodeJS D JIT 250 (See Note 2)

    My product is Q/DD. It has the best performance of the pure
    interpreters; beyond that you need to employ JIT techniques.

    The 'Note 2' mentioned is to do with NodeJS having a 0.5 second startup
    latency which had to be compensated for.

    So I know fuck-all about writing interpreters, they are all toys, my
    languages are toys, and my opinion counts for nothing?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Thu Apr 24 14:31:54 2025
    On Thu, 24 Apr 2025 12:44:48 +0100
    bart <bc@freeuk.com> wibbled:
    On 24/04/2025 11:52, Muttley@DastardlyHQ.org wrote:
    You think anyone in this group needed to be told? Macros arn't supposed to >> work the same way as functions or there'd be no point having them!

    I was replying to this which implies the opposite:

    DB:
    Too few levels of functions and/or macros (there is no semantic
    difference between macros and functions in this matter)

    Depends on the "matter".

    MD:
    Not always. Heard of void?

    I /knew/ you seize upon that! Then I might also say: "You think anyone
    in this group needed to be told?".

    FWIW, in my language, and a few others, 'functions' ALWAYS return values.

    C functions are not pure functions, they're procedures that can return values.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Thu Apr 24 15:28:57 2025
    On 24/04/2025 14:12, David Brown wrote:
    On 23/04/2025 22:49, bart wrote:

    Such libraries as I mentioned for embedded languages or syntax
    wrapping are clever, but usually impractical, unwieldy and inefficient.

    And as usual, I question your basis for making such wild general claims.


    If you want a new language, do it properly!

    Let's compare alternatives here.  If I want to make a little bit of
    embedded language, with C macros I have :

        + The implementation is in a language I already know

    No. It is in the C preprocessor language. It is quite different from C
    and requires special skills.

    (But if someone is up to it, perhaps they can write 'make' in it!)

        + I can probably implement it in a few hundred lines of code

    One Brainfuck interpreter I looked at (not sure if one of those at the
    link below), involved 5000 lines of header code. But they can usually be directly implemented in any normal language in about 50 lines.

        + It will work with any C compiler, any target, and any C code

    Some will need a particular compiler or version because they rely on
    some very specific behaviour.

        + It mixes freely with other C code

    Not necessarily. Look at the 'datatype99' link here for example:

    https://github.com/hirrolot/awesome-c-preprocessor

    That provides a new syntax for type definitions. While it can co-exist
    with normal C code, it will be poorly matched.

    It will also be incredibly confusing for someone looking at a source
    file with a .c extension.

        - Debugging it can be a bit of a pain
        - Complicated things can get a bit ugly with macro tricks
        - C macros are not Turing complete (no loops, recursion, etc.)

    Doing it "properly" means :

        + The language can support anything I want it to
        - I have to design a whole language
        - I have to document a whole language

    You will need docs anyway.

        - I have to implement a whole language and all the tools
        - It only works for the targets I bother supporting
        - No one else can use it without all the tools
        - It has to be a complete language on its own
        - Integration with other code is a PITA at best

    That is going to be a problem anyway if you have this mysterious-looking
    syntax in the middle of a C file.

        - The implementation in C probably uses lots of macros...

    The suggestion that making your own language and tools instead of a
    macro library is clearly absurd.

    Who said devising a language was easy? But a CPP-based one will be poor.
    Here's a comment from the Ferdi265/BF interpreter at that link:

    "The preprocessor brainfuck interpreter is very very inefficient and
    will use around 16 GIGABYTES of memory and 15 to 20 minutes of
    processing time while running hello.bf."

    If all you're thinking of is a library of functions and macros, then
    fine, but that is not exactly a language.


    Or use a more appropriate base language.

    That is sometimes a much better option.

    While not my thing, I was thinking of something like Racket.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to bart on Thu Apr 24 15:32:51 2025
    bart <bc@freeuk.com> writes:
    On 24/04/2025 13:25, David Brown wrote:
    On 23/04/2025 19:43, bart wrote:

    By the 500 such macro definitions, and the EXTENSIVE use of such macro
    invocations instead of functions, in a class of application I'm very
    familiar with.


    So you don't know.  You guessed.

    Why are you automatically sticking up for THEM and not ME?

    Wow! How self-centered can you get?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Thu Apr 24 17:21:33 2025
    On 24/04/2025 16:28, bart wrote:
    On 24/04/2025 14:12, David Brown wrote:
    On 23/04/2025 22:49, bart wrote:

    Such libraries as I mentioned for embedded languages or syntax
    wrapping are clever, but usually impractical, unwieldy and inefficient.

    And as usual, I question your basis for making such wild general claims.


    If you want a new language, do it properly!

    Let's compare alternatives here.  If I want to make a little bit of
    embedded language, with C macros I have :

         + The implementation is in a language I already know

    No. It is in the C preprocessor language. It is quite different from C
    and requires special skills.

    Sometimes you talk a lot of bollocks.

    The C preprocessor directives are part of C, are described in the C
    standards, and are covered by all C tutorial books, courses, and similar material. They take about 20 pages of the C standard of 700 pages (C11)
    - it is not hard to get the hang of typical use of macros in C.

    They do not form a "language". You get text-based macro substitution
    (without the possibility of recursion), conditional compilation, file inclusion, and error directives. They are integral to C, and usually
    integral to C compilers.

    Yes, there are some things that can be a bit fiddly - sometimes you need
    to have an extra layer of macro expansion for complicated things. Most
    people don't need to do that sort of code, and if they do, you can
    figure it out with a bit of trial and error and some googling.


    (But if someone is up to it, perhaps they can write 'make' in it!)


    The C preprocessor directives are not a programming language.

         + I can probably implement it in a few hundred lines of code

    One Brainfuck interpreter I looked at (not sure if one of those at the
    link below), involved 5000 lines of header code. But they can usually be directly implemented in any normal language in about 50 lines.


    I can't figure out what you are trying to say here. But it's probably
    not worth going into detail.

         + It will work with any C compiler, any target, and any C code

    Some will need a particular compiler or version because they rely on
    some very specific behaviour.

    There is almost nothing compiler-specific about pre-processor
    directives. I only know of two very minor extensions that gcc supports,
    for marginally nicer variadic macro support. Of course the result of
    the macro expansion might be compiler-specific, just like any other C
    code you write without macros.


         + It mixes freely with other C code

    Not necessarily. Look at the 'datatype99' link here for example:

      https://github.com/hirrolot/awesome-c-preprocessor

    That provides a new syntax for type definitions. While it can co-exist
    with normal C code, it will be poorly matched.

    These are macros for defining some types and macros for accessing those
    types with extra compile-time checks. You can mix them freely with
    normal C code. You don't have to use the macros for accessing the data
    - it's your choice. And you can mix it all with other C code.


    It will also be incredibly confusing for someone looking at a source
    file with a .c extension.

    I am not personally a fan of things like these macro packages - I'd
    rather just use C++. But it's a matter of choice. Even if you could
    argue that packages like "datatype99" are objectively bad in some sense
    (and you can't argue that), it would only be an argument against that
    use of macros, not C macros themselves or other use of them.

    I also think writing identifiers and comments in Greek is incredibly
    confusing to someone who only reads English, but that does not mean
    Greek speakers should not be allowed to write code in Greek!


         - Debugging it can be a bit of a pain
         - Complicated things can get a bit ugly with macro tricks
         - C macros are not Turing complete (no loops, recursion, etc.)

    Doing it "properly" means :

         + The language can support anything I want it to
         - I have to design a whole language
         - I have to document a whole language

    You will need docs anyway.

    You need to document the use of the macros you write if you make macros
    - you need to document an entire language if you go that route.


         - I have to implement a whole language and all the tools
         - It only works for the targets I bother supporting
         - No one else can use it without all the tools
         - It has to be a complete language on its own
         - Integration with other code is a PITA at best

    That is going to be a problem anyway if you have this mysterious-looking syntax in the middle of a C file.


    No, it is not.

         - The implementation in C probably uses lots of macros...

    The suggestion that making your own language and tools instead of a
    macro library is clearly absurd.

    Who said devising a language was easy? But a CPP-based one will be poor.

    You suggested it would be a better idea than writing some C macros.

    Here's a comment from the Ferdi265/BF interpreter at that link:

    "The preprocessor brainfuck interpreter is very very inefficient and
    will use around 16 GIGABYTES of memory and 15 to 20 minutes of
    processing time while running hello.bf."


    You do realise that Brainfuck is an intentionally silly language, made
    only for the fun and challenge of it? And a C pre-processor
    implementation is also intentionally silly, for fun and the challenge?

    If your best argument against C macros is that someone wrote a Brainfuck interpreter with them and it is inefficient, then I think you should
    retire from the discussion.

    If all you're thinking of is a library of functions and macros, then
    fine, but that is not exactly a language.


    Or use a more appropriate base language.

    That is sometimes a much better option.

    While not my thing, I was thinking of something like Racket.



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to David Brown on Thu Apr 24 18:51:51 2025
    On 24.04.2025 14:25, David Brown wrote:
    On 23/04/2025 19:43, bart wrote:
    On 23/04/2025 16:31, David Brown wrote:
    [...]

    We are all going to have different first-glance opinions on different
    bits of code.

    What's your initial opinion of this 500-line example:
    [...]

    You missed the bit where I said I am not interested in examining bad
    code. Nor am I interested in Lisp, so I have no interest in looking at
    that.

    Right. (I see that bart still does this stupid argument trick.)

    Here's one of the functions from it:

    But I spent a *few seconds* to simply _reformat_ that code (in my
    brain[*]) and it seems quite obvious!

    [*] Below you find the brain dump codified for the post...


    lval rest(lval *h, lval *g) { lval *f = h-1; lval r = 0; for (;
    =g; f--)
    r = cons(h, *f, r); return r; }

    lval rest (lval *h, lval *g)
    {
    lval r = 0;
    for (lval *f = h-1; f>=g; f--)
    r = cons(h, *f, r);
    return r;
    }

    I just swapped the two [independent] assignments (r and f) so I got
    the "complete" 'for' loop which is even of the simple type (the one
    that also bart may understand), with just one running parameter 'f'.

    They're obviously constructing in 'r' the return value by iterating
    from the right to left. (The functional effect of course depends on
    cons() that is undocumented here, but r=cons(..., r) is exposing.)


    Presumably that makes sense to the people who wrote the code. But it
    makes no sense to me.

    (It's obviously much simpler than it was in its unformatted state.)

    That is /not/ because of some syntax or
    formatting issue, or the missing clause in the "for" loop - it is
    because I don't know the types, the functions (or macros) used, the
    purpose of this function, the way memory and resource management is
    handled in this code, the meaning of the single-letter identifiers, or anything else about it.

    And of course you're right.


    How the code is formatted is a drop in the ocean in the effort needed to understand the code, what it does, and where it fits with everything
    else in the code base.

    Here's what my visualisation tool produces:

    global function rest(ref i32 h, g)i64 =
    ref i32 f
    i32 r

    f := h-1
    r := 0
    while f >= g do
    r := cons(h,f^,r)
    f--
    od
    return r
    end

    In my book this non-abstracted form is harder to understand than the
    simple reformatted 'for' loop version. (and if we'd replace the 'while'
    by a 'goto' based construct it would get yet more harder to identify
    the semantic building blocks. (But it's pointless to discuss that with
    you, bart; given your arguments yet I'm sure you don't grok that.)

    Yes, you might apply a C formatter too, and keep it in C, it won't fix
    that for-loop though.

    Yes, the 'for' loop wasn't sensibly used for that algorithm. But it
    was trivial to fix that. (And it's no argument against 'for', just an
    argument against bad programmers and badly written code, as David also
    said.)


    The for-loop is basically irrelevant for understanding the code.

    I fully agree that your "visualisation" here - or a re-factoring in C to
    use a "while" loop rather than a "for" loop - makes the code easier to
    read and makes it more obvious what the mechanics of the function are.

    The (low-level) [imperative] _mechanics_ wasn't the crucial thing here
    for understanding the code.

    And if I were writing the same function myself, I'd use a while loop
    rather than a for loop.

    I wouldn't, as I demonstrated.

    I'd guess you also wouldn't have used 'while' if you'd also have spent
    the 5-10 seconds (that I had spent) to "analyze" the code beforehand.

    So don't misunderstand me here - I am not a fan
    of the way that function is written. But I can't judge the format
    without a lot more context, and such judgement would be highly
    subjective. And the formatting is a very minor aspect of understanding
    the code.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Thu Apr 24 18:03:46 2025
    On Thu, 24 Apr 2025 18:49:00 +0100
    bart <bc@freeuk.com> wibbled:
    I'm trying to stand up for myself as I'M AT THE END OF MY FUCKING TETHER >HERE.

    ALL YOU PEOPLE WANT TO DO IS JUST TRASH EVERYTHING I'VE DONE.

    EVERY SINGLE THING I SAY IS WRONG. NOTHING I SAY IS EVER RIGHT. WHATEVER
    IT IS I SAY, YOU SAY THE OPPOSITE THING.

    MY SELF-ESTEEM HAS NEVER BEEN LOWER - YOU HAVE DESTROYED ME.

    AND WHEN I TRY QUESTION IT - THEN *YOU* ACCUSE ME OF BEING >SELF-CENTRED!!!!!!!

    FUCK YOU, CUNT.

    AND FUCKING TROLLS, ALL OF YOU.

    Oh dear, look at those poor toys being flung out of the pram at supersonic speed.

    Get a grip you snowflake twat, its just a sodding newsgroup.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Thu Apr 24 18:30:27 2025
    On 24/04/2025 16:21, David Brown wrote:
    On 24/04/2025 16:28, bart wrote:
    On 24/04/2025 14:12, David Brown wrote:
    On 23/04/2025 22:49, bart wrote:

    Such libraries as I mentioned for embedded languages or syntax
    wrapping are clever, but usually impractical, unwieldy and inefficient. >>>
    And as usual, I question your basis for making such wild general claims. >>>

    If you want a new language, do it properly!

    Let's compare alternatives here.  If I want to make a little bit of
    embedded language, with C macros I have :

         + The implementation is in a language I already know

    No. It is in the C preprocessor language. It is quite different from C
    and requires special skills.

    Sometimes you talk a lot of bollocks.

    Take a look at any ordinary C code of normal functions, statements etc.

    Then look at the kind of impenetrable macros that are needed to do
    ambitious things like emulate a new kind of syntax within a C file. That
    will be a long list of #defines.

    Can you honestly say that the person writing the former, and the one
    writing the latter, are coding in the same language?

    And can you honestly say that writing those complicated collections of
    macros requires no extra skill?

    If your answers are Yes then /you/ are the one talking bollocks.

    (Maybe you've forgotten that Preprocessing is a C compilation stage
    which performs a transformation from C with macro invocations, to pure C
    with those invocations expanded.

    To repeat, what I call a different language is the set of incantations
    that form the body of each #define. They do not exist in the pure C
    version.)

    Some will need a particular compiler or version because they rely on
    some very specific behaviour.

    There is almost nothing compiler-specific about pre-processor
    directives.  I only know of two very minor extensions that gcc supports,
    for marginally nicer variadic macro support.  Of course the result of
    the macro expansion might be compiler-specific, just like any other C
    code you write without macros.

    C compilers used to vary quite a bit in how macro expansions were done.
    Now there is less variance, maybe because they're sharing the one implementation that got it just right.

    It will also be incredibly confusing for someone looking at a source
    file with a .c extension.

    I am not personally a fan of things like these macro packages - I'd
    rather just use C++.  But it's a matter of choice.  Even if you could
    argue that packages like "datatype99" are objectively bad in some sense
    (and you can't argue that), it would only be an argument against that
    use of macros, not C macros themselves or other use of them.

    You're trying to avoid agreeing with me, that C files containing
    constructs that emulate different syntax or different language elements,
    are going to be confusing.

    Remember I claimed such things to be 'impractical, unwieldy and
    inefficient' -'usually'.

    If your best argument against C macros is that someone wrote a Brainfuck interpreter with them and it is inefficient, then I think you should
    retire from the discussion.

    You seem to advocating using C macros to make an embedded language,
    given that you say:

    "The suggestion that making your own language and tools instead of a
    macro library is clearly absurd."

    I gave an example of a tiny language needing 100 times as much source
    code to implement using C macros, as in a normal language, and another
    version of it that was hopelessy slow and inefficient.

    And that's for a language which is normally as simple to implement, if
    not use, as they come.

    So, do you have an actual example of an embedded language that is
    implemented more reasonably using macros?

    By embedded 'language' I don't mean a library of function or macro
    definitions that you just call or invoked, as happens in any C program.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Thu Apr 24 17:59:41 2025
    On Thu, 24 Apr 2025 18:30:27 +0100
    bart <bc@freeuk.com> wibbled:
    On 24/04/2025 16:21, David Brown wrote:
    Then look at the kind of impenetrable macros that are needed to do
    ambitious things like emulate a new kind of syntax within a C file. That

    s/ambitious/fucking stupid/g

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Scott Lurndal on Thu Apr 24 18:49:00 2025
    On 24/04/2025 16:32, Scott Lurndal wrote:
    bart <bc@freeuk.com> writes:
    On 24/04/2025 13:25, David Brown wrote:
    On 23/04/2025 19:43, bart wrote:

    By the 500 such macro definitions, and the EXTENSIVE use of such macro >>>> invocations instead of functions, in a class of application I'm very
    familiar with.


    So you don't know.  You guessed.

    Why are you automatically sticking up for THEM and not ME?

    Wow! How self-centered can you get?

    OK, you're OK with everybody in this group constantly bullying,
    disrespecting, belittling and insulting me?

    I gave an opinion about X, and people immediately disagreed with me
    despite not being familiar with that field. They gave it thje benefit of
    a doubt, and suggested there were good reasons for it being as it is.

    So I was calling it: I'm interested in why they did that.

    I'm trying to stand up for myself as I'M AT THE END OF MY FUCKING TETHER
    HERE.

    ALL YOU PEOPLE WANT TO DO IS JUST TRASH EVERYTHING I'VE DONE.

    EVERY SINGLE THING I SAY IS WRONG. NOTHING I SAY IS EVER RIGHT. WHATEVER
    IT IS I SAY, YOU SAY THE OPPOSITE THING.

    MY SELF-ESTEEM HAS NEVER BEEN LOWER - YOU HAVE DESTROYED ME.

    AND WHEN I TRY QUESTION IT - THEN *YOU* ACCUSE ME OF BEING
    SELF-CENTRED!!!!!!!

    FUCK YOU, CUNT.

    AND FUCKING TROLLS, ALL OF YOU.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to Janis Papanagnou on Thu Apr 24 22:35:48 2025
    On Fri, 18 Apr 2025 16:57:24 +0200, Janis Papanagnou wrote:
    On 16.04.2025 11:45, Rosario19 wrote:
    On Tue, 15 Apr 2025 09:25:40 +0200, Janis Papanagnou wrote:

    On 15.04.2025 06:57, Rosario19 wrote:
    On 13.04.2025 18:39, bart wrote:
    [...]

    for(let i = 1; i <= 36; i++) {

    C for loop is great, but all can be workarounded with goto label

    Sure. Or all done with Turing machines. - But why would one want to.

    because one not has the for loop, because is need more flexibility in
    what code has to make, because one find so easy goto label, that it is
    easier of the loop for, even if i think in 80% of cases for loop is
    less chars and easier of the loop that use goto label

    (Note my question above was rhetorical. - Turing machine programs is
    not something you should consider as scale for what we usually do in >programming.)

    Of course, if all you have is an assembler language then "all" you
    have are jumps.

    (Note: again an accentuated formulation of the point,
    but I'm confident you understand what I'm trying to say.)

    If, for common loop conditions, it's easier for someone to use gotos
    than to use typical loop constructs then I suggest that this person
    should not apply for a programmers' job.

    for loop is easy because propose always the same type of loop, the initialization, the condition, the increment etc all ok but sometimes
    one need to exit the loop before the main condition of exit, and go
    down or up in the code lines going out of that loop,
    for these cases it is better for me, not use forloop but the right
    if()s goto labels...

    The "number of characters" in a syntactical construct is IMO not the
    most relevant or primary factor. But abstractions in languages often

    coincide with much terser formulations. And abstractions is what aids
    in programming non-trivial systems. I would abstain from gotos, but
    because of the "number of characters" to type or to spare.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Fri Apr 25 02:56:44 2025
    On 2025-04-24, bart <bc@freeuk.com> wrote:
    NOTHING I SAY IS EVER RIGHT.

    Well, /that/ isn't; you're blindly discounting all the times
    someone has agreed with you.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to All on Fri Apr 25 07:46:21 2025
    On 24.04.2025 22:35, Rosario19 wrote:
    [ about gotos ]

    for loop is easy because propose always the same type of loop, the initialization, the condition, the increment etc

    I wouldn't call it "the same type of loop", given that you can
    formulate different types of loops (increments, shifts, other
    operations, etc.). I think the "same type of loop _structure_"
    might describe it better.

    all ok but sometimes
    one need to exit the loop before the main condition of exit,

    The comparably rare cases for early exits can (in "C") be done
    also with 'break' statements.

    Other methods are a reconsideration whether a structural change
    of the code would be more natural; we often see code evolving
    and it's IME not always clear from the beginning whether a
    'for' or a 'while' or a 'do-while' (or something else) is best.
    If we're _designing_ the code from scratch [before coding] (as
    opposed to "evolutionary" writing the code) the "right" control
    constructs usually appear even more naturally.

    But given that there's various ways of developing code (beyond
    just writing it up as one thinks, as opposed to a design with
    various top-down methods) that will lead to different results.

    and go down or up in the code lines going out of that loop,

    I think there was a discussion some time ago about languages
    (or a discussion about the "C" language evolution?) that allow
    to exit loops, and the various allowed ways; one was (AFAIR)
    to allow [for reasons presented there] only forward exits, for
    example.

    Especially if you have backward 'goto's it's IMO worth to have
    a second look on your iteration construct.

    for these cases it is better for me, not use forloop but the right
    if()s goto labels...

    I'll not (re-)open the can of a fundamental discussion on that.

    Use what suits you, and what fits in your [professional/private]
    coding environment.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to Janis Papanagnou on Fri Apr 25 10:29:12 2025
    On Fri, 25 Apr 2025 07:46:21 +0200, Janis Papanagnou wrote:

    Especially if you have backward 'goto's it's IMO worth to have
    a second look on your iteration construct.

    loops have always at last one backward 'goto'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Fri Apr 25 08:53:39 2025
    On Thu, 24 Apr 2025 18:26:16 -0700
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wibbled:
    bart <bc@freeuk.com> writes:
    [...]
    I'm trying to stand up for myself as I'M AT THE END OF MY FUCKING
    TETHER HERE.

    ALL YOU PEOPLE WANT TO DO IS JUST TRASH EVERYTHING I'VE DONE.

    EVERY SINGLE THING I SAY IS WRONG. NOTHING I SAY IS EVER
    RIGHT. WHATEVER IT IS I SAY, YOU SAY THE OPPOSITE THING.

    MY SELF-ESTEEM HAS NEVER BEEN LOWER - YOU HAVE DESTROYED ME.
    [...]

    Bart, if this is sincere, please consider stepping away from
    comp.lang.c for a while. I have no motivation for this post other
    than concern for your well-being.

    If its true and not just him grandstanding then he has bigger problems than having a meltdown on a newsgroup because people disagreed with him.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to Kaz Kylheku on Fri Apr 25 13:48:07 2025
    On Fri, 25 Apr 2025 02:56:44 -0000 (UTC), Kaz Kylheku wrote:

    On 2025-04-24, bart wrote:
    NOTHING I SAY IS EVER RIGHT.

    Well, /that/ isn't; you're blindly discounting all the times
    someone has agreed with you.

    here we are all wrong in something

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to All on Fri Apr 25 14:22:25 2025
    On 25.04.2025 10:29, Rosario19 wrote:
    On Fri, 25 Apr 2025 07:46:21 +0200, Janis Papanagnou wrote:

    Especially if you have backward 'goto's it's IMO worth to have
    a second look on your iteration construct.

    loops have always at last one backward 'goto'

    No.

    That's why loop _abstractions_ have been introduced in programming
    languages, to *not need* _low-level_ loop representations appear in
    high-level programming.

    (You seem to be arguing on assembler level on von Neumann machines,
    but that misses the point of a loop abstraction in loops constructs
    as you find them in form of for, while, repeat, until, etc. in the
    high-level languages. BTW, in your argumentation it would have been
    more precise to have said that there's at least one 'JMP' *and* at
    least one conditional jump, like 'JNZ', to implement loops on such
    a low machine model level.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Fri Apr 25 15:19:12 2025
    On 24/04/2025 19:30, bart wrote:
    On 24/04/2025 16:21, David Brown wrote:
    On 24/04/2025 16:28, bart wrote:
    On 24/04/2025 14:12, David Brown wrote:
    On 23/04/2025 22:49, bart wrote:

    Such libraries as I mentioned for embedded languages or syntax
    wrapping are clever, but usually impractical, unwieldy and
    inefficient.

    And as usual, I question your basis for making such wild general
    claims.


    If you want a new language, do it properly!

    Let's compare alternatives here.  If I want to make a little bit of
    embedded language, with C macros I have :

         + The implementation is in a language I already know

    No. It is in the C preprocessor language. It is quite different from
    C and requires special skills.

    Sometimes you talk a lot of bollocks.

    Take a look at any ordinary C code of normal functions, statements etc.

    Then look at the kind of impenetrable macros that are needed to do
    ambitious things like emulate a new kind of syntax within a C file. That
    will be a long list of #defines.

    Can you honestly say that the person writing the former, and the one
    writing the latter, are coding in the same language?

    Perhaps we are talking at cross-purposes here.

    The C preprocessor supports a few directives - such as #define. It is
    not a language - it is part of standard C. It is not hard to learn or understand, though there are a few awkward issues. Of course it can be
    /used/ in ways that are hard to understand.

    You seem to be talking about some imaginary "language" made by using
    extensive C macros and compiling with a C compiler. I have never heard
    of such a thing, other than perhaps people doing things for fun or the challenge of it and the occasional person who wants to make C look more
    like Pascal by using "#define begin {" and "#define end }".

    Sometimes people use a bit more advanced macros for simplifying their
    code or avoiding duplication of code. That can be things like wrappers
    for easily defining tree-like structs with common "left" and "right"
    pointers, or for defining lists of rules with a common format, or using "x-macros" to let you generate a simple command-line interface where you
    can get the instruction parser, enumerations, help text, etc., generated
    from one list of commands instead of duplicating them. All these things
    are examples of good use of complicated macro setups. All of them can
    also be handled in alternative ways such as using other languages or
    external scripts for generating the C code, or simply duplicating the C
    code manually.


    And can you honestly say that writing those complicated collections of
    macros requires no extra skill?

    Writing more complicated code always requires more skill than writing
    less complicated code.


    If your answers are Yes then /you/ are the one talking bollocks.

    (Maybe you've forgotten that Preprocessing is a C compilation stage
    which performs a transformation from C with macro invocations, to pure C
    with those invocations expanded.

    To repeat, what I call a different language is the set of incantations
    that form the body of each #define. They do not exist in the pure C
    version.)

    Please let me know if you are talking about writing macros as C
    programmers do regularly, or if you are talking about some very unusual
    usage of macro collections. And if it is the later, please say if you
    are talking about developing such "macro libraries", or /using/ such macros.



    Some will need a particular compiler or version because they rely on
    some very specific behaviour.

    There is almost nothing compiler-specific about pre-processor
    directives.  I only know of two very minor extensions that gcc
    supports, for marginally nicer variadic macro support.  Of course the
    result of the macro expansion might be compiler-specific, just like
    any other C code you write without macros.

    C compilers used to vary quite a bit in how macro expansions were done.

    Can you cite evidence of that? Exclude any broken or non-standard
    compilers, or ones that only implement a bit of C, or ones written by
    people who haven't bothered reading the relevant parts of the C
    standards. Also exclude any non-conformities around unrealistic
    situations (such as mixes of macro definitions across #include'd files).

    Now there is less variance, maybe because they're sharing the one implementation that got it just right.

    There are some C compilers that share front ends, but I expect that most
    will have their own pre-processors - either stand-alone, or, more often, integrated with the rest of the compiler.


    It will also be incredibly confusing for someone looking at a source
    file with a .c extension.

    I am not personally a fan of things like these macro packages - I'd
    rather just use C++.  But it's a matter of choice.  Even if you could
    argue that packages like "datatype99" are objectively bad in some
    sense (and you can't argue that), it would only be an argument against
    that use of macros, not C macros themselves or other use of them.

    You're trying to avoid agreeing with me, that C files containing
    constructs that emulate different syntax or different language elements,
    are going to be confusing.

    I happily agree that confusing code is confusing. That applies to
    confusing functions, confusing types, confusing macros, confusing
    comments, and anything else, in any language, using any feature. I
    don't agree that there is something special about macros in C that are confusing.


    Remember I claimed such things to be 'impractical, unwieldy and
    inefficient' -'usually'.

    If you are talking about C macros, which you regularly complain about,
    then you are wrong. (I say "wrong", rather than "I disagree with you",
    because macros are used so often by so many C programmers that it is
    obvious they are neither impractical, unwieldy, nor inefficient.)

    If you are talking about some hypothetical extra embedded language
    written in macros, then it's a non-starter - such things are not used in
    real code, except in very niche cases when they are used precisely
    because they are the most convenient, efficient and safe method in those
    niche situations.

    And if you are talking about something like that "datatype99" macro
    library, then your opinion is worthless unless you can show some
    real-world usage of it, compare it to real code in C doing a similar job without the macro library (or equivalent macros), and demonstrate that
    the "datatype99" version is clearly inferior.

    You are, of course, welcome to your opinions - but if you can't justify
    them or show that they are reasoned opinions, they are worthless.


    If your best argument against C macros is that someone wrote a
    Brainfuck interpreter with them and it is inefficient, then I think
    you should retire from the discussion.

    You seem to advocating using C macros to make an embedded language,
    given that you say:

    "The suggestion that making your own language and tools instead of a
    macro library is clearly absurd."

    Your imagination is running wild again. Try reading what I wrote.

    I have not advocated for making any kind of "embedded language" in C, in
    any sense.


    I gave an example of a tiny language needing 100 times as much source
    code to implement using C macros, as in a normal language, and another version of it that was hopelessy slow and inefficient.

    No, you did not - in either case.


    And that's for a language which is normally as simple to implement, if
    not use, as they come.

    So, do you have an actual example of an embedded language that is
    implemented more reasonably using macros?

    By embedded 'language' I don't mean a library of function or macro definitions that you just call or invoked, as happens in any C program.




    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to All on Fri Apr 25 17:51:15 2025
    On 25/04/2025 13:48, Rosario19 wrote:
    On Fri, 25 Apr 2025 02:56:44 -0000 (UTC), Kaz Kylheku wrote:

    On 2025-04-24, bart wrote:
    NOTHING I SAY IS EVER RIGHT.

    Well, /that/ isn't; you're blindly discounting all the times
    someone has agreed with you.

    here we are all wrong in something

    Not me - I'm never wrong.

    (Except perhaps in this post :-) )

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Fri Apr 25 17:48:58 2025
    On 24/04/2025 15:51, bart wrote:
    On 24/04/2025 13:25, David Brown wrote:
    On 23/04/2025 19:43, bart wrote:

    By the 500 such macro definitions, and the EXTENSIVE use of such
    macro invocations instead of functions, in a class of application I'm
    very familiar with.


    So you don't know.  You guessed.

    Why are you automatically sticking up for THEM and not ME?

    Why are you criticising them (the Lua authors) when you have no idea
    what is behind their code?

    I am not saying that you are wrong as such - maybe the Lua code /is/
    overly complicated, and uses more macros than makes sense, and the code
    is harder to maintain because of it. Maybe there is no particularly
    good reason for this - maybe the Lua programmers are just not very good developers.

    What I am saying is that you don't have the information or background to
    give a fair critique of the code. All you are giving is a highly
    subjective opinion based on a bit of the code, and your own strong
    prejudices about C in general, and certain C features in particular.

    Of course I too could say that at a first glance, there are too many
    low-value macros here, the identifier names are poorly chosen, and at
    least some of the macros would be better if they were replaced by inline functions. But I know that would be a first-glance viewpoint, and could
    easily be wrong or unfair.


    What qualifications and what experience would somebody need for David
    Brown to give credence to their opinion?

    I already outlined that.


    I'm sure there are lots projects you can look at and know straight off
    that its uses of macros or whatever is over the top.

    I am not so sure of that.

    Of course you can form a first impression in many cases, but I don't
    like to place too much weight on that. It is not unreasonable to talk
    about your first impressions, if they are clear enough, but it should be
    a qualified judgement. Don't say "this code abuses too many macros" -
    say "from what I have seen so far, it looks like the code uses more
    macros than I think is sensible for such a task".


    Suppose you reported that here, but I suggested that you don't know
    that; you're only guessing?


    If you called me out on a claim about some code without appropriate understanding of the context, then I should be grateful for the
    correction. I am not going to promise I /would/ be grateful - I'm a
    mere human, with as fragile an ego as the next person.


    You don't have any idea /why/ the developers choose to use macros like
    this - you simply assume that because you have written an interpreter
    with little use of macros,

    I've written a million lines of code with little use of macros.

    So what?

    That does not mean you can judge whether the given macros are a good
    solution in this code. In fact, I'd say it makes you a /worse/ judge
    than most C programmers, since you are unfamiliar with macro usage
    (except to criticise it without justification).

    I've written a million lines of code, and never touched Rust - does that
    mean I can tell Rust programmers that their choices are inefficient and impractical?


    They are prevalent in C simply because the language has them and people
    will use them. Even if you ignore the ones that only exist people
    because don't like to use enums for named constants.


    They are prevalent in C programming primarily because they are very
    useful in C programming, and fully supported by the language and tools.

    Do you also complain about people using the number 7 in their C code?
    After all, it is available in the language, but it is completely
    unnecessary - people could just write "6 + 1" instead and avoid all
    those silly sevens. Or do you think perhaps people write the number 7
    rather than "6 + 1" because it gives them clearer code in a more
    convenient manner, just like good use of macros does?


    What your experience tells you is that is that it is /possible/ to
    implement a little virtual machine for a simple language without using
    C macros.

    It tells you nothing about whether or not it is a good idea, because
    you have not tried it out for comparison.  It tells you nothing about
    how best to implement Lua in C, because that is a very different
    language from your languages.

    The example I gave was from ADD; my language has ADD too! Except that
    Lua's ADD works between Ints and Floats (Floats only before 5.1?); mine
    works between Ints, Floats, Strings, Bignums and Sets.

    So, how different is it really?


    Lua is an established language used by lots of people - it is
    documented, popular, and battle-tested (both as a language, and the
    tools) - yours is not. It is designed as an embedded scripting language
    - yours is, AFAIK, not. Lua is based on tables (for hashmaps, arrays,
    etc.), while yours AFAIK is not. Lua has anonymous functions - indeed,
    all functions are anonymous in Lua. Lua has support for OOP via tables.
    It has proper scoping. I'm confident there are a great many
    differences, though I don't know details of your language. I'm sure
    there are plenty of similarities however, as there are between any pair
    of languages.

      It tells you nothing about the best structure for a core project
    written by multiple people, with extensions written by hundreds or
    thousands of people, and with many orders of magnitude more end users
    - because you just have a one-person language.

    You forgot the bit where I said I've been doing this since the 1980s, on
    a few languages of my own, both dynamic and statically typed. And I've
    looked at lots of others including their implementations.


    No, I didn't forget.

    I've also got my C compiler to build and run some of those (Lua and
    Seed7 among them).


    I've compiled Lua too, linked in with my own code.

    I even created a C interpreter.

    I've experimented with half a dozen kinds of bytecode dispatcher, and
    several methods of type dispatching, and tried out AST tree-walkers.

    Some of my interpreters were embedded, and run within commercial
    products, and used by other people to create their own add-on programs.


    I realise you have done lots of stuff, and have lots of experience. I
    simply don't see it as relevant to be able to judge the way the Lua
    source code is structured without further knowledge of that code.

    And while I am loathe to make ad hominem judgements or appeals to
    authority, you are a guy off the internet who has made a lifetime career
    of living in your own bubble, avoiding any contact or information from
    other languages, other software, or computer science research -
    convinced in your own superiority in language design and implementation
    over the entire rest of humanity. Lua was designed and implemented by university professors - experts in the field, familiar with the
    strengths and weaknesses of lots of languages and implementation
    techniques. The language and its implementation has been refined and
    developed with the feedback of huge numbers of people.

    Of course you can have your subjective opinion on the language and its implementation. It is only natural that you would prefer your language,
    and your style of implementation. But do you understand that I do not
    consider your opinion to be objective? I am not giving any kind of
    opinion or critique on the Lua code, because I know I am not able to
    give a fair and justified analysis. I do not think you are either.

    And to cap it all, you (AFAIUI) don't even use C to implement any of
    this stuff - you use your own languages.  (Those may well be a better
    choice than C for implementing virtual machines.)

    I did try C at one point. That didn't use macros either.

    The way you could /know/ the best way to implement a Lua virtual
    machine in C would be to investigate if the Lua developers, or any
    other groups, have tried to implement the Lua VM in different ways and
    seen how well they work.  Or you could find books or articles that
    discuss different ways of implementing VMs.

    Maybe /I/ should write a book or article instead!

    Perhaps you should. I am sure you have a lot of information (about many topics) that you could put in a book - or at least a series of articles.
    It would be a more constructive use of your keyboard than a lot of
    these Usenet threads :-)



    There are perhaps a half-dozen basic ways of implementing language
    virtual machines.  There are a very large number of interpreted or
    byte- coded languages.  You have experience of implementing a couple
    of simple languages, for personal use, using either a strangely
    restricted subset of C or one of your own languages.

    How many interpreters do you think the developers of Lua have worked on?
    (And how many of those developers also devised and programmed its implemenation language?)

    I don't know the Lua developers personally - but since the core team are university professors, I imagine they have at least /some/ suitable qualifications and knowledge.


    You describe my languages as 'simple'; how much more complex do you
    think Lua is?

    I find it disappointing that you don't want to acknowledge that I might
    know something of this field, that I have extensive experience of it,
    and that my opinions might be valid.

    I /do/ acknowledge your experience. I don't acknowledge that you are in
    a position to judge whether the macros used in the implementation of Lua
    are a good idea or not. Can't you understand that difference?


    More so that you seem to know little about Lua, but decide to give them
    the benefit of a doubt anyway.


    Note - again - that I have not said their use of macros was good. I
    have said that neither you nor I are in a position to say their use of
    macros was bad.

    /Maybe/ they had good reasons for using so many macros, but /maybe/ so
    do I for having so few!


    Equally, I am not in a position to say that your use of few macros is
    bad or that your code would be improved with more of them.


    So why are you automatically assuming they must be right, and I must be wrong?

    Why are you assuming I have said they are right in the way they designed
    their code, or that I have said you were wrong?

    Stop trying to view everything as binary.


    Further, this is part of a survey of interpreters running a recursive Fibonacci benchmark:


    That tells you nothing useful.

    So I know fuck-all about writing interpreters, they are all toys, my languages are toys, and my opinion counts for nothing?


    Your opinions count as your opinions. Nothing more, nothing less.

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

    On Tue, 15 Apr 2025 11:30:24 +0100
    bart <bc@freeuk.com> wrote:

    Let me ask you this: what exactly is the point of the 'while'
    statement in C? Since it can always be trivially be written as:

    for (;cond;)

    It seems to that most use cases (initialise, check exit condition,
    change something that affects the letter), would suit 'for' better.

    But since 'for' then becomes overloaded, there ought to be a
    dedicated feature for simple iteration. So it seems the solution is
    as a I suggested above.

    I suspect that 'while' loop is here in C because Dennis Ritchie wanted
    'do .. while() ' and thought that if the keyword is here anyway than
    why not reuse it?

    According to K&R, all of the basic control structures in C -- if,
    while, for, do, and switch (and listed in that order) -- were
    provided in BCPL, though not using the same syntax as in C,.

    In the hindsight, probably a mistake.

    I admit I don't understand this reaction.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Richard Heathfield on Sun May 4 07:40:30 2025
    Richard Heathfield <rjh@cpax.org.uk> writes:

    On 15/04/2025 13:34, Michael S wrote:

    <snip>

    I suspect that 'while' loop is here in C because Dennis Ritchie wanted
    'do .. while() ' and thought that if the keyword is here anyway than
    why not reuse it?
    In the hindsight, probably a mistake.

    In hindsight:

    $ find . -name \*.c | xargs cat | wc -l
    126343
    $ find . -name \*.c | xargs grep -w while | wc -l
    556
    $ find . -name \*.c | xargs grep -w for | wc -l
    1258


    So although I use for() about twice as much as I use while(), I still
    find while a better option one time in three. That's useful enough to
    make it worth keeping in the toolbox.

    Out of curiousity, I tabulated a similar set of statistics for
    a recent C project. Considering just the three iteration
    control structures (do/for/while), the results (rounded to the
    nearest 0.1 percent) were

    while 56.1 %
    for 24.1 %
    do/while 19.5 %

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Sun May 4 18:08:33 2025
    On Sun, 04 May 2025 07:31:11 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 15 Apr 2025 11:30:24 +0100
    bart <bc@freeuk.com> wrote:

    Let me ask you this: what exactly is the point of the 'while'
    statement in C? Since it can always be trivially be written as:

    for (;cond;)

    It seems to that most use cases (initialise, check exit condition,
    change something that affects the letter), would suit 'for' better.

    But since 'for' then becomes overloaded, there ought to be a
    dedicated feature for simple iteration. So it seems the solution
    is as a I suggested above.

    I suspect that 'while' loop is here in C because Dennis Ritchie
    wanted 'do .. while() ' and thought that if the keyword is here
    anyway than why not reuse it?

    According to K&R, all of the basic control structures in C -- if,
    while, for, do, and switch (and listed in that order) -- were
    provided in BCPL, though not using the same syntax as in C,.

    In the hindsight, probably a mistake.

    I admit I don't understand this reaction.

    I don't like reuse of keyboards. Neither of 'while' nor of 'break' nor
    of 'static' (even more so in C++) nor use of 'long' modifier both for
    integer and for floating-point types.
    Double meaning of 'while' adds unnecessary mental load for a code
    reader. Not a lot of it, but still unnecessary.
    Also having just one form of loop with pre-condition strikes me as more elegant. Since elegance is strongly subjective, I have no logical
    arguments in support of me feelings.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Scott Lurndal on Sun May 4 21:35:16 2025
    scott@slp53.sl.home (Scott Lurndal) writes:

    bart <bc@freeuk.com> writes:

    On 18/04/2025 19:10, James Kuyper wrote:

    On 16.04.2025 13:01, bart wrote:
    ...

    Unlike C's for, which is just a gimmick where you bundle three
    potentially unrelated expressions and hope for the best.

    If all you can do is "hope for the best", you're doing it wrong.
    It's your job to ensure that they are not arbitrary unrelated
    expressions, but correctly related expressions, and that's no
    different from your responsibility for all of the other
    expressions that make up your program.

    If you find that problematic, you shouldn't be programming in

    any language, but certainly not in C.

    I see it didn't take you long to get to the personal insult. What
    is it with this group?

    It's not an insult, it is a simple fact.

    Any statement with the word "should" in it is a lot more likely
    to be a statement of opinion than a statement of fact.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Scott Lurndal on Sun May 4 21:32:22 2025
    scott@slp53.sl.home (Scott Lurndal) writes:

    Michael S <already5chosen@yahoo.com> writes:

    On Wed, 16 Apr 2025 12:32:13 +0100
    bart <bc@freeuk.com> wrote:

    But never, mind, C's for-loop will still be the most superior to
    everybody here. I'd have an easier time arguing about religion!

    Who exactly said that it is superior? Surely not me.
    I think, most posters here would agree with my stance that C for() is
    non-ideal. esp. for writer, but good enough.

    I disagree with that statement, [...]

    Does this mean you think the for() control structure defined
    in ISO C is ideal?

    I'm okay with using C for() statements as an iterative control
    structure, but I don't think I'd describe it as ideal.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Sun May 4 22:17:21 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    bart <bc@freeuk.com> writes:
    [...]

    I'm trying to stand up for myself as I'M AT THE END OF MY FUCKING
    TETHER HERE.

    ALL YOU PEOPLE WANT TO DO IS JUST TRASH EVERYTHING I'VE DONE.

    EVERY SINGLE THING I SAY IS WRONG. NOTHING I SAY IS EVER
    RIGHT. WHATEVER IT IS I SAY, YOU SAY THE OPPOSITE THING.

    MY SELF-ESTEEM HAS NEVER BEEN LOWER - YOU HAVE DESTROYED ME.

    [...]

    Bart, if this is sincere, please consider stepping away from
    comp.lang.c for a while. I have no motivation for this post other
    than concern for your well-being.

    If any poster shows signs of being enormously distraught by
    exchanges in a newsgroup (and comp.lang.c specifically), I hope
    other participants would notice that and consider disengaging
    with that poster for some period of time, not only for the sake
    of the distraught poster but also for the benefit of the rest of
    the group.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Michael S on Mon May 5 10:42:09 2025
    On Sun, 4 May 2025 18:08:33 +0300
    Michael S <already5chosen@yahoo.com> wrote:

    On Sun, 04 May 2025 07:31:11 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 15 Apr 2025 11:30:24 +0100
    bart <bc@freeuk.com> wrote:

    Let me ask you this: what exactly is the point of the 'while'
    statement in C? Since it can always be trivially be written as:

    for (;cond;)

    It seems to that most use cases (initialise, check exit
    condition, change something that affects the letter), would suit
    'for' better.

    But since 'for' then becomes overloaded, there ought to be a
    dedicated feature for simple iteration. So it seems the solution
    is as a I suggested above.

    I suspect that 'while' loop is here in C because Dennis Ritchie
    wanted 'do .. while() ' and thought that if the keyword is here
    anyway than why not reuse it?

    According to K&R, all of the basic control structures in C -- if,
    while, for, do, and switch (and listed in that order) -- were
    provided in BCPL, though not using the same syntax as in C,.

    In the hindsight, probably a mistake.

    I admit I don't understand this reaction.

    I don't like reuse of keyboards. Neither of 'while' nor of 'break' nor
    ^^^^^^^^^
    keywords

    of 'static' (even more so in C++) nor use of 'long' modifier both for
    integer and for floating-point types.
    Double meaning of 'while' adds unnecessary mental load for a code
    reader. Not a lot of it, but still unnecessary.
    Also having just one form of loop with pre-condition strikes me as
    more elegant. Since elegance is strongly subjective, I have no logical arguments in support of me feelings.
    ^^
    my




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

    On Wed, 16 Apr 2025 14:09:44 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    bart <bc@freeuk.com> writes:

    On 15/04/2025 20:07, Scott Lurndal wrote:

    bart <bc@freeuk.com> writes:

    On 15/04/2025 14:19, Kaz Kylheku wrote:

    Thats's fine. But it means a real 'for' loop doesn't exist in C;
    you have to emulate it using that 3-way construct, which is naff,
    and also error prone.

    Real for loops _are_ a three-way construct.

    135 FOR I=1 TO 10 STEP 2 [BASIC]

    for(i = 1; i < 11; i += 2) [C/C++]

    do 1 = 1, 10, 2 [FORTRAN]

    Any step other than 1 is unusual. So Basic and Fortran would
    typically be:

    for i = 1 to 10 # 6 tokens; Basic
    do i = 1, 10 # 6 tokens; Fortran
    for i = 1, 10 # 6 tokens; Lua
    for i to 10 do # 5 tokens; Mine (using default start)
    to 10 do # 3 tokens; Mine (when index is not needed)

    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C

    for(i = 1; i++ <= 10;)

    I'd reject this code during review.
    Hopefully, you too.

    I'm curious to know the basis for your reaction. What about the
    code would prompt your judgment to reject it? Is it just a
    specific reaction, or does it represent some more general pattern
    (and if so then what more general pattern)?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Wed May 7 12:32:32 2025
    On Tue, 06 May 2025 05:59:20 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Wed, 16 Apr 2025 14:09:44 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    bart <bc@freeuk.com> writes:

    On 15/04/2025 20:07, Scott Lurndal wrote:


    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C

    for(i = 1; i++ <= 10;)

    I'd reject this code during review.
    Hopefully, you too.

    I'm curious to know the basis for your reaction. What about the
    code would prompt your judgment to reject it? Is it just a
    specific reaction, or does it represent some more general pattern
    (and if so then what more general pattern)?

    First and foremost it was tongue-in-cheek reaction to the article that
    Scott posted 2-3 minutes after the article that I was reacting to.

    At the next level, it is true that if I do detailed code review (which
    I almost never do) I would indeed reject this code. The first
    and sufficient reason is that the code looks superficially similar to
    very common idiom, but significantly differs in behavior. An additional
    reason is that post-increment operator is generally harder to reason
    about than almost any other C operator, esp. so when used as part of comparison, so, IMHO, readable code should limit use of post-increment
    to very common idioms (or altogether avoid it). The third reason,
    related to the first two is that behavior of this loop is way too
    surprising.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Michael S on Wed May 7 14:54:09 2025
    On 07.05.2025 11:32, Michael S wrote:
    On Tue, 06 May 2025 05:59:20 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Wed, 16 Apr 2025 14:09:44 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    bart <bc@freeuk.com> writes:

    On 15/04/2025 20:07, Scott Lurndal wrote:


    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C

    for(i = 1; i++ <= 10;)

    I'd reject this code during review.
    Hopefully, you too.

    I'm curious to know the basis for your reaction. What about the
    code would prompt your judgment to reject it? Is it just a
    specific reaction, or does it represent some more general pattern
    (and if so then what more general pattern)?

    First and foremost it was tongue-in-cheek reaction to the article that
    Scott posted 2-3 minutes after the article that I was reacting to.

    At the next level, it is true that if I do detailed code review (which
    I almost never do) I would indeed reject this code. The first
    and sufficient reason is that the code looks superficially similar to
    very common idiom, but significantly differs in behavior. An additional reason is that post-increment operator is generally harder to reason
    about than almost any other C operator, esp. so when used as part of comparison, so, IMHO, readable code should limit use of post-increment
    to very common idioms (or altogether avoid it). The third reason,
    related to the first two is that behavior of this loop is way too
    surprising.

    What I derive here is that [formal] reviewers should have some formal
    set of rules that have _sensible rationales_ attached. (This is what
    we've done in one company, at least.) The explanations above sound
    more like some individual/subjective feeling; that of course may have
    its validity (but maybe as well it has not).

    Coding standards, BTW, should thus also be subject to review, and its
    reviewers carefully selected. You can inflict harm to the process if
    you get such standard wrong and install opinion-based style-sheriffs.

    My own subjective feelings about the code above with the two loops is
    also not positive. But I'd neither consider the post-increment as a
    problem (comprehension or else), nor do I find the behavior surprising.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Michael S on Wed May 7 13:50:26 2025
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 06 May 2025 05:59:20 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Wed, 16 Apr 2025 14:09:44 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    bart <bc@freeuk.com> writes:

    On 15/04/2025 20:07, Scott Lurndal wrote:


    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C

    for(i = 1; i++ <= 10;)

    I'd reject this code during review.
    Hopefully, you too.

    I'm curious to know the basis for your reaction. What about the
    code would prompt your judgment to reject it? Is it just a
    specific reaction, or does it represent some more general pattern
    (and if so then what more general pattern)?

    First and foremost it was tongue-in-cheek reaction to the article that
    Scott posted 2-3 minutes after the article that I was reacting to.

    My reply, was of course, also tongue-in-cheek as a response to
    Bart's silly token counting. I've never found a reason to code
    a for loop like that.


    At the next level, it is true that if I do detailed code review (which
    I almost never do) I would indeed reject this code. The first
    and sufficient reason is that the code looks superficially similar to
    very common idiom, but significantly differs in behavior. An additional >reason is that post-increment operator is generally harder to reason
    about than almost any other C operator, esp. so when used as part of >comparison, so, IMHO, readable code should limit use of post-increment
    to very common idioms (or altogether avoid it). The third reason,
    related to the first two is that behavior of this loop is way too
    surprising.

    An overreaction, perhaps. I'm not sure what I'd do if I saw
    it during code review - it would depend on the surrounding context
    I suspect.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Sat May 10 06:43:38 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 04 May 2025 07:31:11 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 15 Apr 2025 11:30:24 +0100
    bart <bc@freeuk.com> wrote:

    Let me ask you this: what exactly is the point of the 'while'
    statement in C? Since it can always be trivially be written as:

    for (;cond;)

    It seems to that most use cases (initialise, check exit condition,
    change something that affects the letter), would suit 'for' better.

    But since 'for' then becomes overloaded, there ought to be a
    dedicated feature for simple iteration. So it seems the solution
    is as a I suggested above.

    I suspect that 'while' loop is here in C because Dennis Ritchie
    wanted 'do .. while() ' and thought that if the keyword is here
    anyway than why not reuse it?

    According to K&R, all of the basic control structures in C -- if,
    while, for, do, and switch (and listed in that order) -- were
    provided in BCPL, though not using the same syntax as in C,.

    In the hindsight, probably a mistake.

    I admit I don't understand this reaction.

    I don't like reuse of [keywords]. Neither of 'while' nor of 'break' nor
    of 'static' (even more so in C++) nor use of 'long' modifier both for
    integer and for floating-point types.
    Double meaning of 'while' adds unnecessary mental load for a code
    reader. Not a lot of it, but still unnecessary.

    Let me take these one at a time, roughly in order of most overloaded
    first. My aim here is to offer some perspectives that may alleviate
    the negative effects you feel.

    A new use for 'static' was added in C99, having to do with parameter
    array declarators. This new use has nothing to do with the earlier
    uses. All I can offer here is that these new uses don't occur very
    often, and are never necessary (in the same sense that 'restrict' is
    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the
    extra effort needed could be seen as a positive.

    Starting already in pre-C99, 'static' has two uses that are somewhat
    different from each other, those uses being one, outside of any
    function definition, and two, local to a particular function body.
    Do you find the two kinds of circumstances need extra mental effort?
    To me the meaning in the two cases is the same but the applications
    are different, in much the same way that 'int x;' at file scope and
    'int x;' in block scope are both the same and different. So even
    though the how 'static' is used is different in the two cases, for
    consistency with other parts of declarations it seems better just to
    use 'static' for both.

    For 'long', maybe it would help to think of 'long' as an independent
    axis, sort of like 'volatile'. I think most programmers wouldn't
    have trouble with two independent axes, such as {binary, decimal}
    and {fixed-point, floating-point}. What modifiers would you use
    if had to have different words for integer types and floating-point
    types? Here I think using 'long' (or maybe 'wide'?) for both is
    more natural than having different words for the two cases.

    For 'break', to me all uses of 'break' do the same thing: they exit
    one level of control structure. It is perhaps odd that 'break'
    cannot be used with 'if', but other than that it seems needlessly
    redundant to have different kinds of 'break' for each of the various
    kinds of control structure. And if a function is so complicated
    that it isn't immediately apparent which control structure is being
    exited, that is an indication that the code needs revising, and not
    just because of problems with break.

    Similarly with 'while', both uses of 'while' mean the same thing: a
    single test to control whether the controlled loop continues or
    exits. We might think of the two kinds of loops as being different,
    but as far as 'while' goes it is doing the same thing whether it is
    at the top or at the bottom.

    I hope you have found these comments helpful. On a larger scale, it
    might help to think in general terms rather than being distracted by
    low-level details.

    Also having just one form of loop with pre-condition strikes me as more elegant. Since elegance is strongly subjective, I have no logical
    arguments in support of me feelings.

    In a recent posting I gave some statistics about the three different
    kinds of looping controls (while,for,do/while). do/while loops were
    almost 20% of all loops, and more than a quarter of the two kinds of
    loops other than for(). Besides being a more pragmatic choice, I
    think having the three kinds of loops be distinct in the language is
    a better choice, because how we think of the different kinds of loop
    is different, and it's helpful to have those differences be readily
    apparent in the program, rather than needing to reconstruct them by
    looking at code around the loop control fragment.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@dastardlyhq.com@21:1/5 to All on Sat May 10 15:56:45 2025
    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the

    Isn't it?

    Where "static" means local to a module the words "local","module","limit" spring to mind which are far closer to the intended meaning. Reusing "static" seems somewhat perverse IMO.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Muttley@dastardlyhq.com on Sat May 10 17:48:20 2025
    Muttley@dastardlyhq.com writes:
    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the

    Isn't it?

    Where "static" means local to a module the words "local","module","limit" >spring to mind which are far closer to the intended meaning. Reusing "static" >seems somewhat perverse IMO.

    'local', 'module', 'limit' are common words used as identifiers in five
    decades of C code. Using them as keywords in a newer version of C would
    not be desirable. Whereas the new flavor of 'static' won't break any
    existing code, and provides a concrete benefit.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Sun May 11 01:09:17 2025
    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 04 May 2025 07:31:11 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:


    Also having just one form of loop with pre-condition strikes me as
    more elegant. Since elegance is strongly subjective, I have no
    logical arguments in support of me feelings.

    In a recent posting I gave some statistics about the three different
    kinds of looping controls (while,for,do/while). do/while loops were
    almost 20% of all loops, and more than a quarter of the two kinds of
    loops other than for(). Besides being a more pragmatic choice, I
    think having the three kinds of loops be distinct in the language is
    a better choice, because how we think of the different kinds of loop
    is different, and it's helpful to have those differences be readily
    apparent in the program, rather than needing to reconstruct them by
    looking at code around the loop control fragment.

    That sounds like misunderstanding.
    I didn't suggest one loop construct. I suggested two constructs: for()
    for loops with pre-condition and do-while for loops with post-condition.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Muttley@dastardlyhq.com on Sat May 10 14:29:50 2025
    Muttley@dastardlyhq.com writes:

    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:

    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the

    Isn't it?

    Where "static" means local to a module the words
    "local","module","limit" spring to mind which are far closer to
    the intended meaning. Reusing "static" seems somewhat perverse
    IMO.

    The use I'm talking about here may be illustrated as follows:

    double
    average( double values[ static 10 ] ){
    double total = 0;
    for( int i = 0; i < 10; i++ ){
    total += values[i];
    }
    return total / 10;
    }

    What word would you suggest to be used in place of 'static'
    there?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@dastardlyhq.com@21:1/5 to All on Sun May 11 08:20:56 2025
    On Sat, 10 May 2025 17:48:20 GMT
    scott@slp53.sl.home (Scott Lurndal) gabbled:
    Muttley@dastardlyhq.com writes:
    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the

    Isn't it?

    Where "static" means local to a module the words "local","module","limit" >>spring to mind which are far closer to the intended meaning. Reusing "static" >>seems somewhat perverse IMO.

    'local', 'module', 'limit' are common words used as identifiers in five >decades of C code. Using them as keywords in a newer version of C would
    not be desirable. Whereas the new flavor of 'static' won't break any >existing code, and provides a concrete benefit.

    Overloading the same keyword to mean different things is never desirable IMO otherwise taken to its logical conclusion you might as well just have 1 keyword that does everything.

    Compiler switches are a thing - if there's a name clash with your old code don't compile it with the new version of the language. I'm sure plenty of old
    C code used variable names such as "new" or "class" so it can't be compiled
    by a C++ compiler.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@dastardlyhq.com@21:1/5 to All on Sun May 11 08:21:22 2025
    On Sat, 10 May 2025 14:29:50 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
    Muttley@dastardlyhq.com writes:

    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:

    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the

    Isn't it?

    Where "static" means local to a module the words
    "local","module","limit" spring to mind which are far closer to
    the intended meaning. Reusing "static" seems somewhat perverse
    IMO.

    The use I'm talking about here may be illustrated as follows:

    double
    average( double values[ static 10 ] ){
    double total = 0;
    for( int i = 0; i < 10; i++ ){
    total += values[i];
    }
    return total / 10;
    }

    What word would you suggest to be used in place of 'static'
    there?

    If I knew what the hell it was supposed to do I'd tell you.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Muttley@dastardlyhq.com on Sun May 11 12:02:25 2025
    On 11/05/2025 10:21, Muttley@dastardlyhq.com wrote:
    On Sat, 10 May 2025 14:29:50 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
    Muttley@dastardlyhq.com writes:

    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:

    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the

    Isn't it?

    Where "static" means local to a module the words
    "local","module","limit" spring to mind which are far closer to
    the intended meaning. Reusing "static" seems somewhat perverse
    IMO.

    The use I'm talking about here may be illustrated as follows:

    double
    average( double values[ static 10 ] ){
    double total = 0;
    for( int i = 0; i < 10; i++ ){
    total += values[i];
    }
    return total / 10;
    }

    What word would you suggest to be used in place of 'static'
    there?

    If I knew what the hell it was supposed to do I'd tell you.


    Using "static" inside array parameters is, IME, extremely rare. It was
    added in C99, and tells the compiler that whenever "average" is called,
    the "values" parameter points to an array of at least 10 doubles. It
    does not affect the signature of the function or compatibility with any
    other declarations, and is AFAIK rarely checked by compilers.

    In an example like the one above, it is completely useless for
    compilation - it tells the compiler nothing that it does not already
    know. An optimising compiler will see that you are accessing values[0]
    to values[9], and if it can get better results through vectorising, prefetching, etc., then it will do so. (You can argue that the "static
    10" is still useful as an indicator to human readers, but I am not
    convinced of that.)

    However, there are possible situations where it could be useful to the compiler. Consider instead this function :

    double average(double values[static 4]) {
    double total = 0.0;
    for (int i = 0; i < 3; i++) {
    total += values[i];
    }
    return total / 3;
    }

    Without the "static 4", the compiler can only assume that it can access
    up to 3 doubles from the "value" array. But with "static 4", it knows
    it is safe to read "values[3]" even though the code never needs to do
    so. And that means it can use a "prefetch 32 bytes" instruction, or a
    "load 4 doubles into a SIMD register" instruction, if these can result
    in faster code.

    When "[static X]" was added to C99, it was thought that this could be a significant help in some code. It certainly /can/ be helpful for some
    code (consider a case where the loop range is from another parameter
    rather than a fixed value like the examples above), but the combination
    of super-scaler and re-ordering modern processors and smarter modern
    compilers means it is very rare that it is helpful. And in cases where
    it could increase efficiency and you really need maximal efficiency, you
    are almost certainly better off using compiler-specific features (like
    gcc's __builtin_prefetch).


    So the obvious answer to Tim's question of what to use instead of
    "static" is "nothing at all" :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@dastardlyhq.com@21:1/5 to All on Sun May 11 15:30:01 2025
    On Sun, 11 May 2025 12:02:25 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    double average(double values[static 4]) {
    double total = 0.0;
    for (int i = 0; i < 3; i++) {
    total += values[i];
    }
    return total / 3;
    }

    Without the "static 4", the compiler can only assume that it can access
    up to 3 doubles from the "value" array. But with "static 4", it knows
    it is safe to read "values[3]" even though the code never needs to do

    Not sure I follow. C doesn't care if its safe or not, it'll just try and
    read them anyway and if it can't and there's a memory leak or crash, well, tough luck mate. So I don't see why it would make a difference to the resulting assembler.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Muttley@dastardlyhq.com on Sun May 11 18:49:44 2025
    On 11/05/2025 17:30, Muttley@dastardlyhq.com wrote:
    On Sun, 11 May 2025 12:02:25 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    double average(double values[static 4]) {
        double total = 0.0;
        for (int i = 0; i < 3; i++) {
            total += values[i];
        }
        return  total / 3;
    }

    Without the "static 4", the compiler can only assume that it can
    access up to 3 doubles from the "value" array.  But with "static 4",
    it knows it is safe to read "values[3]" even though the code never
    needs to do

    Not sure I follow. C doesn't care if its safe or not, it'll just try and
    read them anyway and if it can't and there's a memory leak or crash,
    well, tough luck mate. So I don't see why it would make a difference to
    the resulting
    assembler.



    No, C (and the C compiler) /does/ care if it something is safe or not.
    But it believes the programmer if the programmer says it is safe. Thus
    if the programmer writes code that accesses "values[3]", the compiler
    may assume it is safe to do so at other times too. But if the
    programmer never accesses beyond "values[2]", the compiler cannot assume
    it is safe to access "values[3]". If you want the compiler to be able
    to generate code that is more efficient by accessing "values[4]", you
    have to tell it that it is safe to do so. And using "static 4" here in
    the parameter is one way of saying that.

    There are other ways that could be used - if you write "(void)
    values[3];", the compiler could see that it is safe to read that
    address. Whether or not a given compiler optimiser would use that
    information is another matter, of course.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Muttley@dastardlyhq.com on Sun May 11 16:29:39 2025
    Muttley@dastardlyhq.com writes:
    On Sun, 11 May 2025 12:02:25 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    double average(double values[static 4]) {
    double total = 0.0;
    for (int i = 0; i < 3; i++) {
    total += values[i];
    }
    return total / 3;
    }

    Without the "static 4", the compiler can only assume that it can access
    up to 3 doubles from the "value" array. But with "static 4", it knows
    it is safe to read "values[3]" even though the code never needs to do

    Not sure I follow. C doesn't care if its safe or not, it'll just try and
    read them anyway and if it can't and there's a memory leak or crash, well, >tough luck mate. So I don't see why it would make a difference to the resulting
    assembler.

    He meant that the optimizer could choose to generate a SIMD load
    instruction rather than three separate load instructions, trusting that
    the fourth entry will be legally acessible even if that extra loaded value is not used.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to David Brown on Sun May 11 17:43:42 2025
    On 5/11/25 06:02, David Brown wrote:
    On 11/05/2025 10:21, Muttley@dastardlyhq.com wrote:
    On Sat, 10 May 2025 14:29:50 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
    ...
    The use I'm talking about here may be illustrated as follows:

    double
    average( double values[ static 10 ] ){
    double total = 0;
    for( int i = 0; i < 10; i++ ){
    total += values[i];
    }
    return total / 10;
    }

    What word would you suggest to be used in place of 'static'
    there?

    If I knew what the hell it was supposed to do I'd tell you.


    Using "static" inside array parameters is, IME, extremely rare. It was
    added in C99, and tells the compiler that whenever "average" is called,
    the "values" parameter points to an array of at least 10 doubles. It

    More precisely, it makes it undefined behavior for values to point to an
    array of less than 10 doubles.

    does not affect the signature of the function or compatibility with any
    other declarations, and is AFAIK rarely checked by compilers.

    I'd have preferred it if violating that requirement was a constraint
    violation, but it can't be, because there are many cases where a
    compiler cannot be sure how long the array is that a pointer points at. However, the fact that the behavior is undefined justifies a compiler
    reacting to the case when it can be sure that the requirement will be
    violated. That's the main reason I like this feature, and dislike
    compilers that fail to take advantage of that opportunity. I never
    considered it to be about efficiency, though there are cases where it
    can result in more efficient code.

    In an example like the one above, it is completely useless for
    compilation - it tells the compiler nothing that it does not already
    know. An optimising compiler will see that you are accessing values[0]
    to values[9], and if it can get better results through vectorising, prefetching, etc., then it will do so. (You can argue that the "static
    10" is still useful as an indicator to human readers, but I am not
    convinced of that.)

    It's main potential usefulness is not in the definition of the function,
    but in calls to the function. If the calls occur in a different
    translation unit from the definition, the compiler does not have the
    needed information.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Keith Thompson on Sun May 11 18:30:35 2025
    On 5/11/25 18:06, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [...]
    It's main potential usefulness is not in the definition of the function,
    but in calls to the function. If the calls occur in a different
    translation unit from the definition, the compiler does not have the
    needed information.

    It does if the visible declaration has the same information.

    True - I was responding to his claim that the information in the
    declaration was unneeded, because it's implicit in the function
    definition. That would be true if the primary purpose of this feature
    was to enable optimizations, but I don't thing it was. I think it was
    primarily intended to motivate (but not, unfortunately, mandate)
    warnings when the undefined behavior is predictable at compile time.

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

    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 04 May 2025 07:31:11 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    [...]
    Also having just one form of loop with pre-condition strikes me as
    more elegant. Since elegance is strongly subjective, I have no
    logical arguments in support of me feelings.

    In a recent posting I gave some statistics about the three different
    kinds of looping controls (while,for,do/while). do/while loops were
    almost 20% of all loops, and more than a quarter of the two kinds of
    loops other than for(). Besides being a more pragmatic choice, I
    think having the three kinds of loops be distinct in the language is
    a better choice, because how we think of the different kinds of loop
    is different, and it's helpful to have those differences be readily
    apparent in the program, rather than needing to reconstruct them by
    looking at code around the loop control fragment.

    That sounds like misunderstanding.
    I didn't suggest one loop construct. I suggested two constructs: for()
    for loops with pre-condition and do-while for loops with post-condition.

    Yes, I did misunderstand you. The alternative meaning didn't occur
    to me. I see it now.

    The same posting I mentioned in the previous response gave while()
    loops as occurring more than for() and do/while() combined. I
    conceptualize for() loops quite differently than while() loops, and
    vice versa. By analogy to the only-two-kinds-of-loops suggestion,
    the language could forego switch() and provide only if()/else. To
    me, neither of those what-might-be-called-simplifications seems like
    a good trade. Have you asked other people to see what their
    reactions are?

    Incidentally, a language change to C was once proposed, so that
    a do/while could also have an expression after the while().
    Note that this change is backwards compatible with C as it is,
    because a simple semicolon after while() is an empty statement.
    Adopting this proposal would mean that the language would allow,
    for example

    do {
    // this part will always be done at least once
    // and once more for each time 'condition' is true
    } while( condition ){
    // this part will be done zero or more times
    }

    allowing a convenient way of writing "loop-and-a-half" type
    loops. Do you have any reaction to this idea? Suppose
    the just plain while() style were eliminated, so ordinary
    while() loops would instead be written as

    do ; while( condition ){
    // body of while loop
    }

    Is that better or worse than having a separate while() statement?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Muttley@dastardlyhq.com on Sun May 11 17:59:31 2025
    Muttley@dastardlyhq.com writes:

    On Sat, 10 May 2025 14:29:50 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:

    Muttley@dastardlyhq.com writes:

    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:

    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the

    Isn't it?

    Where "static" means local to a module the words
    "local","module","limit" spring to mind which are far closer to
    the intended meaning. Reusing "static" seems somewhat perverse
    IMO.

    The use I'm talking about here may be illustrated as follows:

    double
    average( double values[ static 10 ] ){
    double total = 0;
    for( int i = 0; i < 10; i++ ){
    total += values[i];
    }
    return total / 10;
    }

    What word would you suggest to be used in place of 'static'
    there?

    If I knew what the hell it was supposed to do I'd tell you.

    When you find out please post your suggested replacement.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Sun May 11 18:15:33 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [...]

    It's main potential usefulness is not in the definition of the
    function, but in calls to the function. If the calls occur in
    a different translation unit from the definition, the compiler
    does not have the needed information.

    It does if the visible declaration has the same information.

    Like 'restrict', parameter array length information, specified by
    way of 'static', is ignored outside of function definitions. As
    was intended (with 'restrict' also).

    Furthermore, and also like 'restrict', there is no general
    way to verify at compile time that the stipulated condition
    holds.

    Considering the above, it's better to observe the status quo, and
    leave any diagnostics up to the discretion of the implementation,
    rather than try to retrofit an incompatible change that would
    make an infringement be a constraint violation that can't be
    checked anyway.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Tim Rentsch on Mon May 12 00:07:15 2025
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [...]

    It's main potential usefulness is not in the definition of the
    function, but in calls to the function. If the calls occur in
    a different translation unit from the definition, the compiler
    does not have the needed information.

    It does if the visible declaration has the same information.

    Like 'restrict', parameter array length information, specified by
    way of 'static', is ignored outside of function definitions. As
    was intended (with 'restrict' also).

    ? What "static" does when applied to an array parameter's length is to
    render the behavior undefined if the function is called with a pointer
    that points to an array that is shorter than the specified length. Are
    you saying that it has no such effect except for inside the function definition? I'm not sure what that would even mean - is the behavior
    undefined only for recursive calls to the function?

    Furthermore, and also like 'restrict', there is no general
    way to verify at compile time that the stipulated condition
    holds.

    As I already mentioned, if such verification could have been generally possible, it should have been a constraint violation. Because it is not possible in general, but only in certain cases, making the behavior
    undefined is the best that can be done. Doing so encourages
    implementations to generate a diagnostic when those cases do come up.

    Considering the above, it's better to observe the status quo, and
    leave any diagnostics up to the discretion of the implementation,
    rather than try to retrofit an incompatible change that would
    make an infringement be a constraint violation that can't be
    checked anyway.
    I was not suggesting any change to the status quo, only explaining why
    the status quo is what it is.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Michael S on Sun May 11 23:48:26 2025
    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 06 May 2025 05:59:20 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Wed, 16 Apr 2025 14:09:44 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    bart <bc@freeuk.com> writes:

    On 15/04/2025 20:07, Scott Lurndal wrote:


    Let's look at that C again:

    for (int i = 1; i < 11; i += 1) # 15 tokens; C

    for(i = 1; i++ <= 10;)

    I'd reject this code during review.
    Hopefully, you too.

    I'm curious to know the basis for your reaction. What about the
    code would prompt your judgment to reject it? Is it just a
    specific reaction, or does it represent some more general pattern
    (and if so then what more general pattern)?

    First and foremost it was tongue-in-cheek reaction to the article
    that Scott posted 2-3 minutes after the article that I was
    reacting to.

    I took the posting at face value.

    At the next level, it is true that if I do detailed code review
    (which I almost never do) I would indeed reject this code. The
    first and sufficient reason is that the code looks superficially
    similar to very common idiom, but significantly differs in
    behavior. An additional reason is that post-increment operator is
    generally harder to reason about than almost any other C operator,
    esp. so when used as part of comparison, so, IMHO, readable code
    should limit use of post-increment to very common idioms (or
    altogether avoid it). The third reason, related to the first two
    is that behavior of this loop is way too surprising.

    I see your comments as saying a few different things. My intention
    below is to give fair paraphrases; please voice an objection if you
    feel that this was not done.

    One: the given code syntactically resembles a common code pattern
    but has quite different semantics.

    Two: postfix ++ is harder to understand than other operators.

    Three: the combination of postfix ++ and a comparison operator
    is even harder to understand than its simpler uses.

    Four: postfix ++ should never be used except in familiar and
    commonly used patterns.

    Five: the effect of the for() controlling statement is not what
    most readers (selected from experienced developers) would expect.

    Would you say that these statements above give a fair restatement
    of your comments? Or have I missed or misrepresented something?

    Taking the above points as fair restatements, here are my reactions.

    Point one is never a reason to reject a given code fragment. If a
    piece of code intends to express a particular semantics, but happens
    to resemble a more common pattern that has different semantics, that
    by itself is never reason to reject the code under consideration.
    It's reasonable to say that a comment be given to alert a reader to
    an unobvious difference, but not to reject the code outright.

    Point two is true at least insofar as postfix ++ is more complicated
    than simple arithmetic operators like + and *. The same could be
    said of all operators with side-effects. Do you think postfix ++ is
    more complicated than postfix --? Both postfix ++ and postfix --
    appear in common and familiar patterns. I don't think the given
    code fragment should be rejected solely for using a postfix ++.

    Point three is certainly true, at least in comparison with using
    postfix ++ by itself. But I don't see why you think using the
    result with a comparison operator is more complicated than other
    compound uses. Consider these code fragments, not too difficult
    I think for most developers:

    *lines++ = next_input_line();
    while( i-- > 0 ) ...

    I don't see either of these examples as being too different than the
    condition 'i++ <= 10'. Is your only reason for rejecting the given
    code is that you find it unfamiliar?

    Point four seems to say explicitly what came up implicitly in point
    three. I think a lot of people follow a similar rule, one not
    necessarily restricted to postfix ++ or other less-used patterns.
    As a guideline I think that's okay; as an inviolate rule I think
    it's wrong. Developers should always write code in a way that they
    feel best expresses their intentions, whether that way is an old
    way or a new way. A second consideration is that, if code is only
    ever written in old familiar ways, then newer and better ways will
    never be discovered. Taking a conservative stance is fine most of
    the time; always vetoing a new form just because it is new is
    overdoing it.

    Point five seems like simply another way of saying, in a more
    generic way, the view raised in point four, or maybe points four
    and one in combination. Same response as was given above.

    I might summarize my reactions as follows. I am philosophically
    opposed to the idea that code should only ever be written in common
    forms or that it should be "dumbed down" for less sophisticated
    developers. An advantage of C is that it is small enough so any
    experienced developer can understand all of it. If someone isn't
    capable of handling basic expressions like those under discussion
    here then they just shouldn't be programming.

    Incidentally, I might agree with you in the sense that I think
    the semantics for the code being considered can be effected using
    code that is either more familiar, or easier to follow than how
    it was written above, or both. If that is your actual underlying
    objection then I think we are pretty much on the same page. My
    response above though gives reactions to what was written, not
    what I imagined you were thinking.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@DastardlyHQ.org@21:1/5 to All on Mon May 12 10:11:43 2025
    On Sun, 11 May 2025 17:59:31 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wibbled:
    Muttley@dastardlyhq.com writes:

    On Sat, 10 May 2025 14:29:50 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:

    Muttley@dastardlyhq.com writes:

    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:

    never necessary). Also it isn't easy to think of a good substitute
    word that might be given for this use of 'static', so maybe the

    Isn't it?

    Where "static" means local to a module the words
    "local","module","limit" spring to mind which are far closer to
    the intended meaning. Reusing "static" seems somewhat perverse
    IMO.

    The use I'm talking about here may be illustrated as follows:

    double
    average( double values[ static 10 ] ){
    double total = 0;
    for( int i = 0; i < 10; i++ ){
    total += values[i];
    }
    return total / 10;
    }

    What word would you suggest to be used in place of 'static'
    there?

    If I knew what the hell it was supposed to do I'd tell you.

    When you find out please post your suggested replacement.

    average( double values[ pointless_keyword 10 ] ){

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Mon May 12 16:18:19 2025
    On Sun, 11 May 2025 17:30:14 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sat, 10 May 2025 06:43:38 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Sun, 04 May 2025 07:31:11 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    [...]
    Also having just one form of loop with pre-condition strikes me as
    more elegant. Since elegance is strongly subjective, I have no
    logical arguments in support of me feelings.

    In a recent posting I gave some statistics about the three
    different kinds of looping controls (while,for,do/while).
    do/while loops were almost 20% of all loops, and more than a
    quarter of the two kinds of loops other than for(). Besides being
    a more pragmatic choice, I think having the three kinds of loops
    be distinct in the language is a better choice, because how we
    think of the different kinds of loop is different, and it's
    helpful to have those differences be readily apparent in the
    program, rather than needing to reconstruct them by looking at
    code around the loop control fragment.

    That sounds like misunderstanding.
    I didn't suggest one loop construct. I suggested two constructs:
    for() for loops with pre-condition and do-while for loops with post-condition.

    Yes, I did misunderstand you. The alternative meaning didn't occur
    to me. I see it now.

    The same posting I mentioned in the previous response gave while()
    loops as occurring more than for() and do/while() combined. I
    conceptualize for() loops quite differently than while() loops, and
    vice versa. By analogy to the only-two-kinds-of-loops suggestion,
    the language could forego switch() and provide only if()/else.

    I don't see it as the same or similar. if we compare switch() with if/ if-else/else chain it's clear that switch() helps DRY which is very
    important (most important?) principle of programming.
    OTOH, while() does not help anything relatively to for().

    To
    me, neither of those what-might-be-called-simplifications seems like
    a good trade. Have you asked other people to see what their
    reactions are?

    Incidentally, a language change to C was once proposed, so that
    a do/while could also have an expression after the while().
    Note that this change is backwards compatible with C as it is,
    because a simple semicolon after while() is an empty statement.
    Adopting this proposal would mean that the language would allow,
    for example

    do {
    // this part will always be done at least once
    // and once more for each time 'condition' is true
    } while( condition ){
    // this part will be done zero or more times
    }


    That is an interesting idea.
    Loops like those do happen quite often in my practice. Of course, if
    have to code them as
    for (;;) {
    ...
    if (!condition)
    break;
    ...
    }

    I find it probable that proposed extended do-while is somewhat easier
    for reader, if for nothing else then because positive logical
    conditions tend to be easier to grasp then negative conditions.

    allowing a convenient way of writing "loop-and-a-half" type
    loops. Do you have any reaction to this idea? Suppose
    the just plain while() style were eliminated, so ordinary
    while() loops would instead be written as

    do ; while( condition ){
    // body of while loop
    }

    Is that better or worse than having a separate while() statement?

    I don't think that it's the same. for(;cond;) alternative is less
    clumsy and is not even longer than while(cond) in # of characters.

    If we compare to newer languages, authors of Go went one step further
    and completely gave up on loop with post-condition. Probably for early
    70s that was too radical. May be, it is still too radical now. I didn't
    write a lot of Go, so can't tell.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Muttley@DastardlyHQ.org on Mon May 12 17:09:07 2025
    On Mon, 12 May 2025 10:11:43 -0000 (UTC)
    Muttley@DastardlyHQ.org wrote:

    On Sun, 11 May 2025 17:59:31 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wibbled:
    Muttley@dastardlyhq.com writes:



    If I knew what the hell it was supposed to do I'd tell you.

    When you find out please post your suggested replacement.

    average( double values[ pointless_keyword 10 ] ){


    Richard Heathfield recently proposed newfangled_gibberish :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Mon May 12 07:19:00 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [...]

    It's main potential usefulness is not in the definition of the
    function, but in calls to the function. If the calls occur in
    a different translation unit from the definition, the compiler
    does not have the needed information.

    It does if the visible declaration has the same information.

    Like 'restrict', parameter array length information, specified by
    way of 'static', is ignored outside of function definitions. As
    was intended (with 'restrict' also).

    I think that by "is ignored", you mean that compilers are not
    required to pay attention to it. [...]

    I mean it has no effect on program semantics.

    It affects whether a program has defined or undefined behavior.
    (Yes, a conforming compiler could ignore it.)

    Please read again what I said: parameter array length information,
    specified by way of 'static', is ignored _outside of function
    definitions_.

    Furthermore, and also like 'restrict', there is no general
    way to verify at compile time that the stipulated condition
    holds.

    Right, but that doesn't prevent implementations from issuing
    useful warnings when it can determine that the stipulated
    condition does not hold.

    True, but in many cases they can't, because that information
    is not part of the function's type and so often it is not
    present.

    Why would it not be present?

    If you mean that someone might use `[static N]` in a function's
    definition but not in a declaration, sure, but I would always
    make sure they match as closely as possible. [...]

    It strikes me that you have a rather self-centered view of the
    world. The vast majority of all C code is written by people other
    than yourself.

    Considering the above, it's better to observe the status quo, and
    leave any diagnostics up to the discretion of the implementation,
    rather than try to retrofit an incompatible change that would
    make an infringement be a constraint violation that can't be
    checked anyway.

    Observing the status quo is better than what, exactly?

    Better than than trying to retrofit an incompatible change that
    would make an infringement be a constraint violation that can't
    be checked anyway.

    And as you seem to have agreed, nobody suggested that. Were we
    supposed to guess what it's better than? Or did I miss something?

    There was no reason to guess, because it was written in plain
    English in the earlier posting.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Tim Rentsch on Mon May 12 15:34:51 2025
    On 12/05/2025 15:19, Tim Rentsch wrote:
    It strikes me that you have a rather self-centered view of the
    world.

    So do you. So do I. So does everybody else. Your eyes are at the
    precise centre of your observable universe.

    The vast majority of all C code is written by people other
    than yourself.

    And the vast majority of those people are entitled to express
    their opinion, just as you are entitled to express yours and
    Keith is entitled to express his.

    I hope I'm wrong, but it strikes me that you're trying to pick a
    fight with Keith. No doubt you have your reasons, but I would
    have expected better from a man of your calibre.

    Hey! You do you. What would I know? And it really is none of my
    business, which is precisely why, back in the day, grown-ups who
    wanted to lock horns would take it to email.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Mon May 12 00:16:34 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [...]

    It's main potential usefulness is not in the definition of the
    function, but in calls to the function. If the calls occur in
    a different translation unit from the definition, the compiler
    does not have the needed information.

    It does if the visible declaration has the same information.

    Like 'restrict', parameter array length information, specified by
    way of 'static', is ignored outside of function definitions. As
    was intended (with 'restrict' also).

    I think that by "is ignored", you mean that compilers are not
    required to pay attention to it. [...]

    I mean it has no effect on program semantics.

    Furthermore, and also like 'restrict', there is no general
    way to verify at compile time that the stipulated condition
    holds.

    Right, but that doesn't prevent implementations from issuing
    useful warnings when it can determine that the stipulated
    condition does not hold.

    True, but in many cases they can't, because that information
    is not part of the function's type and so often it is not
    present.

    Considering the above, it's better to observe the status quo, and
    leave any diagnostics up to the discretion of the implementation,
    rather than try to retrofit an incompatible change that would
    make an infringement be a constraint violation that can't be
    checked anyway.

    Observing the status quo is better than what, exactly?

    Better than than trying to retrofit an incompatible change that
    would make an infringement be a constraint violation that can't
    be checked anyway.

    The status quo is that the "[static N]" syntax has been in the
    language since C99, and programmers and implementations are free
    to take advantage of it. I don't recall anyone in this thread
    proposing a change to that.

    Neither do I, nor did I mean to imply that anyone had.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to James Kuyper on Mon May 12 00:43:22 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [...]

    It's main potential usefulness is not in the definition of the
    function, but in calls to the function. If the calls occur in
    a different translation unit from the definition, the compiler
    does not have the needed information.

    It does if the visible declaration has the same information.

    Like 'restrict', parameter array length information, specified by
    way of 'static', is ignored outside of function definitions. As
    was intended (with 'restrict' also).

    ? What "static" does when applied to an array parameter's length is to
    render the behavior undefined if the function is called with a pointer
    that points to an array that is shorter than the specified length. Are
    you saying that it has no such effect except for inside the function definition? I'm not sure what that would even mean - is the behavior undefined only for recursive calls to the function?

    What I mean is that such uses of 'static' have no effect when
    used in declarations that are not part of a definition.

    Furthermore, and also like 'restrict', there is no general
    way to verify at compile time that the stipulated condition
    holds.

    As I already mentioned, if such verification could have been
    generally possible, it should have been a constraint violation.
    Because it is not possible in general, but only in certain cases,
    making the behavior undefined is the best that can be done. Doing
    so encourages implementations to generate a diagnostic when those
    cases do come up.

    It isn't just that checking the condition cannot be done in general.
    To be reliable the parameter length information would need to be
    part of the function's type. That has implications for type
    compatibility and also for the types of pointers-to-function. And
    it would mean that removing a 'static' array length specification on
    a function definition would necessitate also changing the functions declarations, plus any affected pointers-to-function. Not worth it,
    even if in theory it were doable.

    Considering the above, it's better to observe the status quo, and
    leave any diagnostics up to the discretion of the implementation,
    rather than try to retrofit an incompatible change that would
    make an infringement be a constraint violation that can't be
    checked anyway.

    I was not suggesting any change to the status quo, [...]

    I didn't mean to imply you had.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to James Kuyper on Mon May 12 17:08:32 2025
    On 11/05/2025 23:43, James Kuyper wrote:
    On 5/11/25 06:02, David Brown wrote:
    On 11/05/2025 10:21, Muttley@dastardlyhq.com wrote:
    On Sat, 10 May 2025 14:29:50 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
    ...
    The use I'm talking about here may be illustrated as follows:

    double
    average( double values[ static 10 ] ){
    double total = 0;
    for( int i = 0; i < 10; i++ ){
    total += values[i];
    }
    return total / 10;
    }

    What word would you suggest to be used in place of 'static'
    there?

    If I knew what the hell it was supposed to do I'd tell you.


    Using "static" inside array parameters is, IME, extremely rare. It was
    added in C99, and tells the compiler that whenever "average" is called,
    the "values" parameter points to an array of at least 10 doubles. It

    More precisely, it makes it undefined behavior for values to point to an array of less than 10 doubles.


    The wording of the C standard (C11, as that's what I have open at the
    moment) is :

    """
    If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the
    corresponding actual argument shall provide access to the first element
    of an array with at least as many elements as specified by the size
    expression.
    """

    I think my wording is at least as "precise" as yours. The potential UB
    here comes from violating the "shall" requirement.


    does not affect the signature of the function or compatibility with any
    other declarations, and is AFAIK rarely checked by compilers.

    I'd have preferred it if violating that requirement was a constraint violation, but it can't be, because there are many cases where a
    compiler cannot be sure how long the array is that a pointer points at.

    Indeed. I am also a big fan, in general, of making mistakes in code
    into compiler errors when possible - I'd rather the compiler found my
    bugs than leave it to run-time testing!

    However, the fact that the behavior is undefined justifies a compiler reacting to the case when it can be sure that the requirement will be violated.

    Unfortunately, that is not quite true. A C programmer is free to write whatever nonsense and run-time UB they like, as long as that UB is not
    actually "executed". So a compiler, if it aims to be conforming and to
    accept code with well-defined behaviour, has to be sure that the bad
    code in question would inevitably be executed before it is justified in rejecting the code with an error.

    (When the user has asked for non-conforming behaviour, or additional
    analysis and warnings, then of course the compiler can complain when it
    sees a potential error. Such warnings are almost always a good idea.)

    That's the main reason I like this feature, and dislike
    compilers that fail to take advantage of that opportunity. I never
    considered it to be about efficiency, though there are cases where it
    can result in more efficient code.


    The C99 rational says it was added for efficiency reasons. But often efficiency and static error analysis go together - the more information
    the compiler has, the better it is at both tasks. And I agree with your attitude of emphasising the static error analysis as being more
    important than the efficiency considerations in most cases.

    In an example like the one above, it is completely useless for
    compilation - it tells the compiler nothing that it does not already
    know. An optimising compiler will see that you are accessing values[0]
    to values[9], and if it can get better results through vectorising,
    prefetching, etc., then it will do so. (You can argue that the "static
    10" is still useful as an indicator to human readers, but I am not
    convinced of that.)

    It's main potential usefulness is not in the definition of the function,
    but in calls to the function. If the calls occur in a different
    translation unit from the definition, the compiler does not have the
    needed information.

    That is the case for its potential usefulness in static error checking,
    but not the case for its potential usefulness in optimisation.

    I am not convinced that it is actually useful as an error checking
    mechanism in many situations. In a lot of code, you simply don't have a compile-time checkable array sizes - you have a pointer, and a run-time variable for the size. When you are calling your function with a
    "static" array size, the compiler does not have any way to check your
    pointer for correctness.

    This is why some compilers and other verification tools have extensions
    that can do more than "static" array parameters can - gcc's "access"
    attribute and "object size" builtins are examples.

    Still, even if it only helps occasionally, that's better than no help at
    all.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Keith Thompson on Mon May 12 17:18:06 2025
    On 12/05/2025 11:27, Keith Thompson wrote:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    [...]
    It isn't just that checking the condition cannot be done in general.
    To be reliable the parameter length information would need to be
    part of the function's type. That has implications for type
    compatibility and also for the types of pointers-to-function. And
    it would mean that removing a 'static' array length specification on
    a function definition would necessitate also changing the functions
    declarations, plus any affected pointers-to-function. Not worth it,
    even if in theory it were doable.
    [...]

    In my opinion, keeping a function's definition and declarations
    consistent is absolutely worth it, even if the language might not
    require it.


    Sure. If gcc had a warning enforcing such consistency, I would
    definitely use it.

    But not all C programmers are as pedantic about consistency between a
    function declaration and definition. It is not uncommon to be
    inconsistent about the names of parameters (or even if the parameters
    have names at all), or mixing array-style parameters and pointer-style parameters.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Keith Thompson on Mon May 12 17:24:16 2025
    On 12/05/2025 11:23, Keith Thompson wrote:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [...]
    It's main potential usefulness is not in the definition of the
    function, but in calls to the function. If the calls occur in
    a different translation unit from the definition, the compiler
    does not have the needed information.

    It does if the visible declaration has the same information.

    Like 'restrict', parameter array length information, specified by
    way of 'static', is ignored outside of function definitions. As
    was intended (with 'restrict' also).

    I think that by "is ignored", you mean that compilers are not
    required to pay attention to it. [...]

    I mean it has no effect on program semantics.

    It affects whether a program has defined or undefined behavior.
    (Yes, a conforming compiler could ignore it.)


    The UB is actually at the function call site, rather than in the
    function itself. Thus adding a "static N" to the function definition
    can change the semantics of the call site:

    // file1.c
    extern int foo(int * p);

    int bar(void) {
    int xs[4];
    return foo(xs);
    }

    // file2.c
    #define N 4

    int foo(int p[static N]) {
    return 42;
    }



    Changing "N" to 5 will render the call in file1.c undefined behaviour,
    without having any semantic effect on the function definition in file2.c

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Tim Rentsch on Mon May 12 19:53:14 2025
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    [...]
    It isn't just that checking the condition cannot be done in general.
    To be reliable the parameter length information would need to be
    part of the function's type.

    The problem is much deeper than that. The same pointer can point to
    different arrays, or different positions in the same array, during
    different passes through the same line of code. Some of those would
    violate this rule, others would not. I don't see how violating such a
    rule could ever be made a constraint violation. The violation would have
    to be detected in the code that sets the pointer's value before passing
    it, directly or indirectly, to the function with a "static" array length.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Tim Rentsch on Mon May 12 19:04:20 2025
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    [...]

    It's main potential usefulness is not in the definition of the
    function, but in calls to the function. If the calls occur in
    a different translation unit from the definition, the compiler
    does not have the needed information.

    It does if the visible declaration has the same information.

    Like 'restrict', parameter array length information, specified by
    way of 'static', is ignored outside of function definitions. As
    was intended (with 'restrict' also).

    ? What "static" does when applied to an array parameter's length is to
    render the behavior undefined if the function is called with a pointer
    that points to an array that is shorter than the specified length. Are
    you saying that it has no such effect except for inside the function
    definition? I'm not sure what that would even mean - is the behavior
    undefined only for recursive calls to the function?

    What I mean is that such uses of 'static' have no effect when
    used in declarations that are not part of a definition.

    I need to correct myself. This statement is simply wrong. Giving a
    parameter declarator a 'static' length specification, as part of any
    function declaration whatsoever, has the same effect as it would if
    it had been given on the function definition. To present an example,
    if we have three source files, x.c, y.c, and z.c, with

    /* x.c */
    int foo( int v[] );

    int
    example(){
    return foo( 0 );
    }


    /* y.c */
    int
    foo( int v[] ){
    return v ? v[0] : -1;
    }


    /* z.c */
    int foo( int v[ static 1 ] );


    then because of the declaration of foo() in z.c, the call to foo()
    in x.c has undefined behavior, because a "shall" requirement is
    violated by passing a null pointer for parameter v, which must
    point to an array with at least one element.

    As best I can determine the description of how 'static' works in
    such cases has not changed since its original introduction in C99
    up to the present.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Richard Heathfield on Mon May 12 22:42:30 2025
    Richard Heathfield <rjh@cpax.org.uk> writes:

    On 12/05/2025 15:19, Tim Rentsch wrote:

    It strikes me that you have a rather self-centered view of the
    world.

    So do you. So do I. So does everybody else. Your eyes are at the
    precise centre of your observable universe.

    I think you have misunderstood me. Certainly I would say you
    have your own views and opinions, and many of them strongly
    held. But that isn't the same as what I mean by self-centered.
    I don't think of you as being self-centered in the same sense
    as what I was trying to say above.

    (At some later time I may have more to say about your other
    comments, but it seemed important to respond to this part
    more promptly.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Heathfield@21:1/5 to Tim Rentsch on Tue May 13 07:31:06 2025
    On 13/05/2025 06:42, Tim Rentsch wrote:
    Richard Heathfield <rjh@cpax.org.uk> writes:

    On 12/05/2025 15:19, Tim Rentsch wrote:

    It strikes me that you have a rather self-centered view of the
    world.

    So do you. So do I. So does everybody else. Your eyes are at the
    precise centre of your observable universe.

    I think you have misunderstood me.

    I hope so, because the alternative is unpalatable.

    (At some later time I may have more to say about your other
    comments, but it seemed important to respond to this part
    more promptly.)

    I think you chose the least important part to respond to, so
    maybe you have misunderstood me, too.

    I was trying to defend an honourable man from what seemed to me
    to be an unfair and unnecessarily unkind observation. The
    paragraph you quote above acknowledges that in some literal sense
    your accusation of self-centredness is accurate, and so implies
    by omission that the more metaphorical sense that I think you
    intended is /not/ accurate.

    A fine distinction, some might say. But that's what the other
    paragraphs were for.

    Keith's a big lad. He doesn't need me to defend him. But neither
    does he need you to attack him.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to James Kuyper on Mon May 12 23:03:59 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    [...]

    It isn't just that checking the condition cannot be done in general.
    To be reliable the parameter length information would need to be
    part of the function's type.

    The problem is much deeper than that. The same pointer can point
    to different arrays, or different positions in the same array,
    during different passes through the same line of code. Some of
    those would violate this rule, others would not. I don't see how
    violating such a rule could ever be made a constraint violation.
    [...]

    An implementation could issue a diagnostic whenever it could
    determine that the requirement had been violated, and also
    whenever it could not establish that the requirement was
    satisfied. A message like

    "this call to function foo() might not supply a large enough
    array to satisfy an array static length requirement".

    would, I think, satisfy the letter of the rule that any constraint
    violation must result in at least one diagnostic being produced.

    Granted, I think most people would find such behavior more
    annoying than useful, but it does seem to be a way to meet the
    stipulations for constraint violations, in letter even if not in
    spirit.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Keith Thompson on Tue May 13 12:41:22 2025
    On 12/05/2025 22:38, Keith Thompson wrote:
    David Brown <david.brown@hesbynett.no> writes:
    [...]
    I am not convinced that it is actually useful as an error checking
    mechanism in many situations. In a lot of code, you simply don't have
    a compile-time checkable array sizes - you have a pointer, and a
    run-time variable for the size. When you are calling your function
    with a "static" array size, the compiler does not have any way to
    check your pointer for correctness.
    [...]

    Using [static N] in an array parameter declaration also requires the
    caller to pass a non-NULL pointer. If I want to tell the compiler
    that an argument must not be a NULL pointer, I can write:

    void func(int arg[static 1]);

    func(NULL) then has undefined behavior, and a compiler is likely
    to warn about it. (Of course some UB will be missed if the compiler
    can't detect it.)


    Certainly compilers are more likely to be able to differentiate between
    null values and non-null values, than between pointers to different
    lengths of data. So yes, this can be a useful check.

    For my own use, I dislike this syntax - if I want a pointer to an int, I
    prefer to give the parameter the form pointer to an int. The array form
    might mean the same thing to the compiler, but it does not give the same clarity to the human programmer. And if I want extra checking on this
    kind of thing, I use gcc attributes. (Of course not all programmers can
    do that, or want to do that, in their code.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Tim Rentsch on Tue May 13 15:57:00 2025
    On 12.05.2025 02:30, Tim Rentsch wrote:
    [...]

    Incidentally, a language change to C was once proposed, so that
    a do/while could also have an expression after the while().
    Note that this change is backwards compatible with C as it is,
    because a simple semicolon after while() is an empty statement.
    Adopting this proposal would mean that the language would allow,
    for example

    do {
    // this part will always be done at least once
    // and once more for each time 'condition' is true
    } while( condition ){
    // this part will be done zero or more times
    }

    allowing a convenient way of writing "loop-and-a-half" type
    loops. [...]

    This is an interesting proposal.

    When was it suggested, and what is the decision state?

    What were the arguments, pros and cons?

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Richard Heathfield on Tue May 13 09:30:55 2025
    Richard Heathfield <rjh@cpax.org.uk> writes:

    On 12/05/2025 15:19, Tim Rentsch wrote:

    It strikes me that you have a rather self-centered view of the
    world.

    So do you. So do I. So does everybody else. Your eyes are at the
    precise centre of your observable universe.

    The vast majority of all C code is written by people other
    than yourself.

    And the vast majority of those people are entitled to express their
    opinion, just as you are entitled to express yours and Keith is
    entitled to express his.

    I hope I'm wrong, but it strikes me that you're trying to pick a fight
    with Keith. No doubt you have your reasons, but I would have expected
    better from a man of your calibre.

    I have two more short comments to add.

    One, I have no desire to start a fight, or engage in one.

    Two, I mean to observe a distinction between self-centered and
    selfish. These two words mean different things.

    Also let me add, parenthetically, in most cases I consider it
    bad manners to discuss a third party in a public forum. (That
    is not meant as a criticism of your commment, which I take to
    be a sincere interest in everyone's well being.) I don't mind
    responding to your comments but I don't expect to say anything
    specifically about Keith.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Richard Heathfield on Tue May 13 22:28:25 2025
    On 12.05.2025 16:34, Richard Heathfield wrote:
    On 12/05/2025 15:19, Tim Rentsch wrote:
    [...]

    [...]

    I hope I'm wrong, but it strikes me that you're trying to pick a fight
    with Keith. No doubt you have your reasons, but I would have expected
    better from a man of your calibre.

    Hey! You do you. What would I know? And it really is none of my
    business, which is precisely why, back in the day, grown-ups who wanted
    to lock horns would take it to email.

    It's a social and psychological theme; when a topic gets in a personal direction and getting disrespectful and that is publicly exchanged the
    response (defense or counterstrike) is likely also continued where the
    "attack" had taken place. That bickering doesn't go ad infinitum but
    it at least leads to long and deep threads (with little value). If the disputants have a strong backbone - any many here have - it's getting difficult. But I sense occasional attempts to soothe the situations
    and thus interrupt the [perceived] endless process.

    f() { g(); }
    g() { f(); }

    without an appropriate 'if' will not be good. An alternative is to not
    start that process by f() or g() in the first place. - Just an attempt
    to have this meta-topic getting a bit "C"-like. Feel free to ignore it.
    :-p

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to David Brown on Tue May 13 23:16:49 2025
    On 12.05.2025 17:08, David Brown wrote:
    On 11/05/2025 23:43, James Kuyper wrote:
    [...]

    More precisely, it makes it undefined behavior for values to point to an
    array of less than 10 doubles.

    The wording of the C standard (C11, as that's what I have open at the
    moment) is :

    """
    If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element
    of an array with at least as many elements as specified by the size expression.
    """

    Oh! - This is somewhat surprising to me. - When I first read about
    the "arr[static N]" I assumed that it would be possible to pass any
    sub-array, say "&arr[8]" (or "arr+8") as long as it's large enough
    to still have N elements from the starting point, but the quote says
    explicitly "access to the _first_ element of an array" (which I'd
    interpret as "&arr[0]" (or "arr"). - Unless I misinterpreted that;
    what would be the reason for that?

    Janis

    [...]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Tue May 13 15:10:56 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:

    On 12.05.2025 17:08, David Brown wrote:

    On 11/05/2025 23:43, James Kuyper wrote:

    [...]

    More precisely, it makes it undefined behavior for values to point to an >>>> array of less than 10 doubles.

    The wording of the C standard (C11, as that's what I have open at the
    moment) is :

    """
    If the keyword static also appears within the [ and ] of the array type
    derivation, then for each call to the function, the value of the
    corresponding actual argument shall provide access to the first element
    of an array with at least as many elements as specified by the size
    expression.
    """

    Oh! - This is somewhat surprising to me. - When I first read about
    the "arr[static N]" I assumed that it would be possible to pass any
    sub-array, say "&arr[8]" (or "arr+8") as long as it's large enough
    to still have N elements from the starting point, but the quote says
    explicitly "access to the _first_ element of an array" (which I'd
    interpret as "&arr[0]" (or "arr"). - Unless I misinterpreted that;
    what would be the reason for that?

    My personal interpretation is that this:

    void func(int arr[static 5]) {
    }

    int main(void) {
    int arr[10];
    func(arr+5); // OK
    // func(arr+6); // UB
    }

    is valid, because, for example, the last 5 elements of a 10-element
    array object can be treated as a 5-element array object. gcc seems
    to agree, based on the fact that it warns about func(arr+6) but
    not about func(arr+5).

    This is a fundamental part of my mental model of C, but in a few
    minutes of searching I wasn't able to find explicit wording in the
    standard that supports it.

    In N1570, 6.7.6.3 p7.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Tue May 13 18:38:32 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [...]

    My personal interpretation is that this:

    void func(int arr[static 5]) {
    }

    int main(void) {
    int arr[10];
    func(arr+5); // OK
    // func(arr+6); // UB
    }

    is valid, because, for example, the last 5 elements of a 10-element
    array object can be treated as a 5-element array object. gcc seems
    to agree, based on the fact that it warns about func(arr+6) but
    not about func(arr+5).

    This is a fundamental part of my mental model of C, but in a few
    minutes of searching I wasn't able to find explicit wording in the
    standard that supports it.

    In N1570, 6.7.6.3 p7.

    Did you mean to imply that that paragraph supports (or refutes) my
    statement? [...]

    No. I posted the reference to say that the cited paragraph supports
    the conclusion that 'func(arr+6)' is undefined behavior.

    """
    A declaration of a parameter as ??array of _type_?? shall
    be adjusted to ??qualified pointer to _type_??, where the
    type qualifiers (if any) are those specified within the [ and ]
    of the array type derivation. If the keyword static also appears
    within the [ and ] of the array type derivation, then for each call
    to the function, the value of the corresponding actual argument
    shall provide access to the first element of an array with at least
    as many elements as specified by the size expression.
    """

    The question is whether, for example, the last 5 elements of a
    10-element array object can be treated as a 5-element array object.
    If someone can cite wording in the standard that answers that
    question, I'd appreciate it. (I'll be happier if the answer is yes.)

    To me it seems obvious that 6.7.6.3 p7 is meant to cover the
    case of 'func(arr+6)' as being undefined behavior.

    Note that 6.7.6.3 p7 doesn't say "array object", it says just
    "array". I believe the choice of wording is neither an accident nor
    an oversight.

    Looking into this a bit more, I realize that the question doesn't
    matter if there's no "static" keyword between the [ and ]. In that
    case, the parameter is of pointer type, and the description of
    pointer arithmetic (N1570 6.5.6p8) explicitly allows the pointer
    to point to the i-th element of an array object. The wording for
    [static N] is the only place I've seen (so far) that specifically
    refers to the *first* element of an array object, raising the
    question of whether a subobject of an array object is itself an
    array object.

    Again, not an array object, just an array.

    This might just be some slightly sloppy wording that was
    introduced in C99 and never corrected.

    I draw the opposite conclusion. The wording of 6.7.6.3 p7 was
    carefully chosen so that it would cover cases like 'func(arr+6)'.

    For example, given this code:

    ```
    void without_static(int arr[]) {
    (void)arr[4];
    }

    void with_static(int arr[static 5]) {
    (void)arr[4];
    }

    int main(void) {
    int arr[10] = { 0 };
    without_static(arr+5);
    with_static(arr+5);
    }
    ```

    there's no problem with the call `without_static(arr+5)`, but the
    call `with_static(arr+5)` has defined behavior if and only if the
    last 5 elements of a 10-element array object can be treated as a
    5-element array object.

    That isn't what the C standard says. It just says "array", not
    "array object".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Keith Thompson on Tue May 13 23:54:36 2025
    On 5/13/25 22:37, Keith Thompson wrote:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    [...]

    My personal interpretation is that this:

    void func(int arr[static 5]) {
    }

    int main(void) {
    int arr[10];
    func(arr+5); // OK
    // func(arr+6); // UB
    }

    is valid, because, for example, the last 5 elements of a 10-element
    array object can be treated as a 5-element array object. gcc seems
    to agree, based on the fact that it warns about func(arr+6) but
    not about func(arr+5).

    This is a fundamental part of my mental model of C, but in a few
    minutes of searching I wasn't able to find explicit wording in the
    standard that supports it.

    In N1570, 6.7.6.3 p7.

    Did you mean to imply that that paragraph supports (or refutes) my
    statement? [...]

    No. I posted the reference to say that the cited paragraph supports
    the conclusion that 'func(arr+6)' is undefined behavior.
    ...
    To me it seems obvious that 6.7.6.3 p7 is meant to cover the
    case of 'func(arr+6)' as being undefined behavior.

    But that's not the question I was addressing. My question is whether func(arr+5) has defined behavior, based on whether or not a+5 points to
    the *first element* of an array.


    Tim - you very commonly post messages leaving out lots of relevant
    information, seemingly expecting people to figure out the details that
    you don't bother to provide. This can be a valid teaching technique, but
    using that technique relies on the assumption that what you've left out
    can be determined by careful examination of what you put in. However,
    Keith had no reasonable way of guessing what you had left out, because
    he did not anticipate that you would address the wrong question. As a
    general rule, if there's any possibility that you've made a mistake like
    you did in this case, leaving out too many details as "an exorcise for
    the student" runs the risk of not not providing enough information for
    others to identify and correct the mistake.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Keith Thompson on Wed May 14 03:35:27 2025
    On 2025-05-13, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    is valid, because, for example, the last 5 elements of a 10-element
    array object can be treated as a 5-element array object. gcc seems
    to agree, based on the fact that it warns about func(arr+6) but
    not about func(arr+5).

    This is a fundamental part of my mental model of C, but in a few
    minutes of searching I wasn't able to find explicit wording in the
    standard that supports it.

    I haven't found explicit wording which supports the concept in the above use scenario.

    The Library clause (I'm referring to n3301 here0 has the wording:

    If a function argument is described as being an array, the pointer passed to
    the function shall have a value such that all address computations and
    accesses to objects (that would be valid if the pointer did point to the first
    element of such an array) are valid.(218)

    Footnote 218 gives some degenerate examples more extreme than the
    arr + 5 situation:

    This includes, for example, passing a valid pointer that points
    one-past-the-end of an array along with a size of 0, or using any valid
    pointer with a size of 0.

    The presence of the wording in the Library clause suggests that someone though it was necessary. It needs to be extended (or repeated elsewhere with adjusted wording) to cover situations involving language constructs that are not standard library functions.

    Progarms that manipulate strings using standard library functions often
    take advantage of the above. Strings are defined as null-terminated
    arrays; but it is very common for strings to be arrays that are displaced within larger arrays.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Tue May 13 21:12:53 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [...]

    My personal interpretation is that this:

    void func(int arr[static 5]) {
    }

    int main(void) {
    int arr[10];
    func(arr+5); // OK
    // func(arr+6); // UB
    }

    is valid, because, for example, the last 5 elements of a 10-element
    array object can be treated as a 5-element array object. gcc seems
    to agree, based on the fact that it warns about func(arr+6) but
    not about func(arr+5).

    This is a fundamental part of my mental model of C, but in a few
    minutes of searching I wasn't able to find explicit wording in the
    standard that supports it.

    In N1570, 6.7.6.3 p7.

    Did you mean to imply that that paragraph supports (or refutes) my
    statement? [...]

    No. I posted the reference to say that the cited paragraph supports
    the conclusion that 'func(arr+6)' is undefined behavior.

    I wish you had said so in the first place. Of course func(arr+6) has undefined behavior. Did anyone in this thread say or imply otherwise?

    In my view the same reasoning about the meaning applies to both
    cases, so there is no reason to talk about them separately.

    """
    A declaration of a parameter as ??array of _type_?? shall
    be adjusted to ??qualified pointer to _type_??, where the
    type qualifiers (if any) are those specified within the [ and ]
    of the array type derivation. If the keyword static also appears
    within the [ and ] of the array type derivation, then for each call
    to the function, the value of the corresponding actual argument
    shall provide access to the first element of an array with at least
    as many elements as specified by the size expression.
    """

    The question is whether, for example, the last 5 elements of a
    10-element array object can be treated as a 5-element array object.
    If someone can cite wording in the standard that answers that
    question, I'd appreciate it. (I'll be happier if the answer is yes.)

    To me it seems obvious that 6.7.6.3 p7 is meant to cover the
    case of 'func(arr+6)' as being undefined behavior.

    But that's not the question I was addressing. My question is whether func(arr+5) has defined behavior, based on whether or not a+5 points to
    the *first element* of an array.

    To me it seems obvious that 6.7.6.3 p7 is meant to cover the
    case of 'func(arr+5)' as satisfying the "shall" requirement,
    for the same reasons that it is meant to cover the case of
    'func(arr+6)' as being undefined behavior.

    Note that 6.7.6.3 p7 doesn't say "array object", it says just
    "array". I believe the choice of wording is neither an accident nor
    an oversight.

    Then please explain what you see as the difference. Wording in the
    standard to support the distinction would be welcome.

    Given `int arr[10];`, do the last 5 elements of arr constitute an
    "array"? Do they constitute an "array object"? And the same
    questions for arr as a whole.

    The meanings follow from a plain understanding of the English
    language.

    Consider the following example:

    typedef struct { int s; float f; } T;

    extern void foo( unsigned char blah[ static sizeof(T)-1 ] );

    void
    bas( T *it ){
    foo( (unsigned char *)it + 1 );
    }

    There is no array object. But surely there is an array (or at
    least an array is indicatated, and an array is present if 'it' is
    a valid pointer). This example satisfies the "shall" requirement
    in 6.7.6.3 p7, despite there being no array object in sight.

    Looking into this a bit more, I realize that the question doesn't
    matter if there's no "static" keyword between the [ and ]. In that
    case, the parameter is of pointer type, and the description of
    pointer arithmetic (N1570 6.5.6p8) explicitly allows the pointer
    to point to the i-th element of an array object. The wording for
    [static N] is the only place I've seen (so far) that specifically
    refers to the *first* element of an array object, raising the
    question of whether a subobject of an array object is itself an
    array object.

    Again, not an array object, just an array.

    This might just be some slightly sloppy wording that was
    introduced in C99 and never corrected.

    I draw the opposite conclusion. The wording of 6.7.6.3 p7 was
    carefully chosen so that it would cover cases like 'func(arr+6)'.

    But func(arr+5) is the case I was wondering about. (That's why I
    commented out the func(arr+6) call.)

    The wording of 6.7.6.3 p7 was carefully chosen so that it would allow
    cases like 'func(arr+5)', for the same reasons that it would deem
    'func(arr+6)' as being undefined behavior.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to James Kuyper on Tue May 13 21:19:54 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    On 5/13/25 22:37, Keith Thompson wrote:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [...]

    My personal interpretation is that this:

    void func(int arr[static 5]) {
    }

    int main(void) {
    int arr[10];
    func(arr+5); // OK
    // func(arr+6); // UB
    }

    is valid, because, for example, the last 5 elements of a 10-element >>>>>> array object can be treated as a 5-element array object. gcc seems >>>>>> to agree, based on the fact that it warns about func(arr+6) but
    not about func(arr+5).

    This is a fundamental part of my mental model of C, but in a few
    minutes of searching I wasn't able to find explicit wording in the >>>>>> standard that supports it.

    In N1570, 6.7.6.3 p7.

    Did you mean to imply that that paragraph supports (or refutes) my
    statement? [...]

    No. I posted the reference to say that the cited paragraph supports
    the conclusion that 'func(arr+6)' is undefined behavior.

    ...

    To me it seems obvious that 6.7.6.3 p7 is meant to cover the
    case of 'func(arr+6)' as being undefined behavior.

    But that's not the question I was addressing. My question is whether
    func(arr+5) has defined behavior, based on whether or not a+5 points to
    the *first element* of an array.

    Tim - [...]

    I don't know why you expect me to read postings meant for me but
    posted as a reply to another poster. Sometimes I do, sometimes
    I don't. You may take the correlation as being determined by
    quantum mechanical uncertainty.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Keith Thompson on Wed May 14 06:31:01 2025
    On 2025-05-14, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    [...]
    Progarms that manipulate strings using standard library functions often
    take advantage of the above. Strings are defined as null-terminated
    arrays; but it is very common for strings to be arrays that are displaced
    within larger arrays.

    To be pedantic, a string is defined as "a contiguous sequence of
    characters terminated by and including the first null character".
    The word "array" is not used. It does seem fairly obvious that
    the contiguous sequence will be stored in an array (array object?),
    but the standard doesn't quite say so.

    This issue with a + 5 and all points to a more general issue.
    There is no discussion about aliasing between arrays of
    the same element type, but different sizes and displacements.

    Given int a[10], we can do int (*p)[5] = (int (*)[5])(a + 5) to obtain
    a pointer the upper half of the array as an int [5] array type.

    Then *p is an array lvalue which recovers us a + 5.
    Surely, that is valid; but it's not spelled out.

    Arrays are not accessed themselves since they cannot be passed,
    returned or assigned, and their values "decay" to pointers.

    An access like (*p)[1] cannot be considered an invalid aliasing for
    a[6], since it uses the declared type of the element. The pointer is
    valid, and not by chance; but doe to good arithmetic
    on a good starting value.

    *p itself cannot be invalid aliasing because that concept is defined in
    terms of access using the wrong type, and *p doesn't access.

    (And so, why couldn't we pass the expression *p as the argument to that
    int a[static 5]? If *p doesn't count as an array, by what
    rule is that? Surely not aliasing. And if *p is okay but a + 5 is not,
    what's the point of the hair-splititng.)

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Keith Thompson on Wed May 14 13:00:51 2025
    On 13/05/2025 23:35, Keith Thompson wrote:
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 12.05.2025 17:08, David Brown wrote:
    On 11/05/2025 23:43, James Kuyper wrote:
    [...]
    More precisely, it makes it undefined behavior for values to point to an >>>> array of less than 10 doubles.

    The wording of the C standard (C11, as that's what I have open at the
    moment) is :

    """
    If the keyword static also appears within the [ and ] of the array type
    derivation, then for each call to the function, the value of the
    corresponding actual argument shall provide access to the first element
    of an array with at least as many elements as specified by the size
    expression.
    """

    Oh! - This is somewhat surprising to me. - When I first read about
    the "arr[static N]" I assumed that it would be possible to pass any
    sub-array, say "&arr[8]" (or "arr+8") as long as it's large enough
    to still have N elements from the starting point, but the quote says
    explicitly "access to the _first_ element of an array" (which I'd
    interpret as "&arr[0]" (or "arr"). - Unless I misinterpreted that;
    what would be the reason for that?

    My personal interpretation is that this:

    void func(int arr[static 5]) {
    }

    int main(void) {
    int arr[10];
    func(arr+5); // OK
    // func(arr+6); // UB
    }

    is valid, because, for example, the last 5 elements of a 10-element
    array object can be treated as a 5-element array object. gcc seems
    to agree, based on the fact that it warns about func(arr+6) but
    not about func(arr+5).

    This is a fundamental part of my mental model of C, but in a few
    minutes of searching I wasn't able to find explicit wording in the
    standard that supports it.


    My interpretation matches yours. I can't find any indication in the
    standard of a definition of what an "array" actually means. It would be extraordinary - and render vast amounts of C code as having undefined
    behaviour - if "arr + 5" above could not be considered as pointing to
    the first element of an array of 5 int. (I believe the same logic
    applies to pointer arithmetic in general - not just this specific
    situation.) But that does not imply that the standard says a pointer to
    an element inside an array or array object can be treated as a pointer
    to the first element of an array and/or array object of appropriate size.

    I believe we can reassure Janis that your example code will be
    considered valid by any real-world compiler. But it would be nice to
    find some combination of standard paragraphs that guarantee it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to David Brown on Wed May 14 13:20:57 2025
    On 14.05.2025 13:00, David Brown wrote:
    [...]

    I believe we can reassure Janis that your example code will be
    considered valid by any real-world compiler.

    Thanks. Much appreciated. (I wasn't sure after some postings that were
    a bit distracting and thus more muddying the topic than clarifying.)

    But it would be nice to
    find some combination of standard paragraphs that guarantee it.

    Yes, indeed. (Heuristics are fine but certainty is better.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to All on Wed May 14 11:09:51 2025
    Michael S <already5chosen@yahoo.com> writes:

    (I am summarizing heavily in an effort to return to the main area
    of interest.)

    On Sun, 11 May 2025 17:30:14 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    [...]

    [suggestion to keep for() and eliminate while()]

    [a mention was made of statistics given in another posting
    that reported a ratio of while()/for() of roughly 2.3 to 1.]

    [upthread there was a different posting, from Richard
    Heathfield, that gave statistics reflecting a ratio
    of for()/while() of approximately 3 to 1, IIRC]

    I did a more comprehensive gathering of statistics, using an ad hoc
    collection of 68 open source projects, ranging in size from just
    over 1500 lines to over a million lines, including two outliers
    with 20 million lines and 75 million lines. The ratio of while()
    to do/while() ranged from 12.5% to 2100%, with an average of
    573.9%. The ratio of while() to for() ranged from 1.6% to 300%,
    with an average of 60.8%.

    [...] while() does not help anything relatively to for().

    I understand that that is your view. I don't remember seeing any
    supporting statements other than your personal reactions. My own
    experience is different. Judging by the open source statistics
    reported above, it appears that a fair number of other developers
    don't share your views on this question either.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to David Brown on Wed May 14 23:20:48 2025
    On 5/14/25 07:00, David Brown wrote:
    ...
    My interpretation matches yours. I can't find any indication in the
    standard of a definition of what an "array" actually means

    This is a problem with all of the derived types (6.2.5p25). There are definitions of the terms "array type", "structure type:, "union type", "function type", and "pointer type", but no definitions of the things
    that those types are types of. My interpretation is that for each of
    those object types, "X" is short-hand for "an object of X type". I
    haven't figured out suitable wording to define what a function is,
    since it isn't an object. The best I've come up with is "a thing of
    function type".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Wed May 14 20:44:54 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [...]

    If you mean that someone might use `[static N]` in a function's
    definition but not in a declaration, sure, but I would always
    make sure they match as closely as possible. [...]

    It strikes me that you have a rather self-centered view of the
    world. The vast majority of all C code is written by people other
    than yourself.

    [...]

    Tim, I am not interested in exchanging personal insults with you.
    (Yes, the quoted text above comes across as in insult, however you
    intended it.)

    If the only way to avoid that is to filter out your posts, I will,
    with some regret, do that. I would miss out on your technical
    contributions, but I'm willing to pay that price to avoid your
    hostility.

    There was no animosity meant in my comments. I am very sorry
    if it came across otherwise. I am making an effort to frame
    my future statements to help with this.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Richard Heathfield on Wed May 14 21:12:21 2025
    Richard Heathfield <rjh@cpax.org.uk> writes:

    On 13/05/2025 06:42, Tim Rentsch wrote:

    Richard Heathfield <rjh@cpax.org.uk> writes:

    On 12/05/2025 15:19, Tim Rentsch wrote:

    It strikes me that you have a rather self-centered view of the
    world.

    So do you. So do I. So does everybody else. Your eyes are at the
    precise centre of your observable universe.

    I think you have misunderstood me.

    I hope so, because the alternative is unpalatable.

    (At some later time I may have more to say about your other
    comments, but it seemed important to respond to this part
    more promptly.)

    I think you chose the least important part to respond to, so maybe you
    have misunderstood me, too.

    I was trying to defend an honourable man from what seemed to me to be
    an unfair and unnecessarily unkind observation. The paragraph you
    quote above acknowledges that in some literal sense your accusation of self-centredness is accurate, and so implies by omission that the more metaphorical sense that I think you intended is /not/ accurate.

    A fine distinction, some might say. But that's what the other
    paragraphs were for.

    I responded twice to your earlier message. I want to acknowledge this
    later message and respond here in an effort to achieve some closure.

    I appreciate the intention of your two followups. It isn't easy to
    play the role of peacemaker, especially in comp.lang.c, and I think
    your comments are helping cool things down. Thank you for that.

    Clearly there have been some misunderstandings. I think it would
    be a real effort to unwind those (even assuming that they have all
    been identified), and besides this isn't the right venue at least
    for some of them. So I don't have more to say about that except
    to say I am making an effort to do better in the future.

    Thank you again for trying to help.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to James Kuyper on Thu May 15 11:23:04 2025
    On 15/05/2025 05:20, James Kuyper wrote:
    On 5/14/25 07:00, David Brown wrote:
    ...
    My interpretation matches yours. I can't find any indication in the
    standard of a definition of what an "array" actually means

    This is a problem with all of the derived types (6.2.5p25). There are definitions of the terms "array type", "structure type:, "union type", "function type", and "pointer type", but no definitions of the things
    that those types are types of. My interpretation is that for each of
    those object types, "X" is short-hand for "an object of X type". I
    haven't figured out suitable wording to define what a function is,
    since it isn't an object. The best I've come up with is "a thing of
    function type".


    Yes, I agree.

    I guess that's why they call c.l.c. regulars who discuss these things
    "language lawyers"! Now all we need to do is find a way to get paid
    like lawyers...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Tue Jun 10 06:01:20 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Kaz Kylheku <643-408-1753@kylheku.com> writes:
    [...]

    Progarms that manipulate strings using standard library functions
    often take advantage of the above. Strings are defined as
    null-terminated arrays; but it is very common for strings to be
    arrays that are displaced within larger arrays.

    To be pedantic, a string is defined as "a contiguous sequence of
    characters terminated by and including the first null character".
    The word "array" is not used. It does seem fairly obvious that
    the contiguous sequence will be stored in an array (array
    object?), but the standard doesn't quite say so.

    Consider the following program:

    #include <stdio.h>
    #include <string.h>

    typedef unsigned long long ULL;
    ULL hello = ((((0ULL +'o' <<8) +'l' <<8) +'l' <<8) +'e' <<8) + 'h';

    int
    main(){
    printf( "length is %zu\n", strlen( (char*)&hello ) );
    return 0;
    }

    On a little endian machine (with CHAR_BIT == 8) this program works,
    and TTBOMK conforms to both the letter and the spirit of the C
    standard, without any undefined behavior (on that platform). Yet
    there are no arrays in sight, and certainly no array objects.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bonita Montero on Sat Jun 14 13:57:56 2025
    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 10.06.2025 um 15:01 schrieb Tim Rentsch:

    Consider the following program:

    #include <stdio.h>
    #include <string.h>

    typedef unsigned long long ULL;
    ULL hello = ((((0ULL +'o' <<8) +'l' <<8) +'l' <<8) +'e' <<8) + 'h';

    int
    main(){
    printf( "length is %zu\n", strlen( (char*)&hello ) );
    return 0;
    }

    On a little endian machine (with CHAR_BIT == 8) this program works,
    and TTBOMK conforms to both the letter and the spirit of the C
    standard, without any undefined behavior (on that platform). Yet
    there are no arrays in sight, and certainly no array objects.

    There are not much remaining big-endian architectures today.

    Ethernet is big-endian at the byte level and little-endian
    at the bit level.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Scott Lurndal on Sat Jun 14 22:27:20 2025
    On Sat, 14 Jun 2025 13:57:56 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 10.06.2025 um 15:01 schrieb Tim Rentsch:

    Consider the following program:

    #include <stdio.h>
    #include <string.h>

    typedef unsigned long long ULL;
    ULL hello = ((((0ULL +'o' <<8) +'l' <<8) +'l' <<8) +'e' <<8) +
    'h';

    int
    main(){
    printf( "length is %zu\n", strlen( (char*)&hello ) );
    return 0;
    }

    On a little endian machine (with CHAR_BIT == 8) this program works,
    and TTBOMK conforms to both the letter and the spirit of the C
    standard, without any undefined behavior (on that platform). Yet
    there are no arrays in sight, and certainly no array objects.

    There are not much remaining big-endian architectures today.

    Ethernet is big-endian at the byte level and little-endian
    at the bit level.


    802.3 frames are big-endian, because of Length field.
    Several orders of magnitude more popular Ethernet II frames are
    endian-neutral.

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