On 2026-10-13 16:38, Dan Cross wrote:
In article <11al8uc$hk7a$[email protected]>, bart <[email protected]> wrote:
[snip]
So your workaround had an error. That's what happens.
I could foresee such a stupid response! - You're a hopeless case.
Given that you've had even stupid syntax errors in your original
code I'm astonished that you even dare to get into such argument.
There is no programming that prevents all errors.
(That was not even programming; it was a quick write down for the
post as an example structure to explain what's to be visualized.)
[snip]
Jesus. I take it that you don't agree it is a hack then?
Writing a loop with a predicate that is composed by an 'and' is
certainly not a "hack" but usual programming. Nowadays you learn
such things in kindergarten.
In article <11alkqa$4o6l$[email protected]>,If there's any insult implied then it will have been me.
Janis Papanagnou <[email protected]> wrote:
On 2026-10-13 16:38, Dan Cross wrote:
In article <11al8uc$hk7a$[email protected]>, bart <[email protected]> wrote: >>>> [snip]
So your workaround had an error. That's what happens.
I could foresee such a stupid response! - You're a hopeless case.
Given that you've had even stupid syntax errors in your original
code I'm astonished that you even dare to get into such argument.
There is no programming that prevents all errors.
(That was not even programming; it was a quick write down for the
post as an example structure to explain what's to be visualized.)
[snip]
Jesus. I take it that you don't agree it is a hack then?
Writing a loop with a predicate that is composed by an 'and' is
certainly not a "hack" but usual programming. Nowadays you learn
such things in kindergarten.
Were you referring to me, Janis? Or to bart?
So what those counts indicate: majority of loops is simple, that is
have no early exit. Vast majority of early exits is done via
'return'.
For comparison, here is an example of Python’s match-statement. Like
all the good (i.e. non-C-based) designs, the designers saw no point
in having fall-through.
This is a very simple example, involving straight matching of values
against instances of an enum. There are also more complex
pattern-matching options available.
Were you referring to me, Janis? Or to bart?
There is no programming that prevents all errors.
(That was not even programming; it was a quick write down for the
post as an example structure to explain what's to be visualized.)
On Sat, 10 Oct 2026 00:25:54 -0000 (UTC), I wrote:
For comparison, here is an example of Python’s match-statement. Like
all the good (i.e. non-C-based) designs, the designers saw no point
in having fall-through.
This is a very simple example, involving straight matching of values
against instances of an enum. There are also more complex
pattern-matching options available.
Another, slightly more involved example, where the matching is against
the components of a tuple. This is from a parser for the Varlink
interface definition language. Note the use of the “_” wildcard to indicate don’t-care parts of matches:
match token.value, token.rule_name :
case "[]", _ :
nexttoken()
valtype = parse_typedef(None)
result = ArrayType(name, valtype)
case "[string]", _ :
nexttoken()
valtype = parse_typedef(None)
result = DictType(name, valtype)
case _, "elttypedef" :
result = parse_elttypedef(name)
case _, "typedef" :
result = parse_typedef(name)
case _ :
raise AssertionError \
(
"unrecognized typedef token %s: %s"
%
(token.rule_name, repr(token.value))
)
#end match
bart <[email protected]> writes:
[...]
This is my first example expressed in C (note those first three args
are passed by reference):
while (pmtype = nextcmdparam(¶mno, &name, &value, "m") {
switch (pmtype)
case pm_option: ...; break;
case pm_sourcefile:
if (passlevel == run_pass || passlevel == runpcl_pass) {
break;
Except I can't use break like that. So I have to find a workaround.
The code appears to be valid C that doesn't do what you want. I can't
easily tell what you want it to do. I don't know which of the two break statements was intended to break out of the loop. A comment would have solved that.
I'm going to guess that the first break is supposed to apply to the
switch statement, and the second to the while loop.
You want the language to be changed to make this kind of thing easier.
That's already happening. If you take a look at the N3886 working
draft for C2y, it has named break statements. In C2y (or in gcc
if you use an extension), the above could be written as:
WHILE:
while (pmtype = nextcmdparam(¶mno, &name, &value, "m") {
SWITCH:
switch (pmtype)
case pm_option: ...; break SWITCH;
case pm_sourcefile:
if (passlevel == run_pass || passlevel == runpcl_pass) {
break WHILE;
assuming it's the second "break' that's supposed to break out of
the loop. (I'd probably use more meaninful names.)
There is already a solution for the problem you're complaining about.
(It also solves the problem of breaking out of nested loops.)
If you're unable to use this feature, you can use goto. That's not
ideal, but with well chosen label names and no backward branching
it's not too bad.
On Tue, 13 Oct 2026 07:40:30 -0700
Tim Rentsch <[email protected]> wrote:
Michael S <[email protected]> writes:
On Mon, 12 Oct 2026 21:09:25 +0200
David Brown <[email protected]> wrote:
On 12/10/2026 21:02, Michael S wrote:
On Sun, 11 Oct 2026 14:28:29 -0700
Keith Thompson <[email protected]> wrote:
bart <[email protected]> writes:
[...]
'break' to quit a loop early is part of the language, so why
shouldn't someone make use it?
Agreed. (There are coding styles that require loops to exit only
at the bottom, but that's not what we're talking about.)
It just its use can be interfered with when 'switch' is
involved.
Yes. Everyone here knows that, and knew it before you started
talking about it.
Michael S wrote above that "The cases where I want to break out
of the loop from the switch in the body of the loop are very
common." Tim Rentsch questioned the "very common" part of that,
and asked for an example. You jumped in and asserted that an
example isn't necessary, because you misunderstood what was
being said.
I didn't read the whole subthread, but from what I read it seems
that the only reader that misunderstood my statement was David
Brown. The rest, including bart, understood just fine.
If I have misunderstood, I would love to be corrected. In a number
of my posts I said I was not sure what you were talking about, and
would need more explanation.
I thought that my comment is hard to misunderstand, but you proved
me wrong. So I'd try to elaborate:
switch() nested within loop is very common in my practice and I
suppose in practice of everybody else.
In my practice, but obviously not in practice of Tim Rentsch, it
is sufficiently common to want to transfer control from point within
such nested switch to point immediately following the containing
loop.
Let me clarify my earlier comment. I'm not surprised that people
routinely use switch() inside of loops. What did surprise me is the
statement that wanting to break out of the loop from inside the
switch() is "very common". Not happens occasionally; not happens
commonly or even just sufficiently commonly; not happens routinely;
but "very common". I am wondering now how common it actually is,
for switch() in general and for switch() inside of a loop. Is it
one in a hundred? One in ten? One in two? More than that?
Of course, I never gathered exact statistics.
My guts feeling is that among switches nested within loop it could be as
high as one out of five. Not one out of five case labels, but one out of five switch statements.
I asked for an example because I am curious about what the proximate
cause of such commonality might be. Is it a general style matter?
Is it that you are used to certain patterns of local control flow?
My own use cases are mostly related to processing of incoming network messages that are distinguished by opcode at the beginning of the
message.
But not just that. Generally, I like small functions that return
specialized enum as result code. When such functions used within
loop, it often leads to pattern in question.
Is it that some use cases are more common in the kinds of programs
you deal with? It would be good to get some data here, even just
ad hoc data.
Sorry, right now I have no time for doing such analysis. It is not
trivial exactly because 'C' has no such feature. So I don't know how
to automate a search within codebases.
In my own experience, wanting to escape multiple levels (including
the case of provoking a loop exit from inside a switch()) doesn't
happen often enough to merit considering a language change. But I
would like to know more about the experiences of other people.
I'm reminded of a quote from (if memory serves) Tony Hoare, about
language design. Paraphrasing: A programming language should not
reflect the union of all the features proposed by its designers;
rather it should reflect the union of the designers' prejudices
about what features should NOT be put into the language.
In this particular case Ritchie did not have to innovate in order to
create this feature. Quite opposite, as others (Keith ?) mentioned,
he had to innovate in order to merge distinct break-loop and
break-switch features of ancestor language into unified break.
My view is that using distinct keywords for loop-break and
switch-break (accepting that the language wants the latter) would have
had pretty much zero costs, but worthwhile benefits.
In this particular case Ritchie did not have to innovate in order to
create this feature. Quite opposite, as others (Keith ?) mentioned, he
had to innovate in order to merge distinct break-loop and break-switch features of ancestor language into unified break.
Note this is the only place in that paper where Dennis Ritchie[...]
mentions `break`. Why was it overloaded for `switch`? He does
not say, exactly, but he _does_ alude to space being a
consideration for B, and some of the resulting syntactic quirks
then escaping into C:
bart <[email protected]> writes:
[...]
My view is that using distinct keywords for loop-break and
switch-break (accepting that the language wants the latter) would have
had pretty much zero costs, but worthwhile benefits.
I agree, and I don't think that's particularly controversial.
The point on which we disagree is what can and should be done about
it now.
On 13/10/2026 01:33, Keith Thompson wrote:[...]
[...]That's already happening. If you take a look at the N3886 working
draft for C2y, it has named break statements.
There is already a solution for the problem you're complaining
about.
(It also solves the problem of breaking out of nested loops.)
If you're unable to use this feature, you can use goto. That's not
ideal, but with well chosen label names and no backward branching
it's not too bad.
I've got a better idea. I added an extra keyword to my C compiler
called "breakloop". It's like 'break' but always works with the
nearest enclosing loop, even from inside switch.
Simple, yes? Then you think that this could be done even more easily
50 years ago.
On 13/10/2026 01:33, Keith Thompson wrote:
bart <[email protected]> writes:
[...]
This is my first example expressed in C (note those first three args
are passed by reference):
while (pmtype = nextcmdparam(¶mno, &name, &value, "m") {
switch (pmtype)
case pm_option: ...; break;
case pm_sourcefile:
if (passlevel == run_pass || passlevel == runpcl_pass) {
break;
Except I can't use break like that. So I have to find a workaround.
The code appears to be valid C that doesn't do what you want. I can't
easily tell what you want it to do. I don't know which of the two break
statements was intended to break out of the loop. A comment would have
solved that.
I'm going to guess that the first break is supposed to apply to the
switch statement, and the second to the while loop.
You want the language to be changed to make this kind of thing easier.
That's already happening. If you take a look at the N3886 working
draft for C2y, it has named break statements. In C2y (or in gcc
if you use an extension), the above could be written as:
WHILE:
while (pmtype = nextcmdparam(¶mno, &name, &value, "m") {
SWITCH:
switch (pmtype)
case pm_option: ...; break SWITCH;
case pm_sourcefile:
if (passlevel == run_pass || passlevel == runpcl_pass) {
break WHILE;
assuming it's the second "break' that's supposed to break out of
the loop. (I'd probably use more meaninful names.)
There is already a solution for the problem you're complaining about.
(It also solves the problem of breaking out of nested loops.)
If you're unable to use this feature, you can use goto. That's not
ideal, but with well chosen label names and no backward branching
it's not too bad.
I've got a better idea. I added an extra keyword to my C compiler called >"breakloop". It's like 'break' but always works with the nearest
enclosing loop, even from inside switch.
So this example (a starts at 0):
while (1) {
switch (a++) {
case 1: puts("one"); break;
case 2: puts("two"); breakloop;
case 3: puts("three"); break;
default: puts("other");
}
if (a>40) break;
}
finishes after displaying 'two', instead of after the 37th or so 'other'.
Modding the compiler took 90 seconds, and needed 4 extra lines of code. >Setting up this test took 2-3 minutes.
Simple, yes? Then you think that this could be done even more easily 50 >years ago.
Many other languages solve this using a "labeled break" (Go,
Rust, C#, Kotlin, Java, Ada, Pike, and now C), though some have
used a "counted"/"multi-level" break (Ruby, Perl; I think PHP).
You could have elegantly solved this problem by making `break`
take an optional integer argument, which is the number of levels
of structure to break out of.
But as Keith pointed out, W14 is now entertaining proposals to
add labeled `break` to the language. I haven't looked myself,
but if that is usable in a `switch` context, then it would solve
the problem for good.
This illustrates one reason why changing a language can be hard:--
your idea sounds good at first blush, but it has its own
deficiencies.
Of course, I never gathered exact statistics.
My guts feeling is that among switches nested within loop it could be as
high as one out of five. Not one out of five case labels, but one out of
five switch statements.
On 2026-10-13 22:52, Dan Cross wrote:
Were you referring to me, Janis? Or to bart?
You can identify the association of the answers by its attribution
indent level. - Most was attributed to bart's text that was quoted.
In article <11amlq9$12efg$[email protected]>,
Keith Thompson <[email protected]> wrote:
bart <[email protected]> writes:
[...]
My view is that using distinct keywords for loop-break and
switch-break (accepting that the language wants the latter) would have
had pretty much zero costs, but worthwhile benefits.
I agree, and I don't think that's particularly controversial.
The point on which we disagree is what can and should be done about
it now.
The answer to that is: Invent new languages with C-like syntax, but better. >You can't do anything about C, but you can do better as long as you call
the result something else.
Like C#. Like C++. Like Swift.
In article <11amecs$10eab$[email protected]>, bart <[email protected]> wrote:
I've got a better idea. I added an extra keyword to my C compiler called
"breakloop". It's like 'break' but always works with the nearest
enclosing loop, even from inside switch.
So this example (a starts at 0):
while (1) {
switch (a++) {
case 1: puts("one"); break;
case 2: puts("two"); breakloop;
case 3: puts("three"); break;
default: puts("other");
}
if (a>40) break;
}
finishes after displaying 'two', instead of after the 37th or so 'other'.
Modding the compiler took 90 seconds, and needed 4 extra lines of code.
Setting up this test took 2-3 minutes.
Simple, yes? Then you think that this could be done even more easily 50
years ago.
Not really; for a general mechanism, if suffers from the obvious
deficiency that it doesn't compose.
For example, if the switch is inside of nested loops, and I
want to break out of everything,
or I have two embedded switches
(which I have written when parsing firmware tables); I can think
of a number of instances where you might want to have switch
inside of nested loops and want to break out to function scope,
such as advancing states a la a Thompson-style NFA, where one
has a loop over the input text, a loop over the set of all
states, and a switch matching state against the current input
character, and you want to break out when you find a match.
Many other languages solve this using a "labeled break" (Go,
Rust, C#, Kotlin, Java, Ada, Pike, and now C), though some have
used a "counted"/"multi-level" break (Ruby, Perl; I think PHP).
You could have elegantly solved this problem by making `break`
take an optional integer argument, which is the number of levels
of structure to break out of.
For a `switch` inside of a loop,
`break 2;` would exit both the case and the enclosing loop; for
a nested switch, `break 2;` would break out of both. Workable,
but in some respects the labeled form is better because it is
resilient to code shuffling around and changing nesting levels
and so forth.
An obvious next extension would be augmenting `continue`
similarly.
But as Keith pointed out, W14 is now entertaining proposals to
add labeled `break` to the language. I haven't looked myself,
but if that is usable in a `switch` context, then it would solve
the problem for good.
This illustrates one reason why changing a language can be hard:I appreciate your concern. I've only been doing this (devising and implementing systems languages) for 45 years!
your idea sounds good at first blush, but it has its own
deficiencies.
[...]
Many other languages solve this using a "labeled break" (Go,
Rust, C#, Kotlin, Java, Ada, Pike, and now C), though some have
used a "counted"/"multi-level" break (Ruby, Perl; I think PHP).
The only languages I know of that have a "counted break" (where
"break 2" breaks out of two levels of loops) are the Bourne shell
and shells derived from it, and PHP (you're right about that).
Perl has named break (spelled "last" or "last NAME") and continue
(spelled "next" or "next NAME). It does not have counted versions.
Ruby allows an argument on "break", but it's not the number of levels.
It specifies the value of the expression that it breaks out of. (A
loop is an expression that can yield a value.)
The latest draft of the C++ standard does not include labeled break
and continue statements. I don't know whether it's been proposed.
You could have elegantly solved this problem by making `break`
take an optional integer argument, which is the number of levels
of structure to break out of.
I don't consider that elegant, for reasons I've already ranted about
here.
[...]
But as Keith pointed out, W14 is now entertaining proposals to
add labeled `break` to the language. I haven't looked myself,
but if that is usable in a `switch` context, then it would solve
the problem for good.
Yes, labeled "break" in C2y applies to both loops and switch statements. >There's also a labeled "continue" that applies only to loops.
The labels are optional, so existing code isn't broken.
The latest C2y draft is ><https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3886.pdf>
(3.3 MB, 793 pages).
On 14/10/2026 04:59, Dan Cross wrote:
In article <11amecs$10eab$[email protected]>, bart <[email protected]> wrote:
I've got a better idea. I added an extra keyword to my C compiler called >>> "breakloop". It's like 'break' but always works with the nearest
enclosing loop, even from inside switch.
So this example (a starts at 0):
while (1) {
switch (a++) {
case 1: puts("one"); break;
case 2: puts("two"); breakloop;
case 3: puts("three"); break;
default: puts("other");
}
if (a>40) break;
}
finishes after displaying 'two', instead of after the 37th or so 'other'. >>>
Modding the compiler took 90 seconds, and needed 4 extra lines of code.
Setting up this test took 2-3 minutes.
(I've now simplified it to adding one extra line and tweaking another!
I'd even suggest that using distinct keywords in the original C compiler >would have made it a tiny bit simpler.)
Simple, yes? Then you think that this could be done even more easily 50
years ago.
Not really; for a general mechanism, if suffers from the obvious
deficiency that it doesn't compose.
For example, if the switch is inside of nested loops, and I
want to break out of everything,
This isn't the problem being discussed. IME breaking of nested loops is >uncommon, but breaking out of a loop from inside switch /is/ common.
It's using the same 'break' keyword that makes that awkward in C. And my >experiment solves that easily.
or I have two embedded switches
That's not a problem; 'breakloop' will completely ignore any switch >statements, in the same way that 'continue' does.
Unless you've invented a new requirement where you want 'break' within a >switch (itself solving an artificial problem) to jump straight to the
end of an outer switch.
(which I have written when parsing firmware tables); I can think
of a number of instances where you might want to have switch
inside of nested loops and want to break out to function scope,
such as advancing states a la a Thompson-style NFA, where one
has a loop over the input text, a loop over the set of all
states, and a switch matching state against the current input
character, and you want to break out when you find a match.
'Jumping to function scope' is poorly defined. Do you mean cutting
across not only all loops, but any containing nested 'if' and 'switch' >statements?
So that would be a separate feature from loop-break? Would it still
involve loops at all, or could it be used from within any statement?
That sounds too general and wide-reaching; I think 'goto' is a much
better fit for that, if 'return' or 'defer' wouldn't work.
Many other languages solve this using a "labeled break" (Go,
Rust, C#, Kotlin, Java, Ada, Pike, and now C), though some have
used a "counted"/"multi-level" break (Ruby, Perl; I think PHP).
You could have elegantly solved this problem by making `break`
take an optional integer argument, which is the number of levels
of structure to break out of.
I could have done that in C but it would have taken more than 5 minutes,
and this was anyway a proof of concept.
I've already used that approach for some decades in my other languages,
but as I showed in the tables I posted, it is not common, and where
used, it was always to break out of all loops.
Anyway, I normally use 'all' instead of a specific number to quit all
loops. A number works too but I dislike it.
For a `switch` inside of a loop,
`break 2;` would exit both the case and the enclosing loop; for
a nested switch, `break 2;` would break out of both. Workable,
but in some respects the labeled form is better because it is
resilient to code shuffling around and changing nesting levels
and so forth.
No, it just has a different set of problems. For example, you label the >outer loop and exit to that. Now you add an extra outer loop layer: does >that label go inside this new loop or outside?
That depends on the intended logic, which you don't know.
Maybe the original set of loop performed some task T, and the new loop
wants to repeat T, in which case it must stay inside.
Or maybe it is really has to quit ALL loops including any future outer
ones. Neither labeling or numbering solves this.
Labeled loops may also have a new problem with scoping: is the loop name >local to this nest of loops, or could an outer loop name especially
clash with other loop elsewhere?
An obvious next extension would be augmenting `continue`
similarly.
In my other languages, I use 'exit' for break, and 'nextloop' for
continue, and 'redoloop' to repeat iteration. (The latter will have >different behaviour inside a for-loop with formal loop variables.)
I've just done a survey in my major apps and haven't found an instance
where those latter two needed to cross two or more loops.
Although I am sure C programmers would put 'continue x' to good use if
it was available!
But as Keith pointed out, W14 is now entertaining proposals to
add labeled `break` to the language. I haven't looked myself,
but if that is usable in a `switch` context, then it would solve
the problem for good.
OK. Although in that form, it really is little different from 'goto'. I >believe the main difference is that the label goes at the beginning of
the loop rather than the end!
And maybe those scoping rules will be different: goto labels have >function-wide scope.
This illustrates one reason why changing a language can be hard:
your idea sounds good at first blush, but it has its own
deficiencies.
I appreciate your concern. I've only been doing this (devising and >implementing systems languages) for 45 years!
On 2026-10-13, Michael S <[email protected]> wrote:
Of course, I never gathered exact statistics.
My guts feeling is that among switches nested within loop it could be as
high as one out of five. Not one out of five case labels, but one out of
five switch statements.
Switches inside a loop are natural whenever a state machine is being simulated which has acceptance/failulre states which indicate that the simulation should end.
Switches inside a loop are also natural whenever a stream of
integer-tagged cases is being handled where a terminating sentinel is
also labeled.
There are at least two workarounds for writing this which avoid
duplicated testing or loop termination flags, gotos or such.
One is to make the loop the last statement of a function and use
"return" in the loop-terminating cases.
The other is to put a "break" at the bottom of the loop and
terminate all the loop-continuing cases with "continue",
the terminating cases with "break":
for (;;) {
int ch = getc(in);
switch (ch) {
case '\n':
lines++;
/* fallthrough */
default:
continue;
case EOF:
break;
}
break;
}
On 13/10/2026 01:33, Keith Thompson wrote:
bart <[email protected]> writes:
[...]
I've got a better idea. I added an extra keyword to my C compiler called >"breakloop". It's like 'break' but always works with the nearest
enclosing loop, even from inside switch.
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]> wrote:
I'd even suggest that using distinct keywords in the original C compiler
would have made it a tiny bit simpler.)
Unlikely. I'm trying to chase down the citation, but it was
known that getting B to fit on the PDP-7 was a challenge. From
the C history paper,
The irony here, of course, is that you are claiming that C is
deficient because it doesn't solve what you see as a problem,
but trying to force the problem space specifically so that it
...except for all the other cases where it is still awkward and
solves nothing.
Unless you've invented a new requirement where you want 'break' within a
switch (itself solving an artificial problem) to jump straight to the
end of an outer switch.
Yes, that's exactly what I'm saying. Again, you've identified
one narrow problem,
I think this is the central reason people don't take your
criticism of C particularly seriously.
'Jumping to function scope' is poorly defined. Do you mean cutting
across not only all loops, but any containing nested 'if' and 'switch'
statements?
What I mean is this:
void
foo(void)
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; i++) {
switch (something) {
case ...:
// I want to break out
// of the switch and
// both loops here.
goto label;
}
}
}
label:
}
minutes,>> and this was anyway a proof of concept.I could have done that in C but it would have taken more than 5
Yup. And it took less than that to point out problems.
I've already used that approach for some decades in my other languages,
but as I showed in the tables I posted, it is not common, and where
used, it was always to break out of all loops.
Anyway, I normally use 'all' instead of a specific number to quit all
loops. A number works too but I dislike it.
That sounds overly specific.
This is actually the argument against the counted multi-level
break: if I add or remove a level of nesting, I have to find and
adjust all of the counts. The labeled break mechanism ties the
`break` or `continue` to another syntactic element (a label), so
if I add or remove a nesting level, I'm still breaking to where
I had intended to before.
That said, applying the argument to the labeled case is silly.
Software engineering and good programming practice still matter.
If you are changing the nested looping structure of your
program, then you should know where you want to break to;
presumably your program's behavior depends on it.
I'd say the stronger argument for the labeled control structure
is actually nested switch statements, where I may change a
series of `if`s to a `switch` with a `case` that contains a
nested `switch`, or I may change a `switch` to an `if`; if the
intent is to break out of an enclosing loop, labeled breaks are
resilient to that, but counted breaks are not.
loop>> wants to repeat T, in which case it must stay inside.Maybe the original set of loop performed some task T, and the new
Yes.
Or maybe it is really has to quit ALL loops including any future outer
ones. Neither labeling or numbering solves this.
No. If I want to break out of *all* loops, I just make sure
that the outermost loop is labeled thusly.
Careful here: do you really mean that loop-labels will be in the same name-space as ordinary labels? That means:Labeled loops may also have a new problem with scoping: is the loop name
local to this nest of loops, or could an outer loop name especially
clash with other loop elsewhere?
Since labels are, you know, labels, they follow the semantics of
... labels.
I've just done a survey in my major apps and haven't found an instance
where those latter two needed to cross two or more loops.
Anecdotal evidence, I'm afraid.
It's easy enough to look it up in the draft document; Keith
posted a link.
And yet I've solved all the problems in this thread and many others.This illustrates one reason why changing a language can be hard:
your idea sounds good at first blush, but it has its own
deficiencies.
I appreciate your concern. I've only been doing this (devising and
implementing systems languages) for 45 years!
That really doesn't mean anything. Just doing something for a
long time doesn't mean you're good at it: I have been shooting
baskets for 45 years, but I will never be a point guard in the
NBA.
In article <11am9r9$4o6m$[email protected]>,
Janis Papanagnou <[email protected]> wrote:
On 2026-10-13 22:52, Dan Cross wrote:
Were you referring to me, Janis? Or to bart?
You can identify the association of the answers by its attribution
indent level. - Most was attributed to bart's text that was quoted.
Sure. I was just surprised that the reply to my post was the
vehicle to reply to bart. Anyway, no worries!
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]> wrote:
Yes, I am aware that you will tell me that it is justified
because that problem is actually the one worth solving, and the
others are not; you needn't bother. Simply put, I disagree that
that one problem is sufficiently important to warrant its own
solution, particularly when something more general is already
known and available in the language (labeled break/continue).
On 14/10/2026 13:38, Dan Cross wrote:
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]> wrote:
Yes, I am aware that you will tell me that it is justified
because that problem is actually the one worth solving, and the
others are not; you needn't bother. Simply put, I disagree that
that one problem is sufficiently important to warrant its own
solution, particularly when something more general is already
known and available in the language (labeled break/continue).
I missed this bit.
Is labeled break now available in C?
If so, how would it be used here:
while (1) {
switch (x) {
case y:
Break;
where that Break is meant to quit the loop.
Remember that if DMR hadn't made that screw-up in 1972 it would simply
have been as it is above with his choice of keyword in place of Break.
But I would be interested in trying out the new feature.
On 14/10/2026 13:38, Dan Cross wrote:
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]> wrote:
I'd even suggest that using distinct keywords in the original C compiler >>> would have made it a tiny bit simpler.)
Unlikely. I'm trying to chase down the citation, but it was
known that getting B to fit on the PDP-7 was a challenge. From
the C history paper,
Perhaps Switch should have been left out then if it was that tight.
Sharing a keyword is just crass.
Or maybe they should have considered
not needing 'break' for switch.
The irony here, of course, is that you are claiming that C is
deficient because it doesn't solve what you see as a problem,
but trying to force the problem space specifically so that it
No, /you/ are trying to discredit a simple solution by widening the >goalposts.
The main problem being discussed,
and the one my test fixed, is that of
'break' being used for two purposes and therefore resulting in clashes
when Switches and Loops are mixed.
That could easily have been fixed by DMR choosing to use distinct
keywords. Do you agree so far?
That of breaking out of nested loops is a different problem that would
need a different solution, and nothing to do with the clash with switch.
It is also one that seems to be about 100 times less common IME.
...except for all the other cases where it is still awkward and
solves nothing.
IT WAS ONLY SUPPOSED TO SOLVE THIS PROBLEM! Namely the issues that
ensued from DMR overloading 'break'. NOTHING ELSE.
In fact the confusion between switch-break and loop-break will still be >there even if labels are added.
Unless you've invented a new requirement where you want 'break' within a >>> switch (itself solving an artificial problem) to jump straight to the
end of an outer switch.
Yes, that's exactly what I'm saying. Again, you've identified
one narrow problem,
It's not that narrow a problem, unless you want to call loops themselves
a narrow feature.
It is one that many languages solve for LOOPs by using break or
equivalent. But they tend not to broaden it either to include breaks out
of arbitrary kinds of blocks.
I think this is the central reason people don't take your
criticism of C particularly seriously.
I'm sorry but here I don't take yours seriously either. (Have you ever >implemented any of this stuff, or even used such features that you propose?)
'Jumping to function scope' is poorly defined. Do you mean cutting
across not only all loops, but any containing nested 'if' and 'switch'
statements?
What I mean is this:
void
foo(void)
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; i++) {
switch (something) {
case ...:
// I want to break out
// of the switch and
// both loops here.
goto label;
}
}
}
label:
}
This example just breaks out of both loops. That the outer one is at >function scope is incidental.
If the outer loop was contained within an IF statement, could you jump
to outside that statement using your proposed feature? If not then that
is not function scope.
minutes,>> and this was anyway a proof of concept.I could have done that in C but it would have taken more than 5
Yup. And it took less than that to point out problems.
But it solved the problem I wanted to solve! It would solve the problem >Michael S reported! That is, using distinct keywords for two different >things.
I've already used that approach for some decades in my other languages,
but as I showed in the tables I posted, it is not common, and where
used, it was always to break out of all loops.
Anyway, I normally use 'all' instead of a specific number to quit all
loops. A number works too but I dislike it.
That sounds overly specific.
So is breaking out of an inner loop with 'break;'! But it works well as
it's by far the most common requirement. The next most common IME is to
quit all loops (like you do in your example).
In fact, if there are only two nested loops, the inner and outer cover
all the possibilities.
This is actually the argument against the counted multi-level
break: if I add or remove a level of nesting, I have to find and
adjust all of the counts. The labeled break mechanism ties the
`break` or `continue` to another syntactic element (a label), so
No, it's just another set of problems as I said.
You can add new inner loops, delete inner loops, add outer ones, and
each time you will need to consider whether the labels need to be moved,
or extra ones added.
Here's another solution I favour (not implemented), but it only works
for FOR loops:
for i in a..b
for j in c..d
... break i
It's a little like using a label, but here that 'label' is the loop
index. (This won't work in C as there are no formal loop indices.)
if I add or remove a nesting level, I'm still breaking to where
I had intended to before.
Yes, but that might now be the wrong loop.
That said, applying the argument to the labeled case is silly.
Software engineering and good programming practice still matter.
If you are changing the nested looping structure of your
program, then you should know where you want to break to;
presumably your program's behavior depends on it.
Agreed; see below.
I'd say the stronger argument for the labeled control structure
is actually nested switch statements, where I may change a
series of `if`s to a `switch` with a `case` that contains a
nested `switch`, or I may change a `switch` to an `if`; if the
intent is to break out of an enclosing loop, labeled breaks are
resilient to that, but counted breaks are not.
You're assuming that the count in indexed breaks includes switch
statements. It shouldn't; that would be preposterous, and it all still
comes down to the shared 'break' keyword.
How about fixing that first, or even admitting it was wrong, before
loop>> wants to repeat T, in which case it must stay inside.Maybe the original set of loop performed some task T, and the new
Yes.
Or maybe it is really has to quit ALL loops including any future outer
ones. Neither labeling or numbering solves this.
No. If I want to break out of *all* loops, I just make sure
that the outermost loop is labeled thusly.
But in my first example, that is not what you want! It all depends.
I don't like using multi-level loop exit, it's an untidy feature even
though I implement it. And I don't like using labeled solutions, as they >just turn them into thinly disguised gotos.
Labeled loops may also have a new problem with scoping: is the loop name >>> local to this nest of loops, or could an outer loop name especially
clash with other loop elsewhere?
Since labels are, you know, labels, they follow the semantics of
... labels.
Careful here: do you really mean that loop-labels will be in the same >name-space as ordinary labels? That means:
[snip chest thumping puffery]
See there's a bit more to this language-design lark!
I've just done a survey in my major apps and haven't found an instance
where those latter two needed to cross two or more loops.
Anecdotal evidence, I'm afraid.
You're welcome to post your own surveys. Although unless the languages
used in your survey support such features, you may find that hard.
It's easy enough to look it up in the draft document; Keith
posted a link.
Is that that 793-page document? Perhaps you can summarise how it works!
This illustrates one reason why changing a language can be hard:
your idea sounds good at first blush, but it has its own
deficiencies.
I appreciate your concern. I've only been doing this (devising and
implementing systems languages) for 45 years!
That really doesn't mean anything. Just doing something for a
long time doesn't mean you're good at it: I have been shooting
baskets for 45 years, but I will never be a point guard in the
NBA.
And yet I've solved all the problems in this thread and many others.
On 14/10/2026 13:38, Dan Cross wrote:
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]> wrote:
Yes, I am aware that you will tell me that it is justified
because that problem is actually the one worth solving, and the
others are not; you needn't bother. Simply put, I disagree that
that one problem is sufficiently important to warrant its own
solution, particularly when something more general is already
known and available in the language (labeled break/continue).
I missed this bit.
Is labeled break now available in C?
If so, how would it be used here:
while (1) {
switch (x) {
case y:
Break;
where that Break is meant to quit the loop.
Remember that if DMR hadn't made that screw-up in 1972 it would simply
have been as it is above with his choice of keyword in place of Break.
But I would be interested in trying out the new feature.
[snip]
PS: I've just read another long (300 lines) post you made in
reply to bart. Let me express my admiration for your patience
and countenance (that I'm clearly lacking in this case), and
the very clear form and conclusively explained content.
In article <11ao8af$1k8p3$[email protected]>, bart <[email protected]>
wrote:
On 14/10/2026 13:38, Dan Cross wrote:
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]>
wrote:
I'd even suggest that using distinct keywords in the original C
compiler would have made it a tiny bit simpler.)
Unlikely. I'm trying to chase down the citation, but it was
known that getting B to fit on the PDP-7 was a challenge. From
the C history paper,
Perhaps Switch should have been left out then if it was that tight.
Why? It's genuinely useful.
In article <11ao8af$1k8p3$[email protected]>, bart <[email protected]> wrote:
Perhaps Switch should have been left out then if it was that tight.
Why? It's genuinely useful.
No, that has one meaning which is to terminate a block, there are no repercussions as there are with C-break which has two meanings.Sharing a keyword is just crass.
Don't you share `end`?
That could easily have been fixed by DMR choosing to use distinct
keywords. Do you agree so far?
No. You've described what I consider to be a non-problem; a
mild annoyance at best, and certainly not something that
deserves complicating the language for.
So we can look at N3355 for discussion: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
And yet I've solved all the problems in this thread and many others.
Congratulations! And yet, despite you being obviously more
intelligent than all of Ritchie, McIlroy, Thompson, Johnson,
Kernighan, Plauger, and all of those who have and continue to
contribute to the development of C combined,
name on the list of contributors to that language, nor does
anyone other than you use your language.
But keep shooting hoops, bart. Maybe some day a talent scout
will see you in your driveway and give you a starting position
on a playoff team.
On 14/10/2026 13:38, Dan Cross wrote:
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]> wrote:
Yes, I am aware that you will tell me that it is justified
because that problem is actually the one worth solving, and the
others are not; you needn't bother. Simply put, I disagree that
that one problem is sufficiently important to warrant its own
solution, particularly when something more general is already
known and available in the language (labeled break/continue).
I missed this bit.
Is labeled break now available in C?
If so, how would it be used here:
while (1) {
switch (x) {
case y:
Break;
where that Break is meant to quit the loop.
On 14/10/2026 20:30, Dan Cross wrote:
break loop; // this doesn't break the loop
breakloop; // this doesn't break the loop
But as Keith pointed out, W14 is now entertaining proposals to
add labeled `break` to the language. I haven't looked myself,
but if that is usable in a `switch` context, then it would solve
the problem for good.
OK. Although in that form, it really is little different from
'goto'. I believe the main difference is that the label goes at the
beginning of the loop rather than the end!
And maybe those scoping rules will be different: goto labels have function-wide scope.
On 14/10/2026 20:30, Dan Cross wrote:
[snip more of the same already hashed and rehashed ad naseum]
As for multiple nested loops, this will fix that too, that's great. We
just require some real examples of that being needed!
And yet I've solved all the problems in this thread and many others.
Congratulations! And yet, despite you being obviously more
intelligent than all of Ritchie, McIlroy, Thompson, Johnson,
Kernighan, Plauger, and all of those who have and continue to
contribute to the development of C combined,
Well, my personal C has 'breakloop'! Usually these micro-extensions are >shortlived, but I'll keep this one.
we don't see your
name on the list of contributors to that language, nor does
anyone other than you use your language.
It's enough that I used it and benefited from it.
This is that last example in my syntax (if the switch were the only >statement within the loop otherwise two more tokens needed):
doswitch x
when 3 then exit
end
7 tokens vs. 20 tokens using N3355, and it's repeatable within the
function because 'exit' is relative.
But keep shooting hoops, bart. Maybe some day a talent scout
will see you in your driveway and give you a starting position
on a playoff team.
I really don't care. Most things in the world are not going the way I'd >like, and I'm not the only one who thinks that.
This language stuff is small potatoes but it gives me kick to have long
ago come up with solutions that some languages take ... 54 years to
produce a compromise.
Anyway, at least you've been a sport, unlike Mr. P.
On Wed, 14 Oct 2026 19:30:28 -0000 (UTC)
[email protected] (Dan Cross) wrote:
In article <11ao8af$1k8p3$[email protected]>, bart <[email protected]>
wrote:
On 14/10/2026 13:38, Dan Cross wrote:
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]>
wrote:
I'd even suggest that using distinct keywords in the original C
compiler would have made it a tiny bit simpler.)
Unlikely. I'm trying to chase down the citation, but it was
known that getting B to fit on the PDP-7 was a challenge. From
the C history paper,
Perhaps Switch should have been left out then if it was that tight.
Why? It's genuinely useful.
C switch is in the middle between low level construct (computed goto)
and higher level select/case/whatever of many other languages.
I suppose that implementing true low level alternative would have been simpler for compiler. And it would be even more powerful than current construct. Of course, also more dangerous, but being dangerous is not against C philosophy.
int foo()
{
...
case 42:
....
switch(bar(x)); // can go not just to 6 and 7, but to 42 as well.
// if there is no 'default:' in the scope then default ends up here
....
case 6:
...
case 7:
etc...
}
bart <[email protected]> writes:
On 14/10/2026 13:38, Dan Cross wrote:
In article <11anobe$1dt0e$[email protected]>, bart <[email protected]> wrote:
Yes, I am aware that you will tell me that it is justified
because that problem is actually the one worth solving, and the
others are not; you needn't bother. Simply put, I disagree that
that one problem is sufficiently important to warrant its own
solution, particularly when something more general is already
known and available in the language (labeled break/continue).
I missed this bit.
How??
I've mentioned it more than once in this thread.
[...]
In article <11aoqa9$1rgda$[email protected]>, bart <[email protected]> wrote:....
On 14/10/2026 20:30, Dan Cross wrote:
[snip more of the same already hashed and rehashed ad naseum]
As for multiple nested loops, this will fix that too, that's great. We
just require some real examples of that being needed!
Here's a pretty terrible way to write part of a lexical
analyzer. I just typed this in an hour or so ago.
[snip more of the same already hashed and rehashed ad naseum]
On 15/10/2026 02:26, Dan Cross wrote:
In article <11aoqa9$1rgda$[email protected]>, bart <[email protected]> wrote:....
On 14/10/2026 20:30, Dan Cross wrote:
[snip more of the same already hashed and rehashed ad naseum]
As for multiple nested loops, this will fix that too, that's great. We
just require some real examples of that being needed!
Here's a pretty terrible way to write part of a lexical
analyzer. I just typed this in an hour or so ago.
Wow, it's impressive that you went to that trouble just to prove a point >about nested loops. (Even if it might have been a little bit contrived.)
But this is an interesting pattern with all those breaks:
[snip]
It seems most uses of 'break;' to break out of a loop have disappeared
to be replaced with labeled versions.
The remaining breaks are switch-breaks.
Then I start looking at some of those "breaks;". Some (maybe one) is at >top-level, it jumps to the end of that switch, so the end of the while,
so is really 'continue'.
Most are in nested switches, some of those jump to a 'break loop'. Some
jump somewhere else...
Basically this is spaghetti code (I know you said it was terrible); your >eyes glaze over with breaks everywhere and you give up trying to figure
out the control flow.
There are examples like this:
continue;
default:
break;
}
break loop;
Do you even need 'default: break;}' or even an empty default:?
I then tried an experiment where I got rid of switch-break, to see what
C code with automatic switch-break would look like.
It was a big improvement, now that you know that every case-blocks
proceeds to the end of that switch, and you don't need to double-check
every 'break' to see if it's to do with switches or loops:
break loop;
break loop;
break loop;
break loop;
break loop;
break loop;
break loop;
break loop;
break loop;
break loop;
break loop;
break loop;
break loop;
break sloop;
break loop;
break loop;
break loop;
break loop;
break;
break loop;
break;
All these are known to be loops, even 'break;'.
But also, labeled versions except three 'break loops' can be written as >'break', since 'switch break' does not exist. You're left with:
break loop;
break loop;
break loop;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
(Not ordered.) Compare with the first set.
[snip more of the same already hashed and rehashed ad naseum]
Perhaps that reused keyword thing is a bigger deal than you think. The >effect of it is unnecessary obfuscation.
In article <11aoqa9$1rgda$[email protected]>, bart <[email protected]> wrote:
On 14/10/2026 20:30, Dan Cross wrote:
[snip more of the same already hashed and rehashed ad naseum]
As for multiple nested loops, this will fix that too, that's great. We
just require some real examples of that being needed!
Here's a pretty terrible way to write part of a lexical
analyzer. I just typed this in an hour or so ago.
[200+ lines of code]
[email protected] (Dan Cross) writes:
In article <11aoqa9$1rgda$[email protected]>, bart <[email protected]> wrote:
On 14/10/2026 20:30, Dan Cross wrote:
[snip more of the same already hashed and rehashed ad naseum]
As for multiple nested loops, this will fix that too, that's great. We
just require some real examples of that being needed!
Here's a pretty terrible way to write part of a lexical
analyzer. I just typed this in an hour or so ago.
[200+ lines of code]
This code provides an excellent example of why multi-level breaks
should not be added to C.
The code would be easier to understand
if all the 'break <label>;' lines were replaced with one of 'goto >TOKEN_COMPLETE;' or 'goto COMMENT_COMPLETE;', as appropriate,
and with the loop labels being removed and the two new labels put
in at the appropriate places.
In article <11aqbqv$2avn3$[email protected]>, bart <[email protected]> wrote:I am stating that 'break' used to fix C's poor 'switch' feature
Perhaps that reused keyword thing is a bigger deal than you think. The
effect of it is unnecessary obfuscation.
This is certainly not evidence of that. This is just your
assertion that you took a silly example and apparently (maybe?)
improved it, based on some unstated, but apparently subjective,
criteria.
On 15/10/2026 12:45, Dan Cross wrote:Enough worked that I decided to try a speed test. Both use exactly the
In article <11aqbqv$2avn3$[email protected]>, bart <[email protected]> wrote:
I am stating that 'break' used to fix C's poor 'switch' featurePerhaps that reused keyword thing is a bigger deal than you think. The
effect of it is unnecessary obfuscation.
This is certainly not evidence of that. This is just your
assertion that you took a silly example and apparently (maybe?)
improved it, based on some unstated, but apparently subjective,
criteria.
interferes with 'break' used for loops.
It's not even my opinion: it's fact. In your example, about a third of 'break' tokens are for taking care of switch.
My opinion is that it generates pointless clutter (this it would do even
if a different keyword was used), and it can get confusing when switch
and loop are mixed up.
I actually took your program and ported it to my syntax, as I was
curious how it would look. This is the result:
https://github.com/bart-2026/langs/blob/main/lexertest.m
(It's been spaced out more, vertically.)
Well, here are some stats:
I did try and run mine:
In article <[email protected]>,
Tim Rentsch <[email protected]> wrote:
[...]
It is probably true that this snippet is a good example of how
labeled break/continue can be abused. [...]
The point was to illustrate a contrived
example where one might break out of nested switch statements,
loops inside of switch, switch inside of loops, loops inside of
switch inside of loops, and so on.
[...]
[email protected] (Dan Cross) writes:
In article <11aoqa9$1rgda$[email protected]>, bart <[email protected]> wrote:
On 14/10/2026 20:30, Dan Cross wrote:
[snip more of the same already hashed and rehashed ad naseum]
As for multiple nested loops, this will fix that too, that's great. We
just require some real examples of that being needed!
Here's a pretty terrible way to write part of a lexical
analyzer. I just typed this in an hour or so ago.
[200+ lines of code]
This code provides an excellent example of why multi-level breaks
should not be added to C.
The code would be easier to understand
if all the 'break <label>;' lines were replaced with one of 'goto TOKEN_COMPLETE;' or 'goto COMMENT_COMPLETE;', as appropriate,
and with the loop labels being removed and the two new labels put
in at the appropriate places.
On 15/10/2026 12:45, Dan Cross wrote:
In article <11aqbqv$2avn3$[email protected]>, bart <[email protected]> wrote:
Perhaps that reused keyword thing is a bigger deal than you think. The
effect of it is unnecessary obfuscation.
This is certainly not evidence of that. This is just your
assertion that you took a silly example and apparently (maybe?)
improved it, based on some unstated, but apparently subjective,
criteria.
I am stating that 'break' used to fix C's poor 'switch' feature
interferes with 'break' used for loops.
It's not even my opinion: it's fact. In your example, about a third of >'break' tokens are for taking care of switch.
My opinion is that it generates pointless clutter (this it would do even
if a different keyword was used), and it can get confusing when switch
and loop are mixed up.
I actually took your program and ported it to my syntax, as I was
curious how it would look. This is the result:
https://github.com/bart-2026/langs/blob/main/lexertest.m
(It's been spaced out more, vertically.)
There were some tricky bits of the C to translate, such as:
break;
default:
break;
}
default:
*tp++ = ch;
break;
}
}
*tp++ = '\0';
tt = TkSTRING;
where it seems to break from one switch then sneakily falls through into
the default clauses of the enclosing one!
Well, here are some stats:
C Mine
Size 3374 2997 characters (both with hard tabs)
Non-blank lines 210 174 Lines
I did try and run mine:
c:\mapps>test
1234
tok: tt = tkident, token = '1234'
abc
tok: tt = tkident, token = 'abc'
It shows both of these as an identifier. But yours does the same:
c:\c>a
1234
tok: tt = 1003, token = '1234'
abc
tok: tt = 1003, token = 'abc'
Whatever '1003' means, it's showing the same. So it will do (I don't
care if the code is buggy, just whether my version is reasonably faithful).
Of course, my actual lexers have a different structure.
On 15/10/2026 13:17, Tim Rentsch wrote:
[email protected] (Dan Cross) writes:
In article <11aoqa9$1rgda$[email protected]>, bart <[email protected]> wrote: >>>
On 14/10/2026 20:30, Dan Cross wrote:
[snip more of the same already hashed and rehashed ad naseum]
As for multiple nested loops, this will fix that too, that's great. We >>>> just require some real examples of that being needed!
Here's a pretty terrible way to write part of a lexical
analyzer. I just typed this in an hour or so ago.
[200+ lines of code]
This code provides an excellent example of why multi-level breaks
should not be added to C.
Actually most of those 'break-labels' are not multi-level breaks.
But they have to use that form because they are inside 'switch'.
(Unless you consider 'levels' to include switch statements as loops; I >don't. I mean, there is a 'continue' in there too inside switch, which >doesn't use the label. So how can that not be multi-level but 'break' is?)
It all goes back to that bad decision about 'break' that everyone is
playing down.
The code would be easier to understand
if all the 'break <label>;' lines were replaced with one of 'goto
TOKEN_COMPLETE;' or 'goto COMMENT_COMPLETE;', as appropriate,
and with the loop labels being removed and the two new labels put
in at the appropriate places.
Once you have to write /actual labels/, which aren't even in local scope >within the loop, then 'break label' doesn't buy much over 'goto label':
loop:
while () {
switch () {
case x:
break loop;
}
}
while () {
switch () {
case x:
goto loopend;
}
}
loopend:
The latter will at least work with every compiler.
In article <11aqpl3$2gdup$[email protected]>, bart <[email protected]>
wrote:
On 15/10/2026 12:45, Dan Cross wrote:
In article <11aqbqv$2avn3$[email protected]>, bart <[email protected]>
wrote:
Perhaps that reused keyword thing is a bigger deal than you
think. The effect of it is unnecessary obfuscation.
This is certainly not evidence of that. This is just your
assertion that you took a silly example and apparently (maybe?)
improved it, based on some unstated, but apparently subjective,
criteria.
I am stating that 'break' used to fix C's poor 'switch' feature
interferes with 'break' used for loops.
Sure.
It's not even my opinion: it's fact. In your example, about a third
of 'break' tokens are for taking care of switch.
Ok.
My opinion is that it generates pointless clutter (this it would do
even if a different keyword was used), and it can get confusing when
switch and loop are mixed up.
Ok.
I actually took your program and ported it to my syntax, as I was
curious how it would look. This is the result:
https://github.com/bart-2026/langs/blob/main/lexertest.m
(It's been spaced out more, vertically.)
There were some tricky bits of the C to translate, such as:
break;
default:
break;
}
default:
*tp++ = ch;
break;
}
}
*tp++ = '\0';
tt = TkSTRING;
where it seems to break from one switch then sneakily falls through
into the default clauses of the enclosing one!
Yup.
Well, here are some stats:
C Mine
Size 3374 2997 characters (both with hard
tabs) Non-blank lines 210 174 Lines
Those seem like pretty meaningless statistics. I could really
care less about 377 fewer bytes. Naturally, different languages
will express these things differently.
I did try and run mine:
c:\mapps>test
1234
tok: tt = tkident, token = '1234'
abc
tok: tt = tkident, token = 'abc'
It shows both of these as an identifier. But yours does the same:
c:\c>a
1234
tok: tt = 1003, token = '1234'
abc
tok: tt = 1003, token = 'abc'
Yup. It's a poorly written program; I am not surprised there
are bugs. It wasn't meant to be an illustration of exemplary
programming, it was meant to illustrate a use case for a
language construct that addresses a use case you appeared to
want support for, but that are now upset about, because it was
not provided in the way you like. Or something.
Whatever '1003' means, it's showing the same. So it will do (I don't
care if the code is buggy, just whether my version is reasonably
faithful).
This is actually a good example of the problem you often run
into in these endless c.l.c threads: You seem to take a thing
that was something that was only meant to show one thing, and
asserting that it represents something other than what it was
meant to show, and no matter how many times it is explained to
you that it is not, in fact, what you seem to think that it is,
you persist in your delusion and think that it proves something.
But it doesn't, since you are starting from a false premise, at
which point you whine that you are picked on, treated poorly,
misunderstood, or generally dismissed, to which you conclude
that this can only be due to a slavish devotion to C as it is,
and a refusal to entertain that the language is not perfect. It
is totally lost on you that people may be objecting to what you
are saying on its own merits, since (ironically) you don't seem
able to admit that your own ideas may have their own
deficiencies.
This whole discussion could be summarized as:
Bart: "C sucks because Dennis Ritchie stupidly reused `break`
for both loops and switch. He was a tasteless fool."
All: "You can work around that really easily."
Keith: "C added labeled break and continue...."
Bart: "C sucks. My language is better. Here, I fixed C in 4
lines of code with my `breakloop`, but it still sucks
because C is hopeless."
Me: "No, the real problem is that there's no structured way
break out of nested contexts; your thing only addresses
one special case, and does not compose, so can't cover
the general case."
Bart: "No, it's the overloading. C is terrible and you're all
just too blind to see it. You are all fools, like
Dennis Ritchie."
Me: "I mean, Keith told you how the language is being changed
to address your problem _and_ the other problems in this
general category."
Bart: "Those other problems don't matter. C will never change.
It will suck forever. I mean, have you ever even seen a
use case for these labeled blocks? I don't like them,
therefore they suck, just like C. They also suck
because they solve a problem I don't care about. I have
been doing this for 45 years."
Me: "Here's a program that illustrates the problem. The code
is shit, but shows how it can be used...."
Bart: "This program sucks! You don't _need_ to do it this
way."
Me: "...I mean, I told you it sucked when I posted it...."
Bart: "...I rewrote it in my language. I saved 377 bytes. See
how much C sucks now? My language is better.
Me: "...."
Bart: "My lexer is 50% faster than your lexer. My production
code is an order of magnitude faster. I am a very smart
boy, and deserve a very special gold star on my report
card."
Me: "...Bruh."
Bart: "Dennis Ritchie was a fool. A fool, I say! Haha!
Ahahaha! Muwhahaha!"
In article <11aqpl3$2gdup$[email protected]>, bart <[email protected]> wrote:
Those seem like pretty meaningless statistics.
Naturally, different languages will express these things differently.
This whole discussion could be summarized as:
Bart: "C sucks because Dennis Ritchie stupidly reused `break`
for both loops and switch. He was a tasteless fool."
All: "You can work around that really easily."
Keith: "C added labeled break and continue...."
Bart: "C sucks. My language is better. Here, I fixed C in 4
lines of code with my `breakloop`, but it still sucks
because C is hopeless."
Me: "No, the real problem is that there's no structured way
break out of nested contexts; your thing only addresses
one special case, and does not compose, so can't cover
the general case."
Bart: "No, it's the overloading. C is terrible and you're all
just too blind to see it. You are all fools, like
Dennis Ritchie."
Me: "I mean, Keith told you how the language is being changed
to address your problem _and_ the other problems in this
general category."
Bart: "Those other problems don't matter. C will never change.
It will suck forever. I mean, have you ever even seen a
use case for these labeled blocks? I don't like them,
therefore they suck, just like C. They also suck
because they solve a problem I don't care about. I have
been doing this for 45 years."
Me: "Here's a program that illustrates the problem. The code
is shit, but shows how it can be used...."
Bart: "This program sucks! You don't _need_ to do it this
way."
Me: "...I mean, I told you it sucked when I posted it...."
Bart: "...I rewrote it in my language. I saved 377 bytes. See
how much C sucks now? My language is better.
Me: "...."
Bart: "My lexer is 50% faster than your lexer. My production
code is an order of magnitude faster. I am a very smart
boy, and deserve a very special gold star on my report
card."
Me: "...Bruh."
Bart: "Dennis Ritchie was a fool. A fool, I say! Haha!>Ahahaha! Muwhahaha!"
On 15/10/2026 15:57, bart wrote:I'm mildly curious about this even if no one else is (or they think it
On 15/10/2026 12:45, Dan Cross wrote:
In article <11aqbqv$2avn3$[email protected]>, bart <[email protected]> wrote: >>I am stating that 'break' used to fix C's poor 'switch' feature
Perhaps that reused keyword thing is a bigger deal than you think. The >>>> effect of it is unnecessary obfuscation.
This is certainly not evidence of that. This is just your
assertion that you took a silly example and apparently (maybe?)
improved it, based on some unstated, but apparently subjective,
criteria.
interferes with 'break' used for loops.
It's not even my opinion: it's fact. In your example, about a third of
'break' tokens are for taking care of switch.
My opinion is that it generates pointless clutter (this it would do
even if a different keyword was used), and it can get confusing when
switch and loop are mixed up.
I actually took your program and ported it to my syntax, as I was
curious how it would look. This is the result:
https://github.com/bart-2026/langs/blob/main/lexertest.m
(It's been spaced out more, vertically.)
Well, here are some stats:
I did try and run mine:Enough worked that I decided to try a speed test. Both use exactly the
same algorithm, and I didn't expect either to be fast.
Still, the version in my language/compiler was 50% faster than the C compiled with gcc-O3. I don't know why.
On Sun 10/11/2026 6:33 AM, David Brown wrote:
It is quite obvious that it is easy to write code with loops + break
within a switch. It is equally obvious that it is easy to avoid
such constructs - there are always ways to avoid a "break" in a
loop, and if the code run within a switch case is complex, it is
often practical to refactor it into a separate function. But
presumably Michael has reasons not do do that.
Um... The common pattern for a "search"-style loop looks as follows
for (/* domain condition */)
{
...
if (/* search condition */)
break;
...
}
So, loops that terminate with `break` are the mainstay of every
competently written code. Moving the "early termination" condition
into the loop header (i.e. lumping the search condition with the
domain condition) is a very ugly anti-pattern in most cases. Moreover, majority of the loops in an average C program are such "search"-style
loops, meaning that they do have an "early termination" condition.
Now, while overwhelming majority of my loops would use `if` to check
the "early termination", I can imagine that there sill be cases where
switch` is applicable and more appropriate than an `if`. Yes, a
switch` can always be replaced with an `if` ladder, but being _forced_
to do so by a language limitation doesn't look right.
And writing a separate function just to work around a weird language limitation... that doesn't look right either.
[.. some syntanx changes were made as part of C23 ..]
C23 made some changes with the goal of allowing a label to be
immediately followed by a declaration or `}`. It did so by changing
the grammar for a compound-statement:
compound-statement:
{ block-item-list[opt] }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
unlabeled-statement
label
This means that in
switch (x) {
case 'A':
case 'B':
case 'C':
puts("blah");
}
*there is no labeled-statement*. Instead, each of `case 'A':`,
`case 'B':`, `case 'C':`, and `puts("blah");` is a block-item, and all
the block-items are at the same syntactic level within the compound-statement. (The indentation is still appropriate IMHO.)
Since control jumps to "the statement or declaration following the
matched case label", there is no fallthrough. If x == 'A', control
jumps directly to the puts() call.
In C17 and earlier, the same wording implies that when x=='A', control
jumps to the statement
case 'B': case 'C': puts("blah");
so one might arguably refer to that as "fallthrough". In C23,
case 'B': case 'C': puts("blah");
is not a statement.
A weird but mostly harmless consequence of this is that C23 keeps
the syntactic construct of a *labeled-statement*, but it's used
extremely rarely. Any C17-or-earlier labeled-statement at the
top level of an enclosing compound-statement is no longer a C23 labeled-statement, even though it looks like one. In C23, a labeled-statement can only occur in an odd construct like this:
if (condition)
LABEL: statement;
The proposal that led to this suggested an optional additional change,
making labels outside of compound statements an obsolescent feature.
That part of the proposal was not adopted.
...
My syntax has cleaner and simpler syntax compared to C,...
But it seems people don't value cleaner, more productive syntax when it
it comes to 'serious' languages, only scripting ones....
[snip]
You know, I could well be right about all those points. Maybe mylanguage that has been around for 45 years really is a sweeter, cleaner
'C' which has solved most of the latter's quirks.
And maybe other people's responses to that is just sour grapes.
However one of interests is PL design - specifically at this level - and
how C gets it so wrong, how people defend it so much, how it evolves so >glacially, how much fixing its shortcomings is offloaded to tools, is >fascinating.
It would have been nice to have a more objective discussion about such >aspects, with people not afraid to be a LOT more critical of C and its
tools that they have been.
But I guess this is the wrong forum for that.
Bart: "Dennis Ritchie was a fool. A fool, I say! Haha!>Ahahaha! Muwhahaha!"
Simplest kind of function pointer:
[snip; don't care]
(Apparently it would be this, according to a tool which transpiles to C:
void (*one[10])(void), (*two[10])(void);
Fucking hell. Actually I didn't call DMR a fool. I did mention a
'numskull' which I now withdraw; I prefer to criticise ideas not people.
But this is a disaster.)
On Tue, 13 Oct 2026 07:23:40 -0000 (UTC), Waldek Hebisch wrote:
So what those counts indicate: majority of loops is simple, that is
have no early exit. Vast majority of early exits is done via
'return'.
My experience in my own C code is quite the opposite. Lots of loops
have exits in the middle, leading me to use forms like “for (;;)”. I
also try to avoid putting “return” anywhere other than the end of a function, to make it easier to see the flow of control.
Janis Papanagnou <[email protected]> writes:
On 2026-10-06 03:05, Keith Thompson wrote:
[...]
A weird but mostly harmless consequence of this is that C23 keeps
the syntactic construct of a *labeled-statement*, but it's used
extremely rarely. Any C17-or-earlier labeled-statement at the
top level of an enclosing compound-statement is no longer a C23
labeled-statement, even though it looks like one. In C23, a
labeled-statement can only occur in an odd construct like this:
if (condition)
LABEL: statement;
You've been arguing on the implicit difference in the language
definition here. That's all a fine explanation.
What I wonder about is what you find "odd" with that construct.
For folks who use jumps and labels (not me) that looks not too
odd to me; I can imagine programming cases where that may be
useful.
It's unlikely that I'd write something like that. If I did,
I'd use braces:
if (condition) {
LABEL: statement;
}
I'm sometimes willing to omit optional braces, but almost exclusively
in cases where the entire construct is on one line:
if (condition) statement;
Aside from that, writing an if statement and providing a way to bypass
the test feels odd (to me). Presumably there's a `goto LABEL;`
elsewere in the same function. I'd look for a clearer way to structure
the code.
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
Concernig 'return', having it in place where all work inside
function is done help me to see flow control and avoids
complications. In case of search functions it means return from the
middle of the loop. IMO possible alternatives like flag variables or
break and retrun after loop are worse.
On Fri, 16 Oct 2026 15:24:01 -0000 (UTC), Waldek Hebisch wrote:
Concernig 'return', having it in place where all work inside
function is done help me to see flow control and avoids
complications. In case of search functions it means return from the
middle of the loop. IMO possible alternatives like flag variables or
break and retrun after loop are worse.
Code tends to do a lot of dynamic resource allocation these days, and
that requires cleanup. Doing a direct “return” from the middle of a >function body doesn’t allow for that.
Unless you use a GCC extension like “defer”, I suppose.
Keith Thompson <[email protected]> writes:
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
Definitely.
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is unquestionably better.
Unless you use a GCC extension like “defer”, I suppose.
In article <11arjmc$2qid7$[email protected]>, bart <[email protected]> wrote:So why is this style of syntax popular within scripting languages? (Lua, Julia, Ruby...)
Has it truly
never occurred to you that many other people just don't consider
your syntax significantly cleaner, or more productive?
Perhaps people dismiss what you say because, despite your
self-aggrandizing words, you've shown that you don't actually
know C very well,
For someone who claims to want to discuss C objectively, you
sure do make a lot of subjective statements.
[snip; don't care]
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
[...]
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
[...]
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
I do like the fact that it doesn't conflate goto labels with loop
names, but I still prefer the "NAME: for (;;)" form, partly because
it's consistent with several other languages.
One minor drawback, IMHO, is that the name is easier to miss, because
it's not at the beginning of the line. This is based on zero experience using it.
(The same problem exists with function names. Personally, I just
tolerate that rather than using the common convention of splitting the
return type and function name across two lines. I think I would have preferred a syntax that puts the function name first, but I wouldn't
suggest changing it. I mildly dislike the convention of writing
int
func(void)
for reasons that are vague enough that I won't go into them.)
What's often stated also is how successful C has been, but that
doesn't magically make the syntax wonderful.
On 16/10/2026 13:40, Dan Cross wrote:
In article <11arjmc$2qid7$[email protected]>, bart <[email protected]> wrote:
Has it truly
never occurred to you that many other people just don't consider
your syntax significantly cleaner, or more productive?
So why is this style of syntax popular within scripting languages? (Lua, >Julia, Ruby...)
Those are considered more productive.
Perhaps people dismiss what you say because, despite your
self-aggrandizing words, you've shown that you don't actually
know C very well,
See the type syntax example below. How well do you need to know a
language to see that that is just effing crazy? This is supposed to be a >HLL, not a puzzle that needs to be solved or decoded via algorithms or >employing tools!
For someone who claims to want to discuss C objectively, you
sure do make a lot of subjective statements.
Concerning type declaration syntax, lots of people including the C
creators agree that it was misguided.
If lots of people agree, is that still being subjective? This is the
example I think used in K&R:
char *(*(**foo [][8])())[];
Most would consider this gobbledygook even if you know the rules. It is >atrocious syntax. And what's 'foo' doing in the middle of it!
I think being defensive about it is being subjective, as you demonstrate >here:
[snip; don't care]
That is pretty much the attitude here in a nutshell.
What's often stated also is how successful C has been, but that doesn't >magically make the syntax wonderful.
If DMR had instead produced a language that looked like mine (say like
one of the Algols), and I came along in 2026 and proposed a syntax that >looked like the above, what do you think the response would be?
I would rightly be laughed out of the forum.
So being 'objective' means disregarding history and widespread adoption.
The latter doesn't make the language better, just more tolerated, with
more effort put into tools to make it practical to use (with a nice
sideline in teaching all its ins and outs).
Anyway, to me, pretty much the whole of C looked as badly and crudely
put together as that, when I first came across it in 1982. My background
had been with quite different languages.
bart <[email protected]> writes:
[...]
What's often stated also is how successful C has been, but that
doesn't magically make the syntax wonderful.
NOBODY THINKS C'S SYNTAX IS WONDERFUL.
In article <11auad0$3no1k$[email protected]>, bart <[email protected]> wrote:
Those are considered more productive.
...and you think that's because of the syntax, and not the high
level nature of those languages?
Yes, the syntax is pretty gnarly; Dennis Ritchie even said as
much. Fixed in Go and Rust, but also, I doubt you've ever in
your life had a variable of type array of array of length 8 of
a pointer to a pointer to a function returning an array of
pointers to char. Finding the most ridiculous example you can
is not really evidence of anything besides your weird obsession
with finding abstruse corner cases and holding them up as
reasons to dislike C.
If DMR had instead produced a language that looked like mine (say like
one of the Algols), and I came along in 2026 and proposed a syntax that
looked like the above, what do you think the response would be?
But he didn't, and you didn't, so this is a meaningless
historical, "what if?"
So being 'objective' means disregarding history and widespread adoption.
Well, no...both of those are factors in choosing a language or
not. We can discuss the semantics of the language, it's syntax,
etc; but we can also discuss tooling, engineering resources
availability (can you find programmers who know C? More like,
can you find programmers who _don't_ know C, amirite?), library
and platform support, and so on.
Is C a good language? Meh, it's not the worst, but far from the
best I've seen. Was it a bad language in 1972, when it was
targeting a PDP-11/20? No, it was pretty decent for that era.
Did it do all the stuff that fancy languages with advanced
compilers that ran on big machines could do? No. Did it need
to? Also no.
In article <11audde$3oci5$[email protected]>,
Keith Thompson <[email protected]> wrote:
bart <[email protected]> writes:
[...]
What's often stated also is how successful C has been, but that
doesn't magically make the syntax wonderful.
NOBODY THINKS C'S SYNTAX IS WONDERFUL.
The funny thing is: I actually do.
I may be the only person here who actually thinks the syntax of C's
"switch" statement is just fine. Once you realize that it *is* more of a computed goto
sense (to me, anyway). I have no problem with a declaration like:
int i,j,*ip,arr[10],foo(int bar);
Some would say that declares lots of different types of objects, but I
think of them all as ints (which is what the declaration is telling us).
In article <11audde$3oci5$[email protected]>,
Keith Thompson <[email protected]> wrote:
bart <[email protected]> writes:
[...]
What's often stated also is how successful C has been, but that
doesn't magically make the syntax wonderful.
NOBODY THINKS C'S SYNTAX IS WONDERFUL.
The funny thing is: I actually do.
['switch' topic - snipped]
["if (a = b)" topic - snipped]
FWIW, to take another popular whipping boy of C, I also actually like the variable declaration syntax -
which many people like to criticize as
"backwards" or "inside out". Once you get used to it, it makes perfect
sense (to me, anyway). [...]
bart <[email protected]> writes:
[...]
What's often stated also is how successful C has been, but that
doesn't magically make the syntax wonderful.
NOBODY THINKS C'S SYNTAX IS WONDERFUL.
We surrender. You win. Stop fighting.
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
Definitely.
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is unquestionably better.
Unquestionably? Why?
I do like the fact that it doesn't conflate goto labels with loop
names, but I still prefer the "NAME: for (;;)" form, partly because
it's consistent with several other languages.
On Fri, 16 Oct 2026 15:00:27 -0700
Keith Thompson <[email protected]> wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
Definitely.
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
I don't know why Tim prefers it.
I prefer it (strongly) because it is different from regular label. So
reader that wants to understand a flow of the program should not be
concerned with possibility of jumping to it from places outside for().
I do like the fact that it doesn't conflate goto labels with loop
names, but I still prefer the "NAME: for (;;)" form, partly because
it's consistent with several other languages.
You mentioned itself that in Ada loop labels are distinct from regular labels. I would think that Ada alone easily outweighs "several other languages" if we compare by number (and likely by quality) of man-hours invested into thinking and discussion of syntactic features.
Anyway I value appeal to success more than appeal to authority so by my
own standards the argument above is weak.
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
Definitely.
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
[snip]
I was around when Ada was being developed and refined, a process that
took years.
By contrast, C looks like it was just thrown together with little
thought, and probably that is exactly what happened.
[snip]
Keith Thompson <[email protected]> writes:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
Definitely.
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
Before I respond I'd like to ask you to list as many potential differentiators as you can think of, without regard to which of
the two suggestions each one benefits, and without saying which
ones you think favor one choice or the other. If you do that I
can try to go through your list, say which ones I think are
significant, which of the two choices each one favors, and maybe
also assign some sort of priority ranking. Also that would give
me a chance to think about whether there are other differentiators
not on your list but that could seem to me to be relevant.
On 17/10/2026 04:19, Dan Cross wrote:
In article <11auad0$3no1k$[email protected]>, bart <[email protected]> wrote:
Those are considered more productive.
...and you think that's because of the syntax, and not the high
level nature of those languages?
It's a combination.
Yes, the syntax is pretty gnarly; Dennis Ritchie even said as
much. Fixed in Go and Rust, but also, I doubt you've ever in
your life had a variable of type array of array of length 8 of
a pointer to a pointer to a function returning an array of
pointers to char. Finding the most ridiculous example you can
is not really evidence of anything besides your weird obsession
That was the first one I saw online next to a quote from K&R and I
assumed it was from the book. In fact the example from the book is this:
char (*(*x())[])()
I've no idea what the means either. The point is not that the examples
are ridiculous, but that they are hard to convert to and from LTR form
which is how we think. With LTR syntax it becomes utterly trivial to
read or write them, no matter how complex.
(There's a tool called CDECL that translates types from C syntax to LTR >English or vice versa. It calls the C versions 'gibberish'. This is a
real thing!)
with finding abstruse corner cases and holding them up as
reasons to dislike C.
The first example I gave was the simplest form of function pointer,
where the syntax is 'void(*)(void)'. Hardly a corner case, and it
rapidly goes downhill.
If meeting C for the first time, that does not bode well. If the
designers did not care about this, that does not inspire confidence in
the rest of the language.
If DMR had instead produced a language that looked like mine (say like
one of the Algols), and I came along in 2026 and proposed a syntax that
looked like the above, what do you think the response would be?
But he didn't, and you didn't, so this is a meaningless
historical, "what if?"
You don't get the point.
If C had used LTR type syntax and somebody
proposed using inside-out back-and-forth syntax like 'void(*)(void)',
they'd think they were having a laugh, as it would be ridiculous.
But this is exactly what I think about it anyway, no matter that 100
million programs have battled with it for 50 years.
So being 'objective' means disregarding history and widespread adoption.
Well, no...both of those are factors in choosing a language or
not. We can discuss the semantics of the language, it's syntax,
etc; but we can also discuss tooling, engineering resources
availability (can you find programmers who know C? More like,
can you find programmers who _don't_ know C, amirite?), library
and platform support, and so on.
Yes, this is my point; it is tolerated, and people learn to work with
it. But how much extra effort has been expended, compared if they'd
tried a bit harder to get a better language at the start? Or even during
its first decade.
Is C a good language? Meh, it's not the worst, but far from the
best I've seen. Was it a bad language in 1972, when it was
targeting a PDP-11/20? No, it was pretty decent for that era.
Disagree.
Did it do all the stuff that fancy languages with advanced
compilers that ran on big machines could do? No. Did it need
to? Also no.
I think C was first created for PDP7 with 4K words, then moved to PDP11 >(don't know the spec).
[snip]
My point is you can't excuse C being what it is due to hardware limitations.
I used PDP11 quite a bit (/34) and that had a decent Fortran implementation.
My own stuff was done in my spare time for no extra pay, on 8-bit
machines I helped develop for my company, without the backing of Bell Labs.
On 17/10/2026 17:39, Michael S wrote:
On Fri, 16 Oct 2026 15:00:27 -0700
Keith Thompson <[email protected]> wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
Definitely.
There's a proposal for C2y to use goto labels as loop names, and
a competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
I don't know why Tim prefers it.
I prefer it (strongly) because it is different from regular label.
So reader that wants to understand a flow of the program should not
be concerned with possibility of jumping to it from places outside
for().
I do like the fact that it doesn't conflate goto labels with loop
names, but I still prefer the "NAME: for (;;)" form, partly because
it's consistent with several other languages.
You mentioned itself that in Ada loop labels are distinct from
regular labels. I would think that Ada alone easily outweighs
"several other languages" if we compare by number (and likely by
quality) of man-hours invested into thinking and discussion of
syntactic features. Anyway I value appeal to success more than
appeal to authority so by my own standards the argument above is
weak.
I was around when Ada was being developed and refined, a process that
took years.
By contrast, C looks like it was just thrown together with little
thought, and probably that is exactly what happened.
In the end, Ada was a language that you could admire, but you'd
rather other people used. It's a solid language but I found it too
formal and rather dull (not that it was available for me to use).
Still, I borrowed some syntactic features from it.
One interesting fact that people might forget is that it was case-insensitive, a welcome difference IMV.
In article <11avmfb$55rt$[email protected]>, bart <[email protected]> wrote:
On 17/10/2026 04:19, Dan Cross wrote:
In article <11auad0$3no1k$[email protected]>, bart <[email protected]> wrote: >>>> Those are considered more productive.
...and you think that's because of the syntax, and not the high
level nature of those languages?
It's a combination.
Riiiight.
Yes. C's declaration syntax is famously abstruse; film at 11.
If C had used LTR type syntax and somebody
proposed using inside-out back-and-forth syntax like 'void(*)(void)',
they'd think they were having a laugh, as it would be ridiculous.
Unknowable.
Then your point is minor at best. Here's a thought experiment:
suppose I suddenly came to my senses and agreed with everything
you say: I'm willing to totally toss out C and adopt Bart's
language yesterday.
Where do I get a compiler? What learning
resources exist? Oh, and I need it to generate code for an
ARM Cortex-M0 part; does it do that? I also need RV64GC and
x86_64 and probably aarch64, too. Might want to throw in
Xtensa while we're at it: does your compiler do all of that?
What if I need a debugger? Oh, and I need to use crypto
libraries that are supplied from a vendor; they use the C ABI.
What's the inter-op story like?
Good for you. Totally irrelevant to the history of C.
Lawrence D?Oliveiro <[email protected]d> wrote:
On Tue, 13 Oct 2026 07:23:40 -0000 (UTC), Waldek Hebisch wrote:
So what those counts indicate: majority of loops is simple, that is
have no early exit. Vast majority of early exits is done via
'return'.
My experience in my own C code is quite the opposite. Lots of loops
have exits in the middle, leading me to use forms like ?for (;;)?. I
also try to avoid putting ?return? anywhere other than the end of a
function, to make it easier to see the flow of control.
Well, usually there is a lot of loops. Those with exit in the
middle are still significant.
Concernig 'return', having it in place where all work inside function
is done help me to see flow control and avoids complications. In
case of search functions it means return from the middle of the loop.
IMO possible alternatives like flag variables or break and retrun
after loop are worse.
Lawrence =?iso-8859-13?q?D=FFOliveiro?= <[email protected]d> writes:
On Fri, 16 Oct 2026 15:24:01 -0000 (UTC), Waldek Hebisch wrote:
Concernig 'return', having it in place where all work inside
function is done help me to see flow control and avoids
complications. In case of search functions it means return from the
middle of the loop. IMO possible alternatives like flag variables or
break and retrun after loop are worse.
Code tends to do a lot of dynamic resource allocation these days, and
that requires cleanup. Doing a direct “return” from the middle of a
function body doesn’t allow for that.
Unless you use a GCC extension like “defer”, I suppose.
Better to use the cleanup attribute (or RAII in C++).
#define RAII_CHM __attribute__((cleanup(auto_free_ptr)))
#define RAII_FILE __attribute__((cleanup(auto_close_file)))
int main(void) {
// Memory and file handles are bound to this block scope
RAII_CHM char *buffer = malloc(100);
RAII_FILE FILE *fp = fopen("example.txt", "w");
if (!buffer || !fp) {
return -1; // Even on early exit, validly opened resources are cleaned up!
}
fprintf(fp, "Hello, RAII in C!");
return 0; // Both buffer and fp are automatically freed/closed here
}
On 2026-10-17 00:00, Keith Thompson wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
[...]
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
[...]
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
Why would one question an opinion? ;-)
I do like the fact that it doesn't conflate goto labels with loop
names, but I still prefer the "NAME: for (;;)" form, partly because
it's consistent with several other languages.
I've no strong opinion on that, but I find the "for NAME (;;)" to
clearer express the _local scope_ of embedded breaks or continues.
(Just a matter of taste, and my appreciation for locality.)
As far as I recall, in "C", the name of the function was often put
separately (first in the line) to have an easy method to find its
declaration by simple "grep ^fname". (With any sophisticated editor
this might be a weak argument, though.)
On 17/10/2026 01:29, Janis Papanagnou wrote:
I've no strong opinion on that, but I find the "for NAME (;;)" to
clearer express the _local scope_ of embedded breaks or continues.
(Just a matter of taste, and my appreciation for locality.)
A main objection to "name: for ..." is that with function-scope labels,
you need a new name for every labelled loop or switch. That may be an inconvenience, especially for macro with labelled loops, or for copy- and-paste code. There is a proposal to deal with that which basically
says :
1. Any "break label;" or "continue label;" refers to the innermost containing loop or switch with that label.
2. Any "label" used in "goto label;" must be unique in the function.
Those rules give a simple and intuitive fix without affecting existing
code.
Beyond that, "name: for ..." or "for name ..." is, as you say, mostly a matter of taste. (There are proposals for both versions, and you can
look them up to see the arguments.)
On 17/10/2026 04:19, Dan Cross wrote:
In article <11auad0$3no1k$[email protected]>, bart <[email protected]> wrote:
Those are considered more productive.
...and you think that's because of the syntax, and not the high
level nature of those languages?
It's a combination.
Yes, the syntax is pretty gnarly; Dennis Ritchie even said as
much. Fixed in Go and Rust, but also, I doubt you've ever in
your life had a variable of type array of array of length 8 of
a pointer to a pointer to a function returning an array of
pointers to char. Finding the most ridiculous example you can
is not really evidence of anything besides your weird obsession
That was the first one I saw online next to a quote from K&R and I
assumed it was from the book. In fact the example from the book is this:
char (*(*x())[])()
I've no idea what the means either. The point is not that the examples
are ridiculous, but that they are hard to convert to and from LTR form
which is how we think. With LTR syntax it becomes utterly trivial to
read or write them, no matter how complex.
(There's a tool called CDECL that translates types from C syntax to LTR English or vice versa. It calls the C versions 'gibberish'. This is a
real thing!)
with finding abstruse corner cases and holding them up as
reasons to dislike C.
The first example I gave was the simplest form of function pointer,
where the syntax is 'void(*)(void)'. Hardly a corner case, and it
rapidly goes downhill.
If meeting C for the first time, that does not bode well. If the
designers did not care about this, that does not inspire confidence in
the rest of the language.
On 17/10/2026 01:29, Janis Papanagnou wrote:
On 2026-10-17 00:00, Keith Thompson wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
[...]
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
[...]
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
Why would one question an opinion? ;-)
Time didn't word it as a personal opinion - he made it clear that he
doesn't think anyone else could have a different opinion.
The C standards committee collectively reached an agreement counter to
Tim's thoughts, so clearly his preferred variant is /not/ unquestionably better.
I do like the fact that it doesn't conflate goto labels with loop
names, but I still prefer the "NAME: for (;;)" form, partly because
it's consistent with several other languages.
I've no strong opinion on that, but I find the "for NAME (;;)" to
clearer express the _local scope_ of embedded breaks or continues.
(Just a matter of taste, and my appreciation for locality.)
A main objection to "name: for ..." is that with function-scope labels,
you need a new name for every labelled loop or switch. That may be an inconvenience, especially for macro with labelled loops, or for copy- and-paste code. There is a proposal to deal with that which basically
says :
1. Any "break label;" or "continue label;" refers to the innermost containing loop or switch with that label.
2. Any "label" used in "goto label;" must be unique in the function.
Those rules give a simple and intuitive fix without affecting existing
code.
Beyond that, "name: for ..." or "for name ..." is, as you say, mostly a matter of taste. (There are proposals for both versions, and you can
look them up to see the arguments.)
As far as I recall, in "C", the name of the function was often put
separately (first in the line) to have an easy method to find its
declaration by simple "grep ^fname". (With any sophisticated editor
this might be a weak argument, though.)
I think it was popularised with a shortcut in emacs.
On 18/10/2026 11:48, David Brown wrote:
On 17/10/2026 01:29, Janis Papanagnou wrote:
I've no strong opinion on that, but I find the "for NAME (;;)" to
clearer express the _local scope_ of embedded breaks or continues.
(Just a matter of taste, and my appreciation for locality.)
A main objection to "name: for ..." is that with function-scope
labels, you need a new name for every labelled loop or switch. That
may be an inconvenience, especially for macro with labelled loops, or
for copy- and-paste code. There is a proposal to deal with that which
basically says :
1. Any "break label;" or "continue label;" refers to the innermost
containing loop or switch with that label.
2. Any "label" used in "goto label;" must be unique in the function.
Those rules give a simple and intuitive fix without affecting existing
code.
There's something missing. Labels usually live in their own, function-
wide name space.
But if you have two loops like this:
L1: while () {} L2:
L1: while () {} L2:
Then even if no gotos exist to L1, is that rule somehow relaxed for
those L1s to allow them to co-exist? (While still applying to non-loop labels L2, which would clash.)
Will the L1s still live within the regular name space? (Presumably each
will now be tagged with its associated loop.)
Beyond that, "name: for ..." or "for name ..." is, as you say, mostly
a matter of taste. (There are proposals for both versions, and you
can look them up to see the arguments.)
The second form allows for those label names to be special, for example
by belonging in the same name space as regular identifiers and thus
subject to block scope rules. This is a tidier solution to the above.
On 17/10/2026 13:34, bart wrote:
[...]
char (*(*x())[])()
[...]
Putting that example in cdecl gives :
"declare x as function returning pointer to array of pointer to function returning char"
To me, that is just as much gibberish as the original C. No syntax is going to make sense of it - no amount of "ref" or "func" or pre-fix
array notation will help.
If you want complex types in a programming language, make them out of simpler, named types that express what you are trying to achieve. I
think any decent typed programming language will have a way to do this -
for C, "typedef" is your friend here.
[snip]
Keith Thompson <[email protected]> writes:
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
Definitely.
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is unquestionably better.
On 17/10/2026 18:58, Dan Cross wrote:
In article <11avmfb$55rt$[email protected]>, bart <[email protected]> wrote:
On 17/10/2026 04:19, Dan Cross wrote:
In article <11auad0$3no1k$[email protected]>, bart <[email protected]>
wrote:
Yes. C's declaration syntax is famously abstruse; film at 11.
And ... that's it? Just accept it? How about doing something about it!
[...] (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
[...]
On 17/10/2026 13:34, bart wrote:
On 17/10/2026 04:19, Dan Cross wrote:
In article <11auad0$3no1k$[email protected]>, bart <[email protected]> wrote: >>
Those are considered more productive.
...and you think that's because of the syntax, and not the high
level nature of those languages?
It's a combination.
Yes, the syntax is pretty gnarly; Dennis Ritchie even said as
much. Fixed in Go and Rust, but also, I doubt you've ever in
your life had a variable of type array of array of length 8 of
a pointer to a pointer to a function returning an array of
pointers to char. Finding the most ridiculous example you can
is not really evidence of anything besides your weird obsession
That was the first one I saw online next to a quote from K&R and I
assumed it was from the book. In fact the example from the book is this:
char (*(*x())[])()
I've no idea what the means either. The point is not that the examples
are ridiculous, but that they are hard to convert to and from LTR form
which is how we think. With LTR syntax it becomes utterly trivial to
read or write them, no matter how complex.
(There's a tool called CDECL that translates types from C syntax to
LTR English or vice versa. It calls the C versions 'gibberish'. This
is a real thing!)
Putting that example in cdecl gives :
"declare x as function returning pointer to array of pointer to function returning char"
To me, that is just as much gibberish as the original C.
No syntax is
going to make sense of it - no amount of "ref" or "func" or pre-fix
array notation will help.
If you want complex types in a programming language, make them out of simpler, named types that express what you are trying to achieve. I
think any decent typed programming language will have a way to do this -
for C, "typedef" is your friend here.
(And do /not/ reply by bringing up examples you have cherry-picked from
code you have found, as though it was my fault they wrote
incomprehensible code.)
C is not, and has never claimed to be, a beginner-friendly language.
It
is designed to be efficient while remaining quite a small language,
On 2026-10-18 14:09, David Brown wrote:I'd prefer label consistently attached to the loop-exit keyword.
[...]� (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
We'll see what they finally decide (unless it's already clear; I'm
not sure about the factual weight of the "proposal")...
Janis
[...]
To me, that is just as much gibberish as the original C. No syntax
is going to make sense of it - no amount of "ref" or "func" or
pre-fix array notation will help.
On 18/10/2026 12:22, David Brown wrote:
On 17/10/2026 13:34, bart wrote:
On 17/10/2026 04:19, Dan Cross wrote:
In article <11auad0$3no1k$[email protected]>, bart <[email protected]>
wrote:
Those are considered more productive.
...and you think that's because of the syntax, and not the high
level nature of those languages?
It's a combination.
Yes, the syntax is pretty gnarly; Dennis Ritchie even said as
much. Fixed in Go and Rust, but also, I doubt you've ever in
your life had a variable of type array of array of length 8 of
a pointer to a pointer to a function returning an array of
pointers to char. Finding the most ridiculous example you can
is not really evidence of anything besides your weird obsession
That was the first one I saw online next to a quote from K&R and I
assumed it was from the book. In fact the example from the book is this: >>>
char (*(*x())[])()
I've no idea what the means either. The point is not that the
examples are ridiculous, but that they are hard to convert to and
from LTR form which is how we think. With LTR syntax it becomes
utterly trivial to read or write them, no matter how complex.
(There's a tool called CDECL that translates types from C syntax to
LTR English or vice versa. It calls the C versions 'gibberish'. This
is a real thing!)
Putting that example in cdecl gives :
"declare x as function returning pointer to array of pointer to
function returning char"
To me, that is just as much gibberish as the original C.
That doesn't matter - the problem is not even knowing what it
represents.
(That it is an actual function is a surprise. That you can't
easily tell is crazy.)
In practice there will be actual types that start to look like
gibberish, full of *, () and [] that must be in exactly the right place.
Then maybe you want to construct a pointer to such a type or an array of
it - where will be the new * or [] go? Where will the variable name go
for that matter?
This should be simple enough to do in a language without needing to
follow some back-and-forth algorithm, or use an external tool, or need
to decompose them into multiple levels using 'typedef', or need to disambiguate with parentheses.
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...] (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword. Unfortunately, for() and while() loops have no such keyword.
We'll see what they finally decide (unless it's already clear; I'm
not sure about the factual weight of the "proposal")...
I tend to agree with Tim (if I correctly understood him): a.t.m. the
best outcome would be proposal scrapped completely.
On Sun, 18 Oct 2026 13:22:52 +0200
David Brown <[email protected]> wrote:
To me, that is just as much gibberish as the original C. No syntax
is going to make sense of it - no amount of "ref" or "func" or
pre-fix array notation will help.
[O.T.]
Prefix array notation would not. But postfix * notation would, somewhat.
It would be interesting to find out why designers of C, or of one of its ancestors decided that * as prefix is preferable to * as postfix.
Were they afraid of confusion with usage of * as multiplication?
Probably not, because confusion can arise about equally both for prefix
and for postfix.
On 18/10/2026 16:13, Michael S wrote:Pay attention that 4 patterns are not equal. The second case
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...]� (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword. Unfortunately, for() and while() loops have no such keyword.
That would help for switch inside a loop, or loop inside a switch,
but do nothing for loop inside a loop or switch inside a switch. I
don't think anyone involved in the development of the language has
seriously considered making a solution that only handles the first
two cases, and not the second two
(to say nothing of three or more
nesting layers). "break_switch" and "break_loop" style solutions have
been mentioned and quickly dismissed, along with the "break <depth>"
options.
Nothing is set in stone until the standard released. But you are veryWe'll see what they finally decide (unless it's already clear; I'm
not sure about the factual weight of the "proposal")...
I tend to agree with Tim (if I correctly understood him): a.t.m. the
best outcome would be proposal scrapped completely.
The proposal has been accepted - it is coming to C and C++, whatever
you or Tim may think.
But of course there is no requirement to /use/But others will use it and I'd have to read and understand their code.
the new feature if you don't like it.
(I don't expect to use it
significantly myself - I just don't seem to write code in a way that
could take advantage of it.)
On 18/10/2026 16:24, Michael S wrote:
On Sun, 18 Oct 2026 13:22:52 +0200
David Brown <[email protected]> wrote:
To me, that is just as much gibberish as the original C. No syntax
is going to make sense of it - no amount of "ref" or "func" or
pre-fix array notation will help.
[O.T.]
Prefix array notation would not. But postfix * notation would,
somewhat.
I can agree that notational changes might make it marginally easier
to understand complex declarations - or mean that declarations could
be marginally more complex while still being easily understood. But
nothing can make Bart's exaggerated examples meaningful.
It would be interesting to find out why designers of C, or of one
of its ancestors decided that * as prefix is preferable to * as
postfix. Were they afraid of confusion with usage of * as
multiplication? Probably not, because confusion can arise about
equally both for prefix and for postfix.
I don't know why it is prefix. Maybe they were keen on "*p++ = *q++"
and similar expressions, felt "(p++)* = (q++)*" was unclear?
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...] (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword.
Unfortunately, for() and while() loops have no such keyword.
[...]
On 18/10/2026 15:33, bart wrote:
On 18/10/2026 12:22, David Brown wrote:
To me, that is just as much gibberish as the original C.
That doesn't matter - the problem is not even knowing what it represents.
That is, shall we say, a strange attitude. Gibberish (since that seems
to be the preferred term here) is gibberish, no matter the language or representation, and is equally meaningless and useless.
(That it is an actual function is a surprise. That you can't easily
tell is crazy.)
You can tell it very easy from the C - the final bit is parentheses.
In practice there will be actual types that start to look like
gibberish, full of *, () and [] that must be in exactly the right place.
Not in my code, or the code I work with - types are clear to me. Again, experiences can vary.
(Of course the syntactical elements must be in
the right place!)
Use a typedef. Or since C23, use type inference - that can save naming
and identifying types when things get complex,
This should be simple enough to do in a language without needing to
follow some back-and-forth algorithm, or use an external tool, or need
to decompose them into multiple levels using 'typedef', or need to
disambiguate with parentheses.
You just /have/ to whine, don't you? Whenever you complain - usually
complicated in C, and someone tells you how it can be handled simply and clearly,
unable to simply say "Okay, thanks - that's good to > know" or "Sorry,I was wrong, I thought it was hard". You can't help
but call things workarounds, or complicated, or get your knickers in aThis one is universally disliked and even the language creators said it
twist about having to use a language feature that for some reason you hate.
On Sun, 18 Oct 2026 16:58:38 +0200[...]
David Brown <[email protected]> wrote:
On 18/10/2026 16:24, Michael S wrote:
It would be interesting to find out why designers of C, or of one
of its ancestors decided that * as prefix is preferable to * as
postfix.
Were they afraid of confusion with usage of * as
multiplication? Probably not, because confusion can arise about
equally both for prefix and for postfix.
I don't know why it is prefix. Maybe they were keen on "*p++ = *q++"
and similar expressions, felt "(p++)* = (q++)*" was unclear?
Why would it require parentheses?
On 2026-10-18 17:26, Michael S wrote:
On Sun, 18 Oct 2026 16:58:38 +0200[...]
David Brown <[email protected]> wrote:
On 18/10/2026 16:24, Michael S wrote:
It would be interesting to find out why designers of C, or of one
of its ancestors decided that * as prefix is preferable to * as
postfix.
Because it is more "natural" when read, easier to grasp?
Simpler for compilers?
More consistent if all other, especially standard
operators known from daily use are used in prefix-form (-5, +42,
!false, ~bitset) in expressions?
I don't recall to have used any language with infix-expressions
that would have their monadic operators defined in postfix form.
The only exception was "C" (and C-oriented languages) with their
special case of post-increment/post-decrement operators. (Think
also about the quirk in C++ to define monadic postfix operators
that require a syntactic dummy type argument). (In low-level RPN
systems it may appear more "natural", but that just aside.)
Were they afraid of confusion with usage of * as
multiplication? Probably not, because confusion can arise about
equally both for prefix and for postfix.
I don't know why it is prefix. Maybe they were keen on "*p++ =
*q++" and similar expressions, felt "(p++)* = (q++)*" was unclear?
Why would it require parentheses?
Not necessarily (I think).
Janis
On Sun, 18 Oct 2026 13:22:52 +0200With all the other questionable choices, there probably wasn't much
David Brown <[email protected]> wrote:
To me, that is just as much gibberish as the original C. No syntax
is going to make sense of it - no amount of "ref" or "func" or
pre-fix array notation will help.
[O.T.]
Prefix array notation would not. But postfix * notation would, somewhat.
It would be interesting to find out why designers of C, or of one of its ancestors decided that * as prefix is preferable to * as postfix.
Were they afraid of confusion with usage of * as multiplication?
Probably not, because confusion can arise about equally both for prefix
and for postfix.
On Sun, 18 Oct 2026 16:52:17 +0200
David Brown <[email protected]> wrote:
On 18/10/2026 16:13, Michael S wrote:
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...] (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword.
Unfortunately, for() and while() loops have no such keyword.
That would help for switch inside a loop, or loop inside a switch,
but do nothing for loop inside a loop or switch inside a switch. I
don't think anyone involved in the development of the language has
seriously considered making a solution that only handles the first
two cases, and not the second two
Pay attention that 4 patterns are not equal. The second case
(breaking from loop to outside of containing switch) hardly happens.
(to say nothing of three or more
nesting layers). "break_switch" and "break_loop" style solutions have
been mentioned and quickly dismissed, along with the "break <depth>"
options.
It does not look like you understood what I wrote.
All I wanted to say is that I prefer label to be located at where the
break goes.
Or near this point. Within frame of current C syntax, I
don't see how to achieve it, except for do-while. But it does not
change the fact that I find it desirable.
We'll see what they finally decide (unless it's already clear; I'm
not sure about the factual weight of the "proposal")...
I tend to agree with Tim (if I correctly understood him): a.t.m. the
best outcome would be proposal scrapped completely.
The proposal has been accepted - it is coming to C and C++, whatever
you or Tim may think.
Nothing is set in stone until the standard released. But you are very
likely right. Which does not make me happier.
But of course there is no requirement to /use/
the new feature if you don't like it.
But others will use it and I'd have to read and understand their code.
(I don't expect to use it
significantly myself - I just don't seem to write code in a way that
could take advantage of it.)
On 18/10/2026 15:27, David Brown wrote:
On 18/10/2026 15:33, bart wrote:
On 18/10/2026 12:22, David Brown wrote:
To me, that is just as much gibberish as the original C.
That doesn't matter - the problem is not even knowing what it
represents.
That is, shall we say, a strange attitude. Gibberish (since that
seems to be the preferred term here) is gibberish, no matter the
language or representation, and is equally meaningless and useless.
'Gibberish' here refers to the representation, whether the type being described is made-up nonsense or real.
You may want to know what some complex type is for many reasons, you
don't necessarily need to understand what it means or why it was used.
(For example I might come across a type in a C API that I want to
convert to another language.)
In practice there will be actual types that start to look like
gibberish, full of *, () and [] that must be in exactly the right place.
Not in my code, or the code I work with - types are clear to me.
Again, experiences can vary.
What are you saying here, that your types never involve * () or []? That
is hard to believe.
(Of course the syntactical elements must be in the right place!)
Isn't that the problem? C makes it tricky. Here are two very
straightforward declarations from my projects:
ref []ichar stringtable # ichar is ref char
[N]ref proc(T) handlertable
These are the C versions:
char *(*stringtable)[];
void (*handlertable[N)(T);
They involve * () and [] that must all be in the right place, in the
right nesting order. In C, parentheses are used to alter precedences as
well as for parameter lists. This not a thing in LTR forms.
Additionally, in C, you can sometimes mix up the order of * and [], but since a T* value can be indexed, and a T[] value can be dereferenced,
those errors might still compile.
So it's a problem. You're saying it isn't one if you do X, Y and Z. I'm
that you shouldn't need to do X, Y and Z; if you do then it's a
language problem.
Use a typedef. Or since C23, use type inference - that can save
naming and identifying types when things get complex,
OK, that's a fifth kind of workaround! Although it is more of an
unrelated feature.
This should be simple enough to do in a language without needing to
follow some back-and-forth algorithm, or use an external tool, or
need to decompose them into multiple levels using 'typedef', or need
to disambiguate with parentheses.
You just /have/ to whine, don't you? Whenever you complain - usually
I thought it was, for a change, a civil exchange up to now.
On Sun, 18 Oct 2026 16:58:38 +0200
David Brown <[email protected]> wrote:
On 18/10/2026 16:24, Michael S wrote:
On Sun, 18 Oct 2026 13:22:52 +0200
David Brown <[email protected]> wrote:
To me, that is just as much gibberish as the original C. No syntax
is going to make sense of it - no amount of "ref" or "func" or
pre-fix array notation will help.
[O.T.]
Prefix array notation would not. But postfix * notation would,
somewhat.
I can agree that notational changes might make it marginally easier
to understand complex declarations - or mean that declarations could
be marginally more complex while still being easily understood. But
nothing can make Bart's exaggerated examples meaningful.
It would be interesting to find out why designers of C, or of one
of its ancestors decided that * as prefix is preferable to * as
postfix. Were they afraid of confusion with usage of * as
multiplication? Probably not, because confusion can arise about
equally both for prefix and for postfix.
I don't know why it is prefix. Maybe they were keen on "*p++ = *q++"
and similar expressions, felt "(p++)* = (q++)*" was unclear?
Why would it require parentheses?
On 18/10/2026 17:16, Michael S wrote:
On Sun, 18 Oct 2026 16:52:17 +0200
David Brown <[email protected]> wrote:
On 18/10/2026 16:13, Michael S wrote:
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...]� (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of)
"consistent" with the place of the label attacked in a 'while'
loop; i.e. behind the 'while' keyword. - It's inconsistent in
another interpretation, though; and I'd certainly have favored
the latter form, to have the label consistently attached at the
loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword.
Unfortunately, for() and while() loops have no such keyword.
That would help for switch inside a loop, or loop inside a switch,
but do nothing for loop inside a loop or switch inside a switch. I
don't think anyone involved in the development of the language has
seriously considered making a solution that only handles the first
two cases, and not the second two
Pay attention that 4 patterns are not equal. The second case
(breaking from loop to outside of containing switch) hardly happens.
I know they are not equal - that's why I wrote all four combinations.
But I have no good statistics to determine which combinations might
be more common than others for wanting to break out of the outer
structure. I know /you/ said that /you/ regularly want to break out
of a switch that is inside a loop - fair enough. It is not something
that I have needed to do, or at least not often enough to bother
about it. Indeed, none of the cases are particularly common in my
code. I've no doubt come across some of them at times, and dealt
with them using extra bools or splitting up big functions into
smaller ones where "return" could do the job. Certainly I do not
ever remember wishing I had a "break_loop" statement, or a labelled
break.
But the C standards committee don't care about my code. They don't
care about your code either. They care about what they think makes a difference to large numbers of C programmers. I can't tell you if
they have access to good statistics, or are using the combined gut
feelings of the committee members. However, it would strike me as a
serious wasted opportunity if they made an addition to the language
that only handled the one pattern that you find most common in your
code, rather than also making it work for the other patterns.
(to say nothing of three or more
nesting layers). "break_switch" and "break_loop" style solutions
have been mentioned and quickly dismissed, along with the "break
<depth>" options.
It does not look like you understood what I wrote.
All I wanted to say is that I prefer label to be located at where
the break goes.
In C2y, you /do/ put the label along with the break - you write
"break outer;". But you also have to put the label "outer : " at the
start of the control structure.
If you want to have some kind of "break to outer structure" /without/
having a name or label on the structure, then you need some other way
to refer to it. I thought you had said before your preference was
for something like "break_switch" (ignoring any bike-shedding on the syntax), which would work in the particular case of a switch with
nested loop(s). And as I wrote, this was considered and dismissed.
(Equally, the other plausible syntax that does not require an
explicit label - "break <depth>", was considered and dismissed.)
Or near this point. Within frame of current C syntax, I
don't see how to achieve it, except for do-while. But it does not
change the fact that I find it desirable.
Am I right in thinking you would then have :
do {
switch (...) {
break outer;
while outer (...);
You are happy with labelling the loop or switch, but want the label
at the end, not the start?
Why not then just use "goto" and put a label at the end of the loop
or switch? (This is allowed in C23.)
We'll see what they finally decide (unless it's already clear;
I'm not sure about the factual weight of the "proposal")...
I tend to agree with Tim (if I correctly understood him): a.t.m.
the best outcome would be proposal scrapped completely.
The proposal has been accepted - it is coming to C and C++,
whatever you or Tim may think.
Nothing is set in stone until the standard released. But you are
very likely right. Which does not make me happier.
Okay. There are always changes that we like, changes we dislike, and
(often the majority) changes to which we are indifferent.
But of course there is no requirement to /use/
the new feature if you don't like it.
But others will use it and I'd have to read and understand their
code.
True - but do you /really/ think that is going to be a problem?
(I don't expect to use it
significantly myself - I just don't seem to write code in a way
that could take advantage of it.)
On 2026-10-18 16:13, Michael S wrote:
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...] (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword.
I can see that this might look appealing in case of 'break'. In
case of the same mechanism working also for 'continue' I'd then
think that it should generally better be an "attribute" of the
loop entry keyword, i.e. placed where loops start. (But that's
just my opinion.) Having it at a different place with a do-loop
I consider a really bad decision. It's advantageous to know the
direction in which to seek for the label if you inspect code. -
But okay, it's "C"; I won't heat up about some future C-release
that I'll never use (especially given that I'm not even be using
all of those more recent additions that are already available).
On 18/10/2026 18:09, bart wrote:
Isn't that the problem? C makes it tricky. Here are two very
straightforward declarations from my projects:
ref []ichar stringtable # ichar is ref char >> [N]ref proc(T) handlertable
Are you suggesting that in your language, "stringtable" could also be declared as :
ref ichar [stringtable]
or
][ stringtable ichar ref
?
I suspect that your language also requires the syntactical elements to
be in the right place.
I assume that :
[N] ref proc(T) handlertable
and
ref [N] proc(T) handlertable
are different?
You need to give things in the right order, or use parentheses, to get
the right "type expression" It's just like any other kind of expression.
The intention of the declaration syntax in C is that the declaration
order follows usage.
There's a lot of good things to say about
left-to-right ordering, since that is the order for reading (in English, anyway). But it also means the declaration order and usage order are different unless your array subscript, pointer dereference and call operators are also all left-to-right.
My point is not that C's syntax
is wonderful (I disagree with Kenny here),
but that it works fine in
practice,
you don't have to write incomprehensible declarations
On 17/10/2026 01:29, Janis Papanagnou wrote:
On 2026-10-17 00:00, Keith Thompson wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
[...]
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
[...]
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
Why would one question an opinion? ;-)
Time didn't word it as a personal opinion - he made it clear that he
doesn't think anyone else could have a different opinion.
As far as I recall, in "C", the name of the function was often put
separately (first in the line) to have an easy method to find its
declaration by simple "grep ^fname". (With any sophisticated editor
this might be a weak argument, though.)
I think it was popularised with a shortcut in emacs.
In article <11b2pq5$3pvda$[email protected]>,
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 16:13, Michael S wrote:
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...]Â (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword.
I can see that this might look appealing in case of 'break'. In
case of the same mechanism working also for 'continue' I'd then
think that it should generally better be an "attribute" of the
loop entry keyword, i.e. placed where loops start. (But that's
just my opinion.) Having it at a different place with a do-loop
I consider a really bad decision. It's advantageous to know the
direction in which to seek for the label if you inspect code. -
But okay, it's "C"; I won't heat up about some future C-release
that I'll never use (especially given that I'm not even be using
all of those more recent additions that are already available).
I think colocating it with `do` might create a syntactic
ambiguity. In the case of `for`, `while`, and `select`, there
is a required token following the keyword (the `(`). However,
for a `do`/`while` loop, `do` is followed immediately by a,
`secondary-block` production. In particular, you do not _need_
braces to denote a compound statement after `do`; something like
`do i++; while (i < j);` is perfectly legal in C.
In the N3377 proposal, the new `block-name` is just an
identifier. If it were allowed immediately after the `do`, then
given, `do NAME statement; while(condition);` you can't tell
`NAME` from the name of the loop and a random identifier before
a statement; something like `do LOOP i++; while (i < j);`
appears as though it _would_ be be syntactically valid by N3377
as presently worked, but is the programmer's intent to create a
loop name, or should this just be a syntax error?
By requiring the block-name between a keyword and a
syntactically required `(`, you remove that ambiguity: if there
is an identifier there, then it is a `block-name`; if not, then
the block has no name.
In article <11b2pq5$3pvda$[email protected]>,
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 16:13, Michael S wrote:
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...] (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword.
I can see that this might look appealing in case of 'break'. In
case of the same mechanism working also for 'continue' I'd then
think that it should generally better be an "attribute" of the
loop entry keyword, i.e. placed where loops start. (But that's
just my opinion.) Having it at a different place with a do-loop
I consider a really bad decision. It's advantageous to know the
direction in which to seek for the label if you inspect code. -
But okay, it's "C"; I won't heat up about some future C-release
that I'll never use (especially given that I'm not even be using
all of those more recent additions that are already available).
I think colocating it with `do` might create a syntactic
ambiguity. In the case of `for`, `while`, and `select`, there
is a required token following the keyword (the `(`). However,
for a `do`/`while` loop, `do` is followed immediately by a,
`secondary-block` production. In particular, you do not _need_
braces to denote a compound statement after `do`; something like
`do i++; while (i < j);` is perfectly legal in C.
In the N3377 proposal, the new `block-name` is just an
identifier. If it were allowed immediately after the `do`, then
given, `do NAME statement; while(condition);` you can't tell
`NAME` from the name of the loop and a random identifier before
a statement; something like `do LOOP i++; while (i < j);`
appears as though it _would_ be be syntactically valid by N3377
as presently worked, but is the programmer's intent to create a
loop name, or should this just be a syntax error?
By requiring the block-name between a keyword and a
syntactically required `(`, you remove that ambiguity: if there
is an identifier there, then it is a `block-name`; if not, then
the block has no name.
On 17/10/2026 18:58, Dan Cross wrote:
In article <11avmfb$55rt$[email protected]>, bart <[email protected]> wrote:
On 17/10/2026 04:19, Dan Cross wrote:
In article <11auad0$3no1k$[email protected]>, bart <[email protected]> wrote: >>>>> Those are considered more productive.
...and you think that's because of the syntax, and not the high
level nature of those languages?
It's a combination.
Riiiight.
So greatly simplifying syntax, all other things being equal, does not >increase productivity at all? Gotcha.
Yes. C's declaration syntax is famously abstruse; film at 11.
And ... that's it? Just accept it? How about doing something about it!
I'm angry because to me C was so unusable that I had to create and
maintain my own products over decades.
Then I later found that C had insinuated itself into every API and every >open source product I wanted to use. Even ABIs, supposedly
language-neutral, pay deference to it. Even as a compiler target, there
was no other choice.
So I ended having to deal with it anyway, but thankfully avoided have to >write it.
If C had used LTR type syntax and somebody
proposed using inside-out back-and-forth syntax like 'void(*)(void)',
they'd think they were having a laugh, as it would be ridiculous.
Unknowable.
You do know; you just don't want to admit it. (Imagine introducing C >declarations into a current language.)
Then your point is minor at best. Here's a thought experiment:
suppose I suddenly came to my senses and agreed with everything
you say: I'm willing to totally toss out C and adopt Bart's
language yesterday.
THIS IS NOT ABOUT MY LANGUAGE!
Why hasn't there long been an alternative systems language that didn't
have C's crazy syntax and stupid quirks? I mean like 30-50 years ago.
Yes, mine has lots of examples of how some alternative features could
work; so what? I am not selling my language.
Where do I get a compiler? What learning
resources exist? Oh, and I need it to generate code for an
ARM Cortex-M0 part; does it do that? I also need RV64GC and
x86_64 and probably aarch64, too. Might want to throw in
Xtensa while we're at it: does your compiler do all of that?
What if I need a debugger? Oh, and I need to use crypto
libraries that are supplied from a vendor; they use the C ABI.
What's the inter-op story like?
My language was for in-house use; it was never intended as a product.
(If you really want to try it, I can supply an ASM file for you to
build, but it works on Windows. I can no longer supply a transpiled C >version that part work on Linux;
I have destroyed my C-related projects.)
The C API (not ABI) point is valid, and another bugbear. Why can't APIs
be expressed in a language-agnostic manner? This would help other
languages that also need to solve the problem of creating bindings to >libraries that primarily use a C API.
C is a terrible choice for a cross-language API, as too many C-isms
creep in (like C macros, or vaguely defined types, including the famous >'plain char' that exists in no other language, which is neither signed
nor unsigned, and above all C preprocessor features).
Good for you. Totally irrelevant to the history of C.
It means that meagre hardware resources don't have to compromise the
design of a language, especially when it comes to syntax.
So you can't use limited resources as an excuse for its questionable >choices. Actually some choices actually made it harder to parse.
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...] (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword. Unfortunately, for() and while() loops have no such keyword.
All I wanted to say is that I prefer label to be located at where the
break goes. Or near this point. Within frame of current C syntax, I
don't see how to achieve it, except for do-while. But it does not
change the fact that I find it desirable.
Writing statement with parentheses may look silly, but such code may
be easily produced due to use of macros.
On Sun, 18 Oct 2026 23:51:25 -0000 (UTC), Waldek Hebisch wrote:
Writing statement with parentheses may look silly, but such code may
be easily produced due to use of macros.
Why do you need to distinguish between “statements” and “expressions”,
anyway?
By the way, the precursor of C, BCPL, allowed statement sequences
inside expressions. For some reason this got dropped from C.
On 18/10/2026 15:27, David Brown wrote:
On 18/10/2026 15:33, bart wrote:
On 18/10/2026 12:22, David Brown wrote:
That is, shall we say, a strange attitude. Gibberish (since that seemsTo me, that is just as much gibberish as the original C.
That doesn't matter - the problem is not even knowing what it represents. >>
to be the preferred term here) is gibberish, no matter the language or
representation, and is equally meaningless and useless.
'Gibberish' here refers to the representation, whether the type being described is made-up nonsense or real.
You may want to know what some complex type is for many reasons, you
don't necessarily need to understand what it means or why it was used.
(For example I might come across a type in a C API that I want to
convert to another language.)
On Sun, 18 Oct 2026 20:47:13 +0200
David Brown <[email protected]> wrote:
On 18/10/2026 17:16, Michael S wrote:
All I wanted to say is that I prefer label to be located at where
the break goes.
In C2y, you /do/ put the label along with the break - you write
"break outer;". But you also have to put the label "outer : " at the
start of the control structure.
If you want to have some kind of "break to outer structure" /without/
having a name or label on the structure, then you need some other way
to refer to it. I thought you had said before your preference was
for something like "break_switch" (ignoring any bike-shedding on the
syntax), which would work in the particular case of a switch with
nested loop(s). And as I wrote, this was considered and dismissed.
(Equally, the other plausible syntax that does not require an
explicit label - "break <depth>", was considered and dismissed.)
Or near this point. Within frame of current C syntax, I
don't see how to achieve it, except for do-while. But it does not
change the fact that I find it desirable.
Am I right in thinking you would then have :
do {
switch (...) {
break outer;
while outer (...);
You are happy with labelling the loop or switch, but want the label
at the end, not the start?
Almost. I want it at the end and I want it with syntax that can't be
confused with regular goto targets.
Why not then just use "goto" and put a label at the end of the loop
or switch? (This is allowed in C23.)
Like just about everybody else, I prefer weaker control transfers. They
are not easier to write, but easier to follow by reader.
goto is too powerful - can go everywhere within function. That part is improved by C2y proposal.
But the labels that goto targets are also too powerful - they can be
reached from everywhere in the function. That part is not just not
improved by proposal, but made worse, because now we not just have a
too powerful label (that we have to name, which is problem by itself,
but lesser evil than break N alternative), but this label creates
another, completely unnecessary, target for goto, that the reader of
code should have in mind.
In article <11b0mfv$j5ll$[email protected]>, bart <[email protected]> wrote:
C is a terrible choice for a cross-language API, as too many C-isms
creep in (like C macros, or vaguely defined types, including the famous >>'plain char' that exists in no other language, which is neither signed
nor unsigned, and above all C preprocessor features).
That's why ABIs matter.
Look at the Vax-11 Procedure Calling and Condition Handling
Standard from VMS 2.0; they simply wrote down what this stuff
meant, and you could call between essentially any language on
that system, whether it was C, Fortran, Bliss, COBOL, or
whatever.
On 18/10/2026 20:09, David Brown wrote:
On 18/10/2026 18:09, bart wrote:
Isn't that the problem? C makes it tricky. Here are two very
straightforward declarations from my projects:
ref []ichar stringtable # ichar is ref char
[N]ref proc(T) handlertable
Are you suggesting that in your language, "stringtable" could also be
declared as :
ref ichar [stringtable]
or
][ stringtable ichar ref
?
(Warning: longer post than I'd intended.)
I think you're clutching at straws.
So, what do you think the purpose of CDECL is? Since to you, NOTHING
about C type syntax ever appears to be a problem.
Just admit that the whole concept was a failure. The creators have
already done so.
I can appreciate wanting a syntax that is distinct from regular labels
for "goto".
David Brown <[email protected]> writes:
[...]
I can appreciate wanting a syntax that is distinct from regular labels
for "goto".
So can I. The first language I used that had this kind of thing
was Ada. In the language's initial design, it was decided that
though goto statements were needed, the labels should stand out:
<<LABEL>>
-- ...
goto LABEL;
Names used for loops have a lighter-weight syntax:
LOOP_NAME:
while condition loop
-- ...
end loop;
I can't think of a better syntax for loop names than "NAME:" (used
by several other languages), but in C that syntax is already
taken for goto labels. The possibility of any ambiguity between
"goto NAME;" and "break NAME;" doesn't bother me enough to want
to invent something new. And I consider the fact that other
languages use the "NAME:" syntax for loop names to be another
point in its favor.
The odd scoping rules for labels don't bother me either. They mean
you can't have two loops or switch statements with the same name in
the same function. I can barely imagine that being inconvenient.
And it's already specified in the latest C2y draft, and implemented in
gcc and clang, which means there's already some inertia against any
major changes. Anything could happen between now and the publication
of the next C standard, but I don't see any need to make significant
changes in this area.
I use Perl's equivalent of named break quite a lot. I found
31 occurrences of "exit NAME" in a collection of Perl scripts
I've written. I'm a little surprised to find that none of these
break out of nested loops; I just like to name loops for clarity.
I even find that having to choose a name for something forces
me to think more clearly about it.
The C2y proposed syntax and semantics for named loops and switch
statements is of course imperfect, but it's reasonably clean
and useful. I see no need to make any significant changes in
this area.
In article <11b0mfv$j5ll$[email protected]>, bart <[email protected]> wrote:
I see that you convenient snipped out my comment about C++,
which is the direct counter example.
"Had" is a strong word; dare I say it...a subjective word.
In fact, there have been all kinds of alternatives for years.
In the earlish 1980s, there was Modula-2, PL/M, Forth, Ada, CLU,
BLISS, and so on. You yourself admit you started from Algol68.
By the late 1980s you had Oberon, decent versions of ML, C++
and Objective-C, etc; by the 1990s, there were more than you
could shake a stick at. Now? Take your pick.
You never "had" to use your own language.
You do know; you just don't want to admit it. (Imagine introducing C
declarations into a current language.)
No, really; C's declaration syntax was inspired by FORTRAN, and
generations of scientists and engineers have managed that
language just fine.
Generations of programmers have handled C's
all right as well.
Then why do you keep bringing your language up, showing snippets
of its syntax, and so on?
Why hasn't there long been an alternative systems language that didn't
have C's crazy syntax and stupid quirks? I mean like 30-50 years ago.
There...have been? And still are?
Yes, mine has lots of examples of how some alternative features could
work; so what? I am not selling my language.
Oh good, so you'll stop bringing it up?
Not really, no. I don't do Windows,
But this sort of thing is exactly what I'm talking about: your
language is not useful beyond a userbase of one.
You solved a
set of "problems" that you defined for yourself, whether they
were real or not,
that as evidence about a general argument based on false
premises ("there was no alternative! I _had_ to do my own
thing!"
That's why ABIs matter.
So you can't use limited resources as an excuse for its questionable
choices. Actually some choices actually made it harder to parse.
The team that created C was familiar with, and rather liked,
Richard Martin's BCPL. B was created as sort of a chopped down
BCPL that could fit on the PDP-7, a machine with 4KW of 18-bit
core memory, at an access time of ~1.5ms, where most
instructions touch memory twice. Oh, and that machine was
running a multitasking, multiuser operating system and was
self-hosting. And you are seriously comparing your single-user
home PC with 64k of RAM to that environment? I'm not sure you
know what "hardware limitations" are.
As mentioned, C came from B, once they got a PDP-11; it was an
incremental evolution of a language they already had. The type
syntax you find so distasteful was inspired by FORTRAN.
It's so weird to me that you make such absolute pronouncements
about C and the choices that into its design, but are so
ajbectly ignorant of the actual history. Bluntly, you just are
not very well informed about it to make cogent comments.
Dan Cross <[email protected]> wrote:
In article <11b0mfv$j5ll$[email protected]>, bart <[email protected]> wrote:
C is a terrible choice for a cross-language API, as too many C-isms >>>creep in (like C macros, or vaguely defined types, including the famous >>>'plain char' that exists in no other language, which is neither signed >>>nor unsigned, and above all C preprocessor features).
That's why ABIs matter.
Look at the Vax-11 Procedure Calling and Condition Handling
Standard from VMS 2.0; they simply wrote down what this stuff
meant, and you could call between essentially any language on
that system, whether it was C, Fortran, Bliss, COBOL, or
whatever.
That is getting off-topic, but I looked at VMS documentation.
Simple cases are described with a lot of details. But I was
unable to find general case. Say, given array of structs
containing notrivial types like arrays inside. It seems that
for such types it is essentially "whatever language processor
decides to do" and the other end must know the convention.
Which seem to be exactly what happens on other platforms.
On 19/10/2026 02:19, Dan Cross wrote:
In article <11b0mfv$j5ll$[email protected]>, bart <[email protected]> wrote:
I see that you convenient snipped out my comment about C++,
which is the direct counter example.
I don't want to discuss C++. That language is abominable, other than as
the go-to example of language design going very wrong.
"Had" is a strong word; dare I say it...a subjective word.
In fact, there have been all kinds of alternatives for years.
In the earlish 1980s, there was Modula-2, PL/M, Forth, Ada, CLU,
BLISS, and so on. You yourself admit you started from Algol68.
By the late 1980s you had Oberon, decent versions of ML, C++
and Objective-C, etc; by the 1990s, there were more than you
could shake a stick at. Now? Take your pick.
You never "had" to use your own language.
OK. But they HAD to create C? There were quite a few languages in the
early 70s too: like Pascal, Fortran, PL/I, Coral-66, plus of course BCPL
and B. So why a new one?
Generations of programmers have handled C's
all right as well.
How many gave up because it was too much? How many still struggle with
it and have to employ those 4 or 5 workarounds which I mention
elsewhere? How much has it affected productivity?
On 18/10/2026 18:09, bart wrote:[ declaration syntax ]
[...]
You need to give things in the right order, or use parentheses, to get
the right "type expression". It's just like any other kind of expression.
The intention of the declaration syntax in C is that the declaration
order follows usage. [...]
On Sun, 18 Oct 2026 18:11:18 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 17:26, Michael S wrote:
On Sun, 18 Oct 2026 16:58:38 +0200[...]
David Brown <[email protected]> wrote:
On 18/10/2026 16:24, Michael S wrote:
It would be interesting to find out why designers of C, or of one
of its ancestors decided that * as prefix is preferable to * as
postfix.
Because it is more "natural" when read, easier to grasp?
IMHO, no.
Simpler for compilers?
100% no.
More consistent if all other, especially standard
operators known from daily use are used in prefix-form (-5, +42,
!false, ~bitset) in expressions?
Unary * is more similar in function to postfix operators like [] and ()
than to those you mentioned.
I don't recall to have used any language with infix-expressions
that would have their monadic operators defined in postfix form.
I am a Bear of Very Little Brain, and long words Bother Me.
By chance, did you never use Pascal?
On 2026-10-18 21:09, David Brown wrote:
On 18/10/2026 18:09, bart wrote:[ declaration syntax ]
[...]
(I just want to comment on a [not unimportant] detail...)
You need to give things in the right order, or use parentheses, to get
the right "type expression". It's just like any other kind of
expression.
The intention of the declaration syntax in C is that the declaration
order follows usage. [...]
I think the first part is downplaying that languages typically indeed
make a distinction between parenthesized expressions and declarations.
Quite some other languages [not from the C-heritage] that I used all
did not need to introduce "expression"-grouping for _declarations_ in
the first place given their more consistent ways to declare entities.
The second part is, as I had understood C's history, the idea behind
how it got defined; needless to say that I think that was a bad idea.
But that's what we've got! If they had dropped that requirement/idea
the declaration syntax could have become "better" (more consistent,
less cryptic, less convoluted, clearer). Now, after half a century,
we just have to live with that, and folks who have "problems" with it
should better not touch this language (or maybe not doing programming
at all). The somewhat tragic aspect is that the "declaration follows
use" idea was (IIRC) intended to _simplify_ the understanding of its
concepts and use of the language; the consequences were seemingly not
valued correctly.
bart <[email protected]> wrote:
On 18/10/2026 15:27, David Brown wrote:
On 18/10/2026 15:33, bart wrote:
On 18/10/2026 12:22, David Brown wrote:
That is, shall we say, a strange attitude. Gibberish (since that seems >>> to be the preferred term here) is gibberish, no matter the language orTo me, that is just as much gibberish as the original C.
That doesn't matter - the problem is not even knowing what it represents. >>>
representation, and is equally meaningless and useless.
'Gibberish' here refers to the representation, whether the type being
described is made-up nonsense or real.
You may want to know what some complex type is for many reasons, you
don't necessarily need to understand what it means or why it was used.
(For example I might come across a type in a C API that I want to
convert to another language.)
You say that you had commercial product, but you are apparently not
aware of basic marketing principles. You do not win in the market
by making easy switch from your product to competitor product. You
may want to make it easy to switch _to_ your product. But you want
to make switching to competing products as hard as possible. Of
course there are constraints on this, in the process you do not want
to deteriorate quality of your product too much and you have finite development resources.
Judging on this criteria you should admit that C is pretty good:
people wrote translators from various languages to C, but there
seem to be no success story going in opposite direction.
C++
managed to take over nontrivial part of market previously occupied
by C, but they did this by embedding largish subset of C and by
massvie pileup of extra features.
On 19/10/2026 15:16, Janis Papanagnou wrote:
[...]There are a number of things that I don't particularly like about C's declaration syntax, or where I think it would have been better if it
were different. But the "inside-to-outside" ordering is not one of
them. That is not because I think it is better or clearer than left-to- right ordering, but because when I compare to, say, Pascal, it's not a
big issue for me. Far bigger are :
1. People put too much into a single type declaration, rather than
building types out of logical parts with a purpose and a name.
They
don't do it as much as Bart likes to pretend, but some people do it too
much for my liking. The language doesn't force you to do that - it's programmer style. IMHO there is never a reason for a "pointer to an
array of function pointers taking int and returning void" - no matter
what syntax is used. Give a name to the function pointer type that reflects the usage (/not/ a name that reflects the definition), and
build up from there.
2. Being able to declare variables and functions with different types in
the same declaration. Very occasionally, I find it convenient to
declare more than one variable at once - "int a, b, c;". It is rare in
my code - generally it is one variable with an initialiser (and perhaps
a comment) at a time.
But it is - IMHO - a bad thing that you can write
"int a, xs[20], *p, (*f)(void);" in one declaration.
Both of these are overcome by simply not writing code that way.
Obviously that is easy to achieve in my own code, but other people may
use a different style.
In article <11b2pq5$3pvda$[email protected]>,
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 16:13, Michael S wrote:
On Sun, 18 Oct 2026 14:34:28 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 14:09, David Brown wrote:
[...] (I don't know why N3377 proposed "do { } while NAME ( )"
rather than "do NAME { } while ( )". )
Oh! - I can only think that it would then be (sort of) "consistent"
with the place of the label attacked in a 'while' loop; i.e. behind
the 'while' keyword. - It's inconsistent in another interpretation,
though; and I'd certainly have favored the latter form, to have the
label consistently attached at the loop-entry keyword.
I'd prefer label consistently attached to the loop-exit keyword.
I can see that this might look appealing in case of 'break'. In
case of the same mechanism working also for 'continue' I'd then
think that it should generally better be an "attribute" of the
loop entry keyword, i.e. placed where loops start. [...]
I think colocating it with `do` might create a syntactic
ambiguity. In the case of `for`, `while`, and `select`, there
is a required token following the keyword (the `(`). However,
for a `do`/`while` loop, `do` is followed immediately by a,
`secondary-block` production.
In particular, you do not _need_
braces to denote a compound statement after `do`; something like
`do i++; while (i < j);` is perfectly legal in C.
In the N3377 proposal, the new `block-name` is just an
identifier. If it were allowed immediately after the `do`, then
given, `do NAME statement; while(condition);` you can't tell
`NAME` from the name of the loop and a random identifier before
a statement; something like `do LOOP i++; while (i < j);`
appears as though it _would_ be be syntactically valid by N3377
as presently worked, but is the programmer's intent to create a
loop name, or should this just be a syntax error?
By requiring the block-name between a keyword and a
syntactically required `(`, you remove that ambiguity: if there
is an identifier there, then it is a `block-name`; if not, then
the block has no name.
The odd scoping rules for labels don't bother me either. They mean
you can't have two loops or switch statements with the same name in
the same function. I can barely imagine that being inconvenient.
On 2026-10-18 12:48, David Brown wrote:
On 17/10/2026 01:29, Janis Papanagnou wrote:
On 2026-10-17 00:00, Keith Thompson wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
[...]
There's a proposal for C2y to use goto labels as loop names, and a >>>>>> competing one to define a new syntax like "for NAME (;;)" :
[...]
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
Why would one question an opinion? ;-)
Time didn't word it as a personal opinion - he made it clear that he
doesn't think anyone else could have a different opinion.
You've noticed my smiley? (There was no need for an explanation.)
The C standards committee collectively reached an agreement counter
to Tim's thoughts, so clearly his preferred variant is /not/
unquestionably better.
"C" is "C", and Tim is Tim. (And we know both sufficiently.) :-)
So why IS C still around given that C++ compiler can build C programs,
more or less?
On 2026-10-18 12:48, David Brown wrote:
The C standards committee collectively reached an agreement counter
to Tim's thoughts, so clearly his preferred variant is /not/
unquestionably better.
My confidence in the collective wisdom of the ISO C committee has
declined in recent years, and sadly for more than just the last
few years. So learning that they have settled (even if that might
change in the future) on the "label: for(...)" approach is
disappointing, but not surprising.
In article <11b4smj$1vt4q$[email protected]>,
Keith Thompson <[email protected]> wrote:
The odd scoping rules for labels don't bother me either. They mean
you can't have two loops or switch statements with the same name in
the same function. I can barely imagine that being inconvenient.
An issue is that one might generate such a named loop with a
macro. I can imagine that being useful for `XIMPL` type
constructs, but C's macros are unusually weak, and C doesn't
have something like `(GENSYM)` in Lisp, so you've got to plumb
the loop name through the macro invocation: mildly annoying, but
not too bad.
Then again, if a programmer is abusing macros like that to
generate named loops multiple times in the same function,
then perhaps the program needs a re-think, ximpl or no.
- Dan C.
On 19/10/2026 02:19, Dan Cross wrote:
I see that you convenient snipped out my comment about C++,
which is the direct counter example.
I don't want to discuss C++. That language is abominable, other than as
the go-to example of language design going very wrong.
"Had" is a strong word; dare I say it...a subjective word.
In fact, there have been all kinds of alternatives for years.
In the earlish 1980s, there was Modula-2, PL/M, Forth, Ada, CLU,
BLISS, and so on. You yourself admit you started from Algol68.
By the late 1980s you had Oberon, decent versions of ML, C++
and Objective-C, etc; by the 1990s, there were more than you
could shake a stick at. Now? Take your pick.
You never "had" to use your own language.
OK. But they HAD to create C?
There were quite a few languages in the
early 70s too: like Pascal, Fortran, PL/I, Coral-66, plus of course BCPL
and B. So why a new one?
Anyway you don't know my circumstances. My homemade machine had
absolutely ZERO software. I literally had to start from binary machine
code, as there was no keyboard at first (more below).
I also never used Algol68; I'd only seen it in a book.
In my job later I was an engineer, not a programmer, and there was no
budget for software such as compilers. But they would anyway have been a >nightmare to install (floppy disk formats were not standard!), and would >been hopelessly slow to use.
The language I ended up creating was perfect for my needs and compiled
more or less instantly.
You do know; you just don't want to admit it. (Imagine introducing C
declarations into a current language.)
No, really; C's declaration syntax was inspired by FORTRAN, and
generations of scientists and engineers have managed that
language just fine.
FORTRAN syntax looked nothing like C! Unless you mean the general
pattern of 'INTEGER A, B' which was shared by half of all languages.
(I spent a year writing FORTRAN on mainframes and minicomputers.)
Generations of programmers have handled C's
all right as well.
How many gave up because it was too much? How many still struggle with
it and have to employ those 4 or 5 workarounds which I mention
elsewhere? How much has it affected productivity?
Your statement is meaningless. Maybe some task (in any sphere) takes 17 >steps to achieve. People will manage. But then somebody figures out how
to do it in 3 steps; that's better right?
No, according to you: let's stick with 17 steps; people have always
managed, and 10 million people can't be wrong!
Then why do you keep bringing your language up, showing snippets
of its syntax, and so on?
Suppose that language didn't exist. I guess then it would be OK to bring
up hypothetical new features and bits of syntax here? People do it all
the time (even Keith did today, of all people).
But if those examples come from an actual, working and proven >implementation, which lend them more weight, then it is not allowed and
the examples then become irrelevant?
I guess it is not playing the game in that case?
Why hasn't there long been an alternative systems language that didn't
have C's crazy syntax and stupid quirks? I mean like 30-50 years ago.
There...have been? And still are?
In that case, why has C itself been so heavily used, in OSes, drivers,
and endless libraries, rather than one those which you suggest I adopt?
I needed a language that worked at a lower level, could access hardware,
had inline assembly, had a weak type system that allowed all sorts of >underhand methods /to get things done/.
[snip same stuff over again]
[snip]
I gave you my circumstances above. What would /you/ have done?
[snip]
That's why ABIs matter.
You're confusing APIs and ABIs.
ABIs are a matter for compilers. Translating APIs into a set of bindings
for another language is someone else's job.
[snip sob story about walking uphill both ways in the snow]
But the crude
language I created FROM NOTHING still looked like this:
int a, b, c
println a + b
As mentioned, C came from B, once they got a PDP-11; it was an
incremental evolution of a language they already had. The type
syntax you find so distasteful was inspired by FORTRAN.
Please give an example of FORTRAN that looks like C.
It's so weird to me that you make such absolute pronouncements
about C and the choices that into its design, but are so
ajbectly ignorant of the actual history. Bluntly, you just are
not very well informed about it to make cogent comments.
How does knowing the history in such detail help? If a feature stinks,
it stinks.
See my post yesterday about the impact choosing a prefix dereference op >instead of postfix made on the language. It was probably even more >far-reaching than stated.
And yet Pascal was right there!
That choice had nothing to with limited hardware; it was just the wrong one.
In article <11b500f$216c4$[email protected]>, bart <[email protected]> wrote:If you're going to shit over everything I say, ignore points and keep
On 19/10/2026 02:19, Dan Cross wrote:
I see that you convenient snipped out my comment about C++,
which is the direct counter example.
I don't want to discuss C++. That language is abominable, other than as
the go-to example of language design going very wrong.
Oh. You don't _want_ to; I see. So you want to make statements
about the relative "productivity" of languages but ignore the
most prominent counter example to your argument because you
don't _want_ to discuss C++.
"Had" is a strong word; dare I say it...a subjective word.
In fact, there have been all kinds of alternatives for years.
In the earlish 1980s, there was Modula-2, PL/M, Forth, Ada, CLU,
BLISS, and so on. You yourself admit you started from Algol68.
By the late 1980s you had Oberon, decent versions of ML, C++
and Objective-C, etc; by the 1990s, there were more than you
could shake a stick at. Now? Take your pick.
You never "had" to use your own language.
OK. But they HAD to create C?
Doesn't matter. They did. You weren't there; you don't know
why they made the decisions they made, whether they gave this or
that serious consideration and dismissed it, or were unaware of
one thing or another, what constraints they were operating
under, etc.
It is _so easy_ to sit here and throw stones at people toiling
away in the 1960's because they made decisions you don't like.
But, bluntly, you haven't put in the work to have an opinion:
you are ignorant of the history, and actively resist even simple
things like reading the standard to back up your assertions;
when you're shown to be incorrect, you double down or (yes) move
the goalposts by making some other statement.
You came up with your toy language and compiler in the 80s; more
than a decade after C. It's cute that you felt you _had_ to do
that, but you were in a completely different context than the
1127 folks at Bell Labs who created C.
There were quite a few languages in the
early 70s too: like Pascal, Fortran, PL/I, Coral-66, plus of course BCPL
and B. So why a new one?
B _was_ a new language. Pascal as a useful language beyond
pedagogy postdates C. Pretty much the rest of this is discussed
in DMR's C history paper, which I'm willing to bet you haven't
bothered to read.
Anyway you don't know my circumstances. My homemade machine had
absolutely ZERO software. I literally had to start from binary machine
code, as there was no keyboard at first (more below).
Next you'll tell us you went to the beach and picked up sand so
you could smelt it and create your own silicon wafers, right?
You described its capabilities. It was vastly more capable than
a PDP-7, and it had only one user: you.
I also never used Algol68; I'd only seen it in a book.
You said yourself you modeled your language on Algol68; whether
you had used it or not is irrelevant.
In my job later I was an engineer, not a programmer, and there was no
budget for software such as compilers. But they would anyway have been a
nightmare to install (floppy disk formats were not standard!), and would
been hopelessly slow to use.
The language I ended up creating was perfect for my needs and compiled
more or less instantly.
You said you could not use a compiler and then literally
described using a compiler.
You do know; you just don't want to admit it. (Imagine introducing C
declarations into a current language.)
No, really; C's declaration syntax was inspired by FORTRAN, and
generations of scientists and engineers have managed that
language just fine.
FORTRAN syntax looked nothing like C! Unless you mean the general
pattern of 'INTEGER A, B' which was shared by half of all languages.
That was literally the thing you said you address with
left-to-right syntax, and that anyone who proposed such would be
laughed at. Now it's fine, just not in C. Because C is bad.
Or something.
(I spent a year writing FORTRAN on mainframes and minicomputers.)
I'm sure no one else here has done that. (*rolls eyes*)
Generations of programmers have handled C's
all right as well.
How many gave up because it was too much? How many still struggle with
it and have to employ those 4 or 5 workarounds which I mention
elsewhere? How much has it affected productivity?
Your statement is meaningless. Maybe some task (in any sphere) takes 17
steps to achieve. People will manage. But then somebody figures out how
to do it in 3 steps; that's better right?
Maybe, maybe not. There may well be other considerations that
factor into that decision.
No, according to you: let's stick with 17 steps; people have always
managed, and 10 million people can't be wrong!
So by this metric, it's cool if a pilot just jumps into an
airliner, turns it on, and takes off? The rest of the
pre-flight checklist is just busywork, amirite?
Then why do you keep bringing your language up, showing snippets
of its syntax, and so on?
Suppose that language didn't exist. I guess then it would be OK to bring
up hypothetical new features and bits of syntax here? People do it all
the time (even Keith did today, of all people).
But if those examples come from an actual, working and proven
implementation, which lend them more weight, then it is not allowed and
the examples then become irrelevant?
If you want to discuss C on its merits, then discuss C.
Unfortunately for you that would probably mean you'd have to
actually read the relevant documentation.
Do you _really_ think that the people who post here regularly
are not aware that, say, other variable declaration syntaxes
exist that are less messy than C's? No, seriously, don't give
me some other example from your language, answer that question
honestly: do you _really_ believe that no one here understands
that fact, or just outright disbelieves it?
I guess it is not playing the game in that case?
Why hasn't there long been an alternative systems language that didn't >>>> have C's crazy syntax and stupid quirks? I mean like 30-50 years ago.
There...have been? And still are?
In that case, why has C itself been so heavily used, in OSes, drivers,
and endless libraries, rather than one those which you suggest I adopt?
I can think of any number of reasons: legacy, compatibility,
tool availability, in some cases just personal preference. For
any one of these, I'm sure that someone has already told you
sometime in the last six months. My repeating them is unlikely
to have any effect.
I needed a language that worked at a lower level, could access hardware,
had inline assembly, had a weak type system that allowed all sorts of
underhand methods /to get things done/.
[snip same stuff over again]
No one cares.
[snip]
I gave you my circumstances above. What would /you/ have done?
Probably not spent years seething about how the rest of the
world is wrong for making decisions I would not have.
[snip]
That's why ABIs matter.
You're confusing APIs and ABIs.
ABIs are a matter for compilers. Translating APIs into a set of bindings
for another language is someone else's job.
You really don't understand how multilangauge environments work,
do you? Maybe have a look at an ABI document at some point.
[snip sob story about walking uphill both ways in the snow]
But the crude
language I created FROM NOTHING still looked like this:
int a, b, c
println a + b
Ok. Don't really care.
As mentioned, C came from B, once they got a PDP-11; it was an
incremental evolution of a language they already had. The type
syntax you find so distasteful was inspired by FORTRAN.
Please give an example of FORTRAN that looks like C.
Why? What would that show?
If you'd get over yourself for ten minutes and read the HOPL
paper on C, you may see this:
|Fortran influenced the syntax of declarations: B declarations
|begin with a specifier like `auto` or `static`, followed by a
|list of names, and C not only followed this style but
|ornamented it by placing its type keywords at the start of
|declarations. (https://www.nokia.com/bell-labs/about/dennis-m-ritchie/chist.html)
It's so weird to me that you make such absolute pronouncements
about C and the choices that into its design, but are so
ajbectly ignorant of the actual history. Bluntly, you just are
not very well informed about it to make cogent comments.
How does knowing the history in such detail help? If a feature stinks,
it stinks.
Much of your ranting amounts to, "how could anyone have possibly
thought this was a good idea?" Perhaps if you looked into the
history a bit, you may become enlightened as to why anybody
possibly thought it was a good idea.
See my post yesterday about the impact choosing a prefix dereference op
instead of postfix made on the language. It was probably even more
far-reaching than stated.
And yet Pascal was right there!
Amazingly, ALGOL W used syntax much closer to C's, despite being
the immediate predecessor of Pascal.
That choice had nothing to with limited hardware; it was just the wrong one.
One final quote from HOPL:
|Although we entertained occasional thoughts about implementing
|one of the major languages of the time like Fortran, PL/I, or
|Algol 68, such a project seemed hopelessly large for our
|resources: much simpler and smaller tools were called for. All
|these languages influenced our work, but it was more fun to do
|things on our own.
So, they were aware of all the languages you've cited as
influences. And yet they decided to do things differently.
Perhaps they had their reasons. They are not (in the case of
Ken) and were not (sadly, in the case of Dennis) idiiots or
fools.
On 2026-10-18 18:32, Michael S wrote:
On Sun, 18 Oct 2026 18:11:18 +0200
Janis Papanagnou <[email protected]> wrote:
I don't recall to have used any language with infix-expressions
that would have their monadic operators defined in postfix form.
I am a Bear of Very Little Brain, and long words Bother Me.
(If that quote is important for your argument, please explain.)
On Mon, 19 Oct 2026 15:44:40 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 18:32, Michael S wrote:
On Sun, 18 Oct 2026 18:11:18 +0200
Janis Papanagnou <[email protected]> wrote:
I don't recall to have used any language with infix-expressions
that would have their monadic operators defined in postfix form.
I am a Bear of Very Little Brain, and long words Bother Me.
(If that quote is important for your argument, please explain.)
Translation:
1. I have no idea what unary * has to do with infix-expressions
2. I don't appriciate use of the term "infix-expression" instead of more common (in context of description of C and similar languages) term
'binary operators'.
3. I don't know what "monadic operators defined in postfix form" means
and have no plans to look for the meaning
On 19/10/2026 15:16, Janis Papanagnou wrote:
On 2026-10-18 21:09, David Brown wrote:There are a number of things that I don't particularly like about C's declaration syntax, or where I think it would have been better if it
On 18/10/2026 18:09, bart wrote:[ declaration syntax ]
[...]
(I just want to comment on a [not unimportant] detail...)
You need to give things in the right order, or use parentheses, to
get the right "type expression". It's just like any other kind of
expression.
The intention of the declaration syntax in C is that the declaration
order follows usage. [...]
I think the first part is downplaying that languages typically indeed
make a distinction between parenthesized expressions and declarations.
Quite some other languages [not from the C-heritage] that I used all
did not need to introduce "expression"-grouping for _declarations_ in
the first place given their more consistent ways to declare entities.
The second part is, as I had understood C's history, the idea behind
how it got defined; needless to say that I think that was a bad idea.
But that's what we've got! If they had dropped that requirement/idea
the declaration syntax could have become "better" (more consistent,
less cryptic, less convoluted, clearer). Now, after half a century,
we just have to live with that, and folks who have "problems" with it
should better not touch this language (or maybe not doing programming
at all). The somewhat tragic aspect is that the "declaration follows
use" idea was (IIRC) intended to _simplify_ the understanding of its
concepts and use of the language; the consequences were seemingly not
valued correctly.
were different. But the "inside-to-outside" ordering is not one of
them. That is not because I think it is better or clearer than left-to- right ordering, but because when I compare to, say, Pascal, it's not a
big issue for me. Far bigger are :
1. People put too much into a single type declaration, rather than
building types out of logical parts with a purpose and a name. They
don't do it as much as Bart likes to pretend, but some people do it too
much for my liking. The language doesn't force you to do that - it's programmer style. IMHO there is never a reason for a "pointer to an
array of function pointers taking int and returning void" - no matter
what syntax is used.
Point 1. - I gave the hint that in languages that support RPN
(= Reverse Polish Notation) things like monadic postfix operators
(= having just _one_ argument applied _after_ the operator) are the
Janis
On 2026-10-19 21:35, Michael S wrote:
On Mon, 19 Oct 2026 15:44:40 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 18:32, Michael S wrote:
On Sun, 18 Oct 2026 18:11:18 +0200
Janis Papanagnou <[email protected]> wrote:
I don't recall to have used any language with infix-expressions
that would have their monadic operators defined in postfix form.
I am a Bear of Very Little Brain, and long words Bother Me.
(If that quote is important for your argument, please explain.)
Translation:
1. I have no idea what unary * has to do with infix-expressions
2. I don't appriciate use of the term "infix-expression" instead of
more common (in context of description of C and similar languages)
term 'binary operators'.
3. I don't know what "monadic operators defined in postfix form"
means and have no plans to look for the meaning
I'm sorry, these are (AFAICT) common terms, and I thought obvious.
So let me explain and amend with more text and examples...
Point 1. - I gave the hint that in languages that support RPN
(= Reverse Polish Notation) things like monadic postfix operators
(= having just _one_ argument applied _after_ the operator) are the
natural way of writing expressions. Less so in languages, which are
the majority since decades, that support expressions with infix
operators (= the operator arguments left and right of the operator).
Point 2. - A "binary operator" may be the '*' in the expressions
a * b typical infix notation (with parenthesis for precedence)
a b * RPN
* a b PN (Polish Notation)
A "binary operator" is something different from an "infix expression"
(the first one of the three; the others are RPN and PN examples).
That's why I took the appropriate term to explain what I intended to
explain.
Point 3. - "monadic" (see point 1). Applying to postfix form is best explained on another example; assume RPN
a - monadic (unary) minus (on one argument)
a b - dyadic (binary) minus (difference of two arguments)
Hope the terms are clear now. Now consider our original case, e.g.
a * *b ... multiply and dereference
a - -b ... subtract and negate
as soon as we parse the second operator we know its kind. With postfix operators we'd have (assuming same semantics but with postfix
operators)
a * b * ... now what is the second '*' at that point of parsing?
a - b - ... we don't expect that second '-' to be a negation.
The compilers can handle every variant. For the users it's different;
usually they seem to prefer unary operators to be prefixed (YMMV).
The question (concerning "C") was; would it have been "better" (in any respect) if the dereferencing operator would have been defined in "C"
as postfix operator (as you seem to prefer).
Janis
On 19/10/2026 12:50, Keith Thompson wrote:[...]
[...]The odd scoping rules for labels don't bother me either. They mean
you can't have two loops or switch statements with the same name in
the same function. I can barely imagine that being inconvenient.
I can imagine that being a bit inconvenient in some cases, but I think
the proposal in N3658 would simply and cleanly fix that.
In article <11b500f$216c4$[email protected]>, bart <[email protected]> wrote:[...]
I also never used Algol68; I'd only seen it in a book.
You said yourself you modeled your language on Algol68; whether
you had used it or not is irrelevant.
One final quote from HOPL:
|Although we entertained occasional thoughts about implementing
|one of the major languages of the time like Fortran, PL/I, or
|Algol 68, such a project seemed hopelessly large for our
|resources: much simpler and smaller tools were called for. All
|these languages influenced our work, but it was more fun to do
|things on our own.
So, they were aware of all the languages you've cited as
influences. And yet they decided to do things differently.
[...]
On 2026-10-18 21:09, David Brown wrote:
On 18/10/2026 18:09, bart wrote:[ declaration syntax ]
[...]
(I just want to comment on a [not unimportant] detail...)
You need to give things in the right order, or use parentheses, to
get the right "type expression". It's just like any other kind of
expression.
The intention of the declaration syntax in C is that the declaration
order follows usage. [...]
I think the first part is downplaying that languages typically indeed
make a distinction between parenthesized expressions and declarations.
Quite some other languages [not from the C-heritage] that I used all
did not need to introduce "expression"-grouping for _declarations_ in
the first place given their more consistent ways to declare entities.
On Mon, 19 Oct 2026 23:27:03 +0200
Janis Papanagnou <[email protected]> wrote:
[...]
If C was as strongly typed from the beginning as it ended up in the 2nd
half of the 70s then it would make sense to use postfix . (dot) instead
of prefix * as dereference operator.
[...]
On 2026-10-19 19:22, Dan Cross wrote:
In article <11b500f$216c4$[email protected]>, bart <[email protected]> wrote:[...]
I also never used Algol68; I'd only seen it in a book.
You said yourself you modeled your language on Algol68; whether
you had used it or not is irrelevant.
It may be worth the observation we could make here in the flood of
bart's posts; most (if not all) features or ideas he seems to have
adopted only on a lexical or syntactical level. Given what he gave
as examples I have strong doubts that this should be attributed to
Algol 68 in its "whole glory". - Syntactical inspiration; maybe. -
More than that? - I'd be astonished.
Janis Papanagnou <[email protected]> writes:
On 2026-10-18 12:48, David Brown wrote:
On 17/10/2026 01:29, Janis Papanagnou wrote:
On 2026-10-17 00:00, Keith Thompson wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
[...]
There's a proposal for C2y to use goto labels as loop names, and a >>>>>>> competing one to define a new syntax like "for NAME (;;)" :
[...]
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
Why would one question an opinion? ;-)
Time didn't word it as a personal opinion - he made it clear that he
doesn't think anyone else could have a different opinion.
You've noticed my smiley? (There was no need for an explanation.)
Anyone who thinks my statement "the second ("for NAME (;;)") is unquestionably better" was meant as a statement of fact rather
than a statement of opinion is an idiot.
I think most people can see that I am careful in my writing, and
also that I make an effort to differentiate statements of opinion,
statements of belief, and statements of fact. My remark above is
no exception to that practice.
For the benefit of any other people who may have not seen the
distinction here, please remember this: any statement that uses
the word "better", when made without any reference to some sort of
objective metric, is inherently a subjective statement. Any
subjective statement (that does not fall into the category of
being a statement of belief) is a statement of opinion. It's easy
to see this simply by a process of elimination, because subjective
statements are not facts, and vice versa.
My confidence in the collective wisdom of the ISO C committee has
declined in recent years, and sadly for more than just the last
few years. So learning that they have settled (even if that might
change in the future) on the "label: for(...)" approach is
disappointing, but not surprising.
Janis Papanagnou <[email protected]> writes:
On 2026-10-18 21:09, David Brown wrote:
On 18/10/2026 18:09, bart wrote:[ declaration syntax ]
[...]
(I just want to comment on a [not unimportant] detail...)
You need to give things in the right order, or use parentheses, to
get the right "type expression". It's just like any other kind of
expression.
The intention of the declaration syntax in C is that the declaration
order follows usage. [...]
I think the first part is downplaying that languages typically indeed
make a distinction between parenthesized expressions and declarations.
Quite some other languages [not from the C-heritage] that I used all
did not need to introduce "expression"-grouping for _declarations_ in
the first place given their more consistent ways to declare entities.
Just one quibble. C's declaration syntax *is* consistent. Its
rules are rigorously specified by the standard, particularly by
the grammar.
Many of us (myself included) don't particularly like it, but that
doesn't mean it's inconsistent.
My own take on all this is that having declaration syntax follow usage
was a very clever idea, where "clever" is not necessarily a compliment.
It was IMHO unsuccessful in the sense that it can lead to confusing
and overly complicated declarations.
(Other languages don't have tools
corresponding to cdecl for much the same reason that Spanish-speaking countries don't have spelling bees.) But it was extraordinarily
successful in the sense that, even if you think it was a bad idea,
it wasn't bad enough to keep C from becoming one of the most popular programming languages.
(I wonder if keeping the declaration-follows-use principle while
making "*" a postfix operator might have improved things.)
Names used for loops have a lighter-weight syntax:
LOOP_NAME:
while condition loop
-- ...
end loop;
I can't think of a better syntax for loop names than "NAME:" (used
by several other languages), but in C that syntax is already
taken for goto labels.
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
I find "break NAME;", where "NAME" is the name of an enclosing
construct, unambiguously better than "break N;", where N is the
number of levels to break out of. [...]
Definitely.
There's a proposal for C2y to use goto labels as loop names, and a
competing one to define a new syntax like "for NAME (;;)" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3355.htm
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3377.pdf
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
I do like the fact that it doesn't conflate goto labels with loop
names, but I still prefer the "NAME: for (;;)" form, partly because
it's consistent with several other languages.
Keith Thompson <[email protected]> writes:
Names used for loops have a lighter-weight syntax:
LOOP_NAME:
while condition loop
-- ...
end loop;
That's a syntax error. In Ada, if you put a loop name at the top of the
loop, you are required to repeat it at the bottom, like this:
LOOP_NAME: while condition loop
...
end loop LOOP_NAME;
If there's an "exit LOOP_NAME;" in there, it's pretty clear which
loop it's jumping out of, AND where it's jumping to.
I can't think of a better syntax for loop names than "NAME:" (used
by several other languages), but in C that syntax is already
taken for goto labels.
Agreed.
But in current C (before adding the named-loop feature),
and in Ada, and in many other languages, a label serves
as a warning: One or more gotos jump here. That's useful
information.
This new feature of C seems to lose that benefit, which
is unfortunate. But I think the "while LOOP_NAME..."
syntax is less readable than "LOOP_NAME: while...",
as you said.
So if it were up to me, I wouldn't add named loops to C in
either proposed syntax. The "goto" is good enough for
jumping out of nested loops.
[email protected] (Waldek Hebisch) writes:
Lawrence D?Oliveiro <[email protected]d> wrote:
On Tue, 13 Oct 2026 07:23:40 -0000 (UTC), Waldek Hebisch wrote:
So what those counts indicate: majority of loops is simple, that is
have no early exit. Vast majority of early exits is done via
'return'.
My experience in my own C code is quite the opposite. Lots of loops
have exits in the middle, leading me to use forms like ?for (;;)?. I
also try to avoid putting ?return? anywhere other than the end of a
function, to make it easier to see the flow of control.
Well, usually there is a lot of loops. Those with exit in the
middle are still significant.
Concernig 'return', having it in place where all work inside function
is done help me to see flow control and avoids complications. In
case of search functions it means return from the middle of the loop.
IMO possible alternatives like flag variables or break and retrun
after loop are worse.
I rarely use 'break' to exit a loop. Part of this is that I try to
write standard loops so that they complete as part of the loop test
(i.e., in while() or for() control expressions). That isn't the
whole story though so let me talk about 'return'.
Most of the functions I write have exactly one return, at the end of
the function. I estimate this pattern accounts for around 85% of
all functions, let's say plus or minus 5%.
Sometimes functions have early returns for errors or exceptional
conditions.
Early returns are easily seen to lie outside the main
body of function processing so they don't interfere with
understanding what the rest of the function is doing or how it
works.
A fairly common sub-pattern are functions most of whose body is a
switch() statement, with all of the switch() cases being a simple
return.
It does sometimes happen that a function will have a loop with a
return in the middle, and also a return at the end for what to do if
the loop terminates. To me having an in-loop return looks better
than using an assignment and a break.
A fairly rare but important pattern is what I might call vectoring
or decomposition. Here the function body serves to distinguish and
separate out different regimes of subprocessing. To continue
processing in a particular regime, a return is used not to directly
yield a value but rather to call a further function to handle that sub-domain. The benefit here is both to keep function bodies small
and to allow re-use of commonly called sub-functions.
Two aspects are important for having these different styles work
together. One is that it's easy to distinguish the different kinds
of patterns, and by far the most simple pattern is the most common.
The other is to be sure to keep function bodies small. Keeping
function bodies small goes a long way in making them easy to
understand, which obviously is a key property in writing good code.
Also keeping function bodies small effectively prevents mixing
different styles in a single function, serving to reinforce point
one.
[snip]
Anyone who thinks my statement "the second ("for NAME (;;)") is >unquestionably better" was meant as a statement of fact rather
than a statement of opinion is an idiot.
OK. But they HAD to create C? There were quite a few languages in the
early 70s too: like Pascal, Fortran, PL/I, Coral-66, plus of course BCPL
and B. So why a new one?
FORTRAN syntax looked nothing like C! Unless you mean the general
pattern of 'INTEGER A, B' which was shared by half of all languages.
You do not win in the market by making easy switch from your product
to competitor product. You may want to make it easy to switch _to_
your product. But you want to make switching to competing products
as hard as possible.
Similarly, BCPL was too complicated, B and C were simplifications
and adaptations small machine.
The "goto" is good enough for jumping out of nested loops.
On Mon, 19 Oct 2026 19:38:38 -0400, Bob Duff wrote:
The "goto" is good enough for jumping out of nested loops.
“Goto” leads inevitably to spaghetti code. [...]
David Brown <[email protected]> writes:
On 19/10/2026 12:50, Keith Thompson wrote:[...]
[...]The odd scoping rules for labels don't bother me either. They mean
you can't have two loops or switch statements with the same name in
the same function. I can barely imagine that being inconvenient.
I can imagine that being a bit inconvenient in some cases, but I think
the proposal in N3658 would simply and cleanly fix that.
*If* the fact that labels (which are now also loop/switch names)
follow strange scope rules is a real problem, N3658 is probably
the best practical solution. I'm slightly uncomfortable with the
idea of an entity's scope depending on how it's used, not just how
it's defined. I think it introduces a complication to the language
without much real benefit.
But cleaner solutions are impractical.
IMHO the only really clean solution would be to make labels and
loop/switch names distinct, keep the existing scoping rules for
labels, and use more normal scoping rules for loop/switch names.
And if the "while NAME (...)" proposal were accepted, that's probably
how it should work. (But I prefer having the name as a prefix of the
loop or switch statement.)
If N3658 were adopted, it wouldn't bother me much. I just don't
think it's necessary.
Janis Papanagnou <[email protected]> writes:
On 2026-10-18 12:48, David Brown wrote:
On 17/10/2026 01:29, Janis Papanagnou wrote:
On 2026-10-17 00:00, Keith Thompson wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
[...]
There's a proposal for C2y to use goto labels as loop names, and a >>>>>>> competing one to define a new syntax like "for NAME (;;)" :
[...]
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
Why would one question an opinion? ;-)
Time didn't word it as a personal opinion - he made it clear that he
doesn't think anyone else could have a different opinion.
You've noticed my smiley? (There was no need for an explanation.)
Anyone who thinks my statement "the second ("for NAME (;;)") is unquestionably better" was meant as a statement of fact rather
than a statement of opinion is an idiot.
I think most people can see that I am careful in my writing, and
also that I make an effort to differentiate statements of opinion,
statements of belief, and statements of fact. My remark above is
no exception to that practice.
Careful with adverbs, folks, especially with absolute ones in
generalizing text contexts!
On 19/10/2026 14:46, David Brown wrote:
On 19/10/2026 15:16, Janis Papanagnou wrote:
On 2026-10-18 21:09, David Brown wrote:There are a number of things that I don't particularly like about C's
On 18/10/2026 18:09, bart wrote:[ declaration syntax ]
[...]
(I just want to comment on a [not unimportant] detail...)
You need to give things in the right order, or use parentheses, to
get the right "type expression". It's just like any other kind of
expression.
The intention of the declaration syntax in C is that the declaration
order follows usage. [...]
I think the first part is downplaying that languages typically indeed
make a distinction between parenthesized expressions and declarations.
Quite some other languages [not from the C-heritage] that I used all
did not need to introduce "expression"-grouping for _declarations_ in
the first place given their more consistent ways to declare entities.
The second part is, as I had understood C's history, the idea behind
how it got defined; needless to say that I think that was a bad idea.
But that's what we've got! If they had dropped that requirement/idea
the declaration syntax could have become "better" (more consistent,
less cryptic, less convoluted, clearer). Now, after half a century,
we just have to live with that, and folks who have "problems" with it
should better not touch this language (or maybe not doing programming
at all). The somewhat tragic aspect is that the "declaration follows
use" idea was (IIRC) intended to _simplify_ the understanding of its
concepts and use of the language; the consequences were seemingly not
valued correctly.
declaration syntax, or where I think it would have been better if it
were different. But the "inside-to-outside" ordering is not one of
them. That is not because I think it is better or clearer than left-
to- right ordering, but because when I compare to, say, Pascal, it's
not a big issue for me. Far bigger are :
1. People put too much into a single type declaration, rather than
building types out of logical parts with a purpose and a name. They
don't do it as much as Bart likes to pretend, but some people do it
too much for my liking. The language doesn't force you to do that -
it's programmer style. IMHO there is never a reason for a "pointer to
an array of function pointers taking int and returning void" - no
matter what syntax is used.
Then you have a peculiar and restricted coding style.
(Funny that when I suggest that nested loop breaks are uncommon,
everyone says I'm wrong! Some even write 200-line made-up examples to
prove their point.)
These are two actual function pointer arrays from my projects (not C):
[]ref proc hosthandlers = ...
[pclnames.len]ref proc(pcl) px_handlertable
There is no reason to abstract away that function pointer type.
You probably do so in C /because/ the type involves * () and [] but have somehow persuaded yourself that it just better that way.
Note that 'pcl' in my example /is/ a typedef; here it makes sense as it
is used in 100s of places. This function pointer occurs in only one place.
(The C version looks like: 'void (*name[N]))T)'. I used a tool and transcribed it, then I double-checked and found I'd written '(*name)[N]'
not '(*name[N])'; I wouldn't have noticed.)
BTW what name would be given to such a function pointer type? There is nothing obvious other than 'funcptr', but suppose there is more than one
in scope?
Something else strikes me about breaking up a complex type-decl sequence into a chain of typedefs: if you take that list of typedefs, and rotate
it 90 degrees c/w, you have something that resembles the LTR
representation!
On 2026-10-19 21:35, Michael S wrote:
On Mon, 19 Oct 2026 15:44:40 +0200
Janis Papanagnou <[email protected]> wrote:
On 2026-10-18 18:32, Michael S wrote:
On Sun, 18 Oct 2026 18:11:18 +0200
Janis Papanagnou <[email protected]> wrote:
I don't recall to have used any language with infix-expressions
that would have their monadic operators defined in postfix form.
I am a Bear of Very Little Brain, and long words Bother Me.
(If that quote is important for your argument, please explain.)
Translation:
1. I have no idea what unary * has to do with infix-expressions
2. I don't appriciate use of the term "infix-expression" instead of more
common (in context of description of C and similar languages) term
'binary operators'.
3. I don't know what "monadic operators defined in postfix form" means
and have no plans to look for the meaning
I'm sorry, these are (AFAICT) common terms, and I thought obvious.
So let me explain and amend with more text and examples...
Point 1. - I gave the hint that in languages that support RPN
(= Reverse Polish Notation) things like monadic postfix operators
(= having just _one_ argument applied _after_ the operator) are the
natural way of writing expressions. Less so in languages, which are
the majority since decades, that support expressions with infix
operators (= the operator arguments left and right of the operator).
Point 2. - A "binary operator" may be the '*' in the expressions
a * b typical infix notation (with parenthesis for precedence)
a b * RPN
* a b PN (Polish Notation)
A "binary operator" is something different from an "infix expression"
(the first one of the three; the others are RPN and PN examples).
That's why I took the appropriate term to explain what I intended to
explain.
Point 3. - "monadic" (see point 1). Applying to postfix form is best explained on another example; assume RPN
a - monadic (unary) minus (on one argument)
a b - dyadic (binary) minus (difference of two arguments)
Hope the terms are clear now. Now consider our original case, e.g.
a * *b ... multiply and dereference
a - -b ... subtract and negate
as soon as we parse the second operator we know its kind. With postfix operators we'd have (assuming same semantics but with postfix operators)
a * b * ... now what is the second '*' at that point of parsing?
a - b - ... we don't expect that second '-' to be a negation.
The compilers can handle every variant. For the users it's different;
usually they seem to prefer unary operators to be prefixed (YMMV).
The question (concerning "C") was; would it have been "better" (in any respect) if the dereferencing operator would have been defined in "C"
as postfix operator (as you seem to prefer).
Janis
In article <11b285v$121v2$[email protected]>,
David Brown <[email protected]> wrote:
On 17/10/2026 01:29, Janis Papanagnou wrote:
On 2026-10-17 00:00, Keith Thompson wrote:
Tim Rentsch <[email protected]> writes:
Keith Thompson <[email protected]> writes:
[...]
There's a proposal for C2y to use goto labels as loop names, and a >>>>>> competing one to define a new syntax like "for NAME (;;)" :
[...]
I'm not particularly a fan of multi-level break/continue. But if
we're going to have one of these, the second ("for NAME (;;)") is
unquestionably better.
Unquestionably? Why?
Why would one question an opinion? ;-)
Time didn't word it as a personal opinion - he made it clear that he
doesn't think anyone else could have a different opinion.
Tim often makes it sound as though he believes that his opinions
are facts.
On 19/10/2026 23:28, bart wrote:
(Funny that when I suggest that nested loop breaks are uncommon,
everyone says I'm wrong! Some even write 200-line made-up examples to
prove their point.)
I don't remember "everyone" saying you were wrong to say that nested
loop breaks are uncommon - in fact, I don't remember /anyone/ saying
that was wrong.
There is no reason to abstract away that function pointer type.
You probably do so in C /because/ the type involves * () and [] but
have somehow persuaded yourself that it just better that way.
Do you hear that whooshing noise? It is the sound of the point flying
far above your head.
Here is an example of some sensible function typedefs, all from third-
party code (so not my "peculiar" style)
typedef void (*TimerCallbackFunction_t)( TimerHandle_t xTimer );
TimerHandle_t xTimerCreate( const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void * pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
typedef void (*lwip_thread_fn)(void *arg);
typedef void (*tcpip_init_done_fn)(void *arg);
typedef void (*tcpip_callback_fn)(void *ctx);
typedef void (* sys_timeout_handler)(void *arg);
typedef void (*dns_found_callback)(const char *name,
const ip_addr_t *ipaddr, void *callback_arg);
Ask yourself why the typedefs are used. Look at the /names/. Those
last four are all from the same network stack library, and are all
typedefs for "void (*)(void*)".
Note that 'pcl' in my example /is/ a typedef; here it makes sense as
it is used in 100s of places. This function pointer occurs in only one
place.
I'm sorry, I had mistaken you for a programmer who wanted to write good, clear programs. Naming things is not a shortcut to save keypresses.
BTW what name would be given to such a function pointer type?
I have no idea what your code is supposed to do,
[email protected] (Dan Cross) writes:
[snip]
Tim often makes it sound as though he believes that his opinions
are facts.
I invite you to compare the statements made about David Parnas and
his advice on software development, first those in the original
edition of The Mythical Man-Month and second those in the revised
(20th Anniversary) edition of MM-M, both of course by Fred Brooks.
I learned a lot from Fred Brooks.
On 20/10/2026 09:01, David Brown wrote:
On 19/10/2026 23:28, bart wrote:
(Funny that when I suggest that nested loop breaks are uncommon,
everyone says I'm wrong! Some even write 200-line made-up examples to
prove their point.)
I don't remember "everyone" saying you were wrong to say that nested
loop breaks are uncommon - in fact, I don't remember /anyone/ saying
that was wrong.
(There was a LOT of antipathy towards my idea to fix the common case of 'loop-break' clashing with 'switch-break', BECAUSE it did not fix the problem of nested loop-break, which is uncommon, even though that wasn't
the aim.)
There is no reason to abstract away that function pointer type.
You probably do so in C /because/ the type involves * () and [] but
have somehow persuaded yourself that it just better that way.
Do you hear that whooshing noise? It is the sound of the point flying
far above your head.
Here is an example of some sensible function typedefs, all from third-
party code (so not my "peculiar" style)
typedef void (*TimerCallbackFunction_t)( TimerHandle_t xTimer );
TimerHandle_t xTimerCreate( const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void * pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
typedef void (*lwip_thread_fn)(void *arg);
typedef void (*tcpip_init_done_fn)(void *arg);
typedef void (*tcpip_callback_fn)(void *ctx);
typedef void (* sys_timeout_handler)(void *arg);
typedef void (*dns_found_callback)(const char *name,
const ip_addr_t *ipaddr, void *callback_arg);
This is the kind of C I find hard to read. There are lots of typedefs
but few uses of those typedefs that I can see, so I don't know how much difference they make.
Except here:
typedef void (*TimerCallbackFunction_t)( TimerHandle_t xTimer );
TimerHandle_t xTimerCreate( const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void * pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
Without the typedef, I believe it would just be this:
TimerHandle_t xTimerCreate( const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void * pvTimerID,
void (*pxCallbackFunction)(TimerHandle_t));
(I've left out the parameter name of the callback function, as I don't believe it is that useful.
I've left in the regular parameter names, even though C doesn't need
them, but they are quite heavy - you don't really need those Hungarian- style prefixes.)
Well, I guess this buys you one thing: the parameter name for the last parameter is to the right of its type, rather than be inside it. But a C expert should not be fazed by that.
Here is the same function as I might write it in an alternative syntax.
I've kept the same names, but changed case-style and removed prefixes
and suffixes. I've capitalised user-type names:
func TimerCreate( # (retain case if FFI import)
ichar timername,
Ticktype timerperiodinticks,
Ubasetype autoreload,
ref void timerid,
ref proc(Timerhandle) callbackfn)
In this form, it's hard to see what benefit a typedef would give for
that last parameter; it is simple enough.
Ask yourself why the typedefs are used. Look at the /names/. Those
last four are all from the same network stack library, and are all
typedefs for "void (*)(void*)".
Until you mentioned it, I hadn't noticed. So typedef has done a good job
of hiding that useful fact! But looking more closely, it is the first
four of the last five.
Let's take one:
typedef void (*lwip_thread_fn)(void *arg);
That 'arg' is not much use for a start (other than being a hint that
this particular (...) is where the parameters go).
So, maybe this is used like this:
void F(lwip_thread_fn lwip_thread_callback);
Here you have two identifiers imparting the sort kind of information; a tautology.
If that function pointer pattern is common, or recurs in a suite of functions, I might also have used a typedef, but with a common name.
Then only one would be needed, say:
typedef void (*stack_callbackfn)(void);
I might have done the same in that alternate syntax as it would start to
get cluttery: 'ref proc(ref void)', but also in order to define that
common pattern in one place.
Note that 'pcl' in my example /is/ a typedef; here it makes sense as
it is used in 100s of places. This function pointer occurs in only
one place.
I'm sorry, I had mistaken you for a programmer who wanted to write
good, clear programs. Naming things is not a shortcut to save
keypresses.
Isn't that one of the main uses of typedefs? So as to give a handy, 'euphonious' one-token alias to an elaborate typedef.
It also allows you to change the type in one place without having to
update hundreds of instances.
It also allows the type to be opaque.
Saving keypresses is bonus benefit, but if it is shorter, then it can
also help readability as other critical elements are not overshadowed.
So I'm not sure what objection you have to this particular use of it.
Here is the one place I do remember using typedef for a function pointer (from an old project, not in C):
type fnptr = ref proc
repeat
(fnptr(pcptr^))^()
until stopped
It's used as a cast, but reason I have it is because with simple cast syntax, which is 'T(X)', the meaning without it would be ambiguous (a grammar issue that I might fix one day).
Rather than fallback to standard cast syntax (which is 'cast(X, T)'),
this was tidier.
BTW what name would be given to such a function pointer type?
I have no idea what your code is supposed to do,
It's a table of function pointers! All sharing the same signature.
That's pretty generic. Is it really that hard to guess? You don't need
to know what they do, other than at some point they will be called as handlertable[i](arg).
bart <[email protected]> wrote:
OK. But they HAD to create C? There were quite a few languages in the
early 70s too: like Pascal, Fortran, PL/I, Coral-66, plus of course BCPL
and B. So why a new one?
You ignore fact that Ritche wanted reasonably fast code from
very simple compiler.
PL/I had most needed features. But PL/I was a big language,
to run on small machine they would have to take tiny subset
and then add extentions. Basicaly they would end up with a
language which is very far from PL/I.
Similarly, BCPL was too complicated, B and C were simplifications
and adaptations small machine.
I think that Pascal was too late: nominally it was created earlier
but I think that it was available to Bell Labs only after they
did initial work leading to C. And Pascal shared problem of
speed on small machines. Note that later UCSD Pascal which
run on micros compiled to interpreted bytecode, which significantly
reduced performance.
FORTRAN syntax looked nothing like C! Unless you mean the general
pattern of 'INTEGER A, B' which was shared by half of all languages.
I think more pattern of
INTEGER A(20), B
which has similar structure to C variable declarations.
Of course,
FORTRAN had no pointers (and structures or unions), so Ritche had
to invent syntax for them.
IMO C suffers because typedef was added late in the game and
function prototypes are much later. Prototypes need types and
to get it one needs "hole" in variable declaration. Where the
hole should be is specified by the C syntax, but placement of
hole is probably least clear aspect of declarations.
IMO C declaration syntax was a mistake, but as real life shows
it was not a fatal mistake, people can adapt.
On 19/10/2026 23:27, Janis Papanagnou wrote:
On 2026-10-19 21:35, Michael S wrote:
[...]
I'm sorry, these are (AFAICT) common terms, and I thought obvious.
I am afraid your terminology is further from common use than you
thought.
("Common use" of course depends on the context of the user -
we are in the context of C programmers.) Your posts can be clearer if
you use appropriate terminology.
So let me explain and amend with more text and examples...
Point 1. - I gave the hint that in languages that support RPN
(= Reverse Polish Notation) things like monadic postfix operators
(= having just _one_ argument applied _after_ the operator) are the
natural way of writing expressions. Less so in languages, which are
the majority since decades, that support expressions with infix
operators (= the operator arguments left and right of the operator).
RPN - Reverse Polish Notation - is certainly a well-known term, though
the abbreviation might seem out of place.
"Postfix" is the term most
obvious in the context of C, as that is the term used in the standards.
And while "x y +" is clearly RPN, "x *" is not - it could be part of an infix expression, or a unary postfix operator.
"Monadic" /can/ refer to single argument functions or operators.
But it
can also mean something completely different - monadic operations are operations that work on "packaged" types that unpack the value, apply a function, and pack it in again. There is nothing of that kind in C (the language or standard library), but it is becoming a familiar term for
users of C++ and is well-established in many other languages.
The C standard using "unary" for single-argument operators.
Similarly, "binary" is the normal term for two-argument operators, not "dyadic". (Though I don't think "dyadic" has any other common meanings.)
Point 2. - A "binary operator" may be the '*' in the expressions
a * b typical infix notation (with parenthesis for precedence) >> a b * RPN
Normally known as "postfix", especially in C.
* a b PN (Polish Notation)
There is no term "Polish Notation" -
except as occasionally used to
mean /postfix/ as a short form of "Reverse Polish Notation". RPN was invented, or at least popularised, by the Polish logician Jan
Łukasiewicz (I admit to looking that up on Wikipedia!). There is no
"PN" opposite.
A "binary operator" is something different from an "infix expression"
(the first one of the three; the others are RPN and PN examples).
That's why I took the appropriate term to explain what I intended to
explain.
Yes, binary operators can be prefix, infix or postfix.
[ snip rest ]
The other was C. There, several choices were made:
* To start with that Fortran style except that [] are used
* To decree that that 'A[20]' syntax is supposed to match indexing of
A as it might appear in an expression
* To introduce "*" as a prefix dereference operator in expressions ...
* ... which then means that a prefix "*" appears in the declaration too
* A further complication was to allow function pointers within that a
declaration list
* Yet one more which came later was to add 'const', where placement now
gets confusing
But to stay with pointers, take this expression:
*A[i]
C precedence rules mean this is parsed as *(A[i]), which means that a
type written as 'T *A[N]' must be an array of pointers to T (I had to
think for a few seconds!).
But suppose you wanted a pointer to array of T? The expression for that would be:
(*A)[i]
And so the declaration has to be 'T (*A)[N]' too.
So it is unfortunate that parentheses used to control precedence in an expression now also have to appear in type declarations (where they are often next to () used for parameter lists, for further confusion).
==============================================
So, what would have happened with a postfix deref op? (Ignore whether
'*' would still be a good choice.) My first example would be this:
A*[i]
Here, it would mean that A is dereferenced, then indexed; A must then be
a pointer to an array of T.
But suppose we wanted the original array of pointers to T, where you
index first then dereference. That is written like this:
A[i]*
You simply swap the order of [] and *.
So, PARENTHESES HAVE BEEN ELIMINATED for purpose of disambiguating array/pointer and pointer/array, both within expressions and within type-declarations.
How about that? Further, most of the type-spec is now LTR; only the base-type has to stay on the left. Access terms in expressions will be
fully LTR.
IMO C suffers because typedef was added late in the game and
function prototypes are much later. Prototypes need types and
to get it one needs "hole" in variable declaration. Where the
hole should be is specified by the C syntax, but placement of
hole is probably least clear aspect of declarations.
I thought that 'hole' was where 'int A[10]' mean one thing in normal declaration but another within a parameter list.
IMO C declaration syntax was a mistake, but as real life shows
it was not a fatal mistake, people can adapt.
A mistake that could so easily have been avoid by choosing a different precedence as shown above. Did none of the thousand people working at
Bell Labs (according to a comment in DC's follow-ip) spot this and say anything?
Had no-one even glanced at a Pascal spec, if there was no working copy?
It would have transformed C type syntax.
(ACTUALLY IT IS NOT TOO LATE. A secondary postfix deref op could have
been added. This could have been done 50 years ago, with the original eventually deprecated.
But this is a common theme of mine whether I perceive a problem that
people grudgingly admit might not be idea. But nothing was ever done to
fix it even after decades.)
On 2026-10-20 10:25, David Brown wrote:
On 19/10/2026 23:27, Janis Papanagnou wrote:
On 2026-10-19 21:35, Michael S wrote:
[...]
I'm sorry, these are (AFAICT) common terms, and I thought obvious.
I am afraid your terminology is further from common use than you thought.
I'm afraid you are wrong here; in several ways. I'll expand below.
On 20/10/2026 09:01, David Brown wrote:
On 19/10/2026 23:28, bart wrote:
(Funny that when I suggest that nested loop breaks are uncommon,
everyone says I'm wrong! Some even write 200-line made-up examples to
prove their point.)
I don't remember "everyone" saying you were wrong to say that nested
loop breaks are uncommon - in fact, I don't remember /anyone/ saying
that was wrong.
(There was a LOT of antipathy towards my idea to fix the common case of >'loop-break' clashing with 'switch-break', BECAUSE it did not fix the >problem of nested loop-break, which is uncommon, even though that wasn't
the aim.)
There is no reason to abstract away that function pointer type.
You probably do so in C /because/ the type involves * () and [] but
have somehow persuaded yourself that it just better that way.
Do you hear that whooshing noise? It is the sound of the point flying
far above your head.
Here is an example of some sensible function typedefs, all from third-
party code (so not my "peculiar" style)
typedef void (*TimerCallbackFunction_t)( TimerHandle_t xTimer );
TimerHandle_t xTimerCreate( const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void * pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
typedef void (*lwip_thread_fn)(void *arg);
typedef void (*tcpip_init_done_fn)(void *arg);
typedef void (*tcpip_callback_fn)(void *ctx);
typedef void (* sys_timeout_handler)(void *arg);
typedef void (*dns_found_callback)(const char *name,
const ip_addr_t *ipaddr, void *callback_arg);
This is the kind of C I find hard to read. There are lots of typedefs
but few uses of those typedefs that I can see, so I don't know how much >difference they make.
[snip]
I've left in the regular parameter names, even though C doesn't need
them, but they are quite heavy - you don't really need those
Hungarian-style prefixes.)
Well, I guess this buys you one thing: the parameter name for the last >parameter is to the right of its type, rather than be inside it. But a C >expert should not be fazed by that.
Here is the same function as I might write it in an alternative syntax.
I've kept the same names, but changed case-style and removed prefixes
and suffixes. I've capitalised user-type names:
func TimerCreate( # (retain case if FFI import)
ichar timername,
Ticktype timerperiodinticks,
Ubasetype autoreload,
ref void timerid,
ref proc(Timerhandle) callbackfn)
In this form, it's hard to see what benefit a typedef would give for
that last parameter; it is simple enough.
Ask yourself why the typedefs are used. Look at the /names/. Those
last four are all from the same network stack library, and are all
typedefs for "void (*)(void*)".
Until you mentioned it, I hadn't noticed. So typedef has done a good job
of hiding that useful fact! But looking more closely, it is the first
four of the last five.
Let's take one:
typedef void (*lwip_thread_fn)(void *arg);
That 'arg' is not much use for a start (other than being a hint that
this particular (...) is where the parameters go).
So, maybe this is used like this:
void F(lwip_thread_fn lwip_thread_callback);
Here you have two identifiers imparting the sort kind of information; a >tautology.
If that function pointer pattern is common, or recurs in a suite of >functions, I might also have used a typedef, but with a common name.
Then only one would be needed, say:
typedef void (*stack_callbackfn)(void);
I might have done the same in that alternate syntax as it would start to
get cluttery: 'ref proc(ref void)', but also in order to define that
common pattern in one place.
Note that 'pcl' in my example /is/ a typedef; here it makes sense as
it is used in 100s of places. This function pointer occurs in only one
place.
I'm sorry, I had mistaken you for a programmer who wanted to write good,
clear programs. Naming things is not a shortcut to save keypresses.
Isn't that one of the main uses of typedefs? So as to give a handy, >'euphonious' one-token alias to an elaborate typedef.
It also allows you to change the type in one place without having to
update hundreds of instances.
It also allows the type to be opaque.
Saving keypresses is bonus benefit, but if it is shorter, then it can
also help readability as other critical elements are not overshadowed.
So I'm not sure what objection you have to this particular use of it.
Here is the one place I do remember using typedef for a function pointer >(from an old project, not in C):
type fnptr = ref proc
repeat
(fnptr(pcptr^))^()
until stopped
It's used as a cast, but reason I have it is because with simple cast >syntax, which is 'T(X)', the meaning without it would be ambiguous (a >grammar issue that I might fix one day).
Rather than fallback to standard cast syntax (which is 'cast(X, T)'),
this was tidier.
BTW what name would be given to such a function pointer type?
I have no idea what your code is supposed to do,
It's a table of function pointers! All sharing the same signature.
That's pretty generic. Is it really that hard to guess? You don't need
to know what they do, other than at some point they will be called as >handlertable[i](arg).
Rust implementation of Timers, mentioned above<--
On 20/10/2026 16:11, bart wrote:
The other was C. There, several choices were made:
* To start with that Fortran style except that [] are used
* To decree that that 'A[20]' syntax is supposed to match indexing of
A as it might appear in an expression
* To introduce "*" as a prefix dereference operator in expressions ...
* ... which then means that a prefix "*" appears in the declaration too
* A further complication was to allow function pointers within that a
declaration list
I don't see a problem with that. If you need to declare a function pointer, you need to declare it in a declaration list.
To me, the big disadvantage of C's declaration syntax is that it lets
you declare things of different (but related) types in the same
declaration.
or, more common and therefore worse :
int * a, b;
I was going to say it was right-to-left, but it can be considered both* Yet one more which came later was to add 'const', where placement now
gets confusing
Some people do find it hard to understand the difference between :
const int * p;
int * const q;
const int * const r;
I note that this is despite the clear left-to-right nature of "const" here.
Complicated types are a minority.
So, PARENTHESES HAVE BEEN ELIMINATED for purpose of disambiguating
array/pointer and pointer/array, both within expressions and within
type-declarations.
Agreed.
But does that make a significant difference? I don't think so.
A mistake that could so easily have been avoid by choosing a different
precedence as shown above. Did none of the thousand people working at
Bell Labs (according to a comment in DC's follow-ip) spot this and say
anything?
I suspect the folks at Bell Labs were too busy writing real code to be bothered by how confused you would be with artificially complex types.
(ACTUALLY IT IS NOT TOO LATE. A secondary postfix deref op could have
been added. This could have been done 50 years ago, with the original
eventually deprecated.
It /is/ too late - far, far too late. It would be a terrible idea to
add a new postfix dereference operator to give two different operators
with no benefit other than very occasionally reducing the need for parentheses.
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote:
The point is that the name you chose is meaningless to anyone
other than you. What's a PCL? Phase Control Line? Printer
Command Language? Photon Compressor Loop?
Here is the one place I do remember using typedef for a function pointer
(from an old project, not in C):
type fnptr = ref proc
repeat
(fnptr(pcptr^))^()
until stopped
More generally, I fail to see what this is trying to
demonstrate.
On 20/10/2026 02:03, Waldek Hebisch wrote:
bart <[email protected]> wrote:
OK. But they HAD to create C? There were quite a few languages in
the early 70s too: like Pascal, Fortran, PL/I, Coral-66, plus of
course BCPL and B. So why a new one?
You ignore fact that Ritche wanted reasonably fast code from
very simple compiler.
According to DC's quote from HOPL, it was also more fun to create a
new language.
PL/I had most needed features. But PL/I was a big language,
to run on small machine they would have to take tiny subset
and then add extentions. Basicaly they would end up with a
language which is very far from PL/I.
There were PL/360 and PL/M, although those were more specific, more 'machine-oriented' languages. (I implemented one for PDP10 but it was
a port of a systems language from a GEC machine.)
Anyway, a more general subset could have been used.
Similarly, BCPL was too complicated, B and C were simplifications
and adaptations small machine.
I think that Pascal was too late: nominally it was created earlier
but I think that it was available to Bell Labs only after they
did initial work leading to C. And Pascal shared problem of
speed on small machines. Note that later UCSD Pascal which
run on micros compiled to interpreted bytecode, which significantly
reduced performance.
It would not have been hard to use Pascal as a starting point for a
workable systems language. Wirth wouldn't have approved, but his
languages were too pure, too academic; some of us had things we
needed to get done!
Here I mean adapting Pascal for a competing systems language.
In my hands some aspects would be simplified (eg. no nested
functions, no closures), thus making it easier to generate decent
code with a simple compiler.
FORTRAN syntax looked nothing like C! Unless you mean the general
pattern of 'INTEGER A, B' which was shared by half of all
languages.
I think more pattern of
INTEGER A(20), B
which has similar structure to C variable declarations.
OK. That was typical for the time. But in Fortran it didn't get much
more complicated than that. Maybe 2D arrays and so on.
Of course,
FORTRAN had no pointers (and structures or unions), so Ritche had
to invent syntax for them.
There were three languages from that era that I know had pointers or references, and which allowed composing arbitrary types with arrays
and pointers, two of which were Algol68 and Pascal.
Both used a 100% LTR form.
The other was C. There, several choices were made:
* To start with that Fortran style except that [] are used
* To decree that that 'A[20]' syntax is supposed to match indexing of
A as it might appear in an expression
* To introduce "*" as a prefix dereference operator in expressions ...
* ... which then means that a prefix "*" appears in the declaration
too
* A further complication was to allow function pointers within that a
declaration list
* Yet one more which came later was to add 'const', where placement
now gets confusing
But to stay with pointers, take this expression:
*A[i]
C precedence rules mean this is parsed as *(A[i]), which means that a
type written as 'T *A[N]' must be an array of pointers to T (I had to
think for a few seconds!).
But suppose you wanted a pointer to array of T? The expression for
that would be:
(*A)[i]
And so the declaration has to be 'T (*A)[N]' too.
So it is unfortunate that parentheses used to control precedence in
an expression now also have to appear in type declarations (where
they are often next to () used for parameter lists, for further
confusion).
==============================================
So, what would have happened with a postfix deref op? (Ignore whether
'*' would still be a good choice.) My first example would be this:
A*[i]
Here, it would mean that A is dereferenced, then indexed; A must then
be a pointer to an array of T.
But suppose we wanted the original array of pointers to T, where you
index first then dereference. That is written like this:
A[i]*
You simply swap the order of [] and *.
So, PARENTHESES HAVE BEEN ELIMINATED for purpose of disambiguating array/pointer and pointer/array, both within expressions and within type-declarations.
How about that? Further, most of the type-spec is now LTR; only the base-type has to stay on the left. Access terms in expressions will
be fully LTR.
IMO C suffers because typedef was added late in the game and
function prototypes are much later. Prototypes need types and
to get it one needs "hole" in variable declaration. Where the
hole should be is specified by the C syntax, but placement of
hole is probably least clear aspect of declarations.
I thought that 'hole' was where 'int A[10]' mean one thing in normal declaration but another within a parameter list.
IMO C declaration syntax was a mistake, but as real life shows
it was not a fatal mistake, people can adapt.
A mistake that could so easily have been avoid by choosing a
different precedence as shown above. Did none of the thousand people
working at Bell Labs (according to a comment in DC's follow-ip) spot
this and say anything?
Had no-one even glanced at a Pascal spec, if there was no working
copy? It would have transformed C type syntax.
(ACTUALLY IT IS NOT TOO LATE. A secondary postfix deref op could have
been added. This could have been done 50 years ago, with the original eventually deprecated.
But this is a common theme of mine whether I perceive a problem that
people grudgingly admit might not be idea. But nothing was ever done
to fix it even after decades.)
On 20/10/2026 20:24, Dan Cross wrote:
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote:
The point is that the name you chose is meaningless to anyone
other than you. What's a PCL? Phase Control Line? Printer
Command Language? Photon Compressor Loop?
Within the context of that application then it would be clear. You're
just being overly hostile.
(Within the app, PCL is the name of a bytecode language, and 'pcl' is a >reference to a specific instruction.
Next time I'll just use T for such examples, since the type is not
relevant to the point. Although that didn't stop you seizing upon my F >function.)
Here is the one place I do remember using typedef for a function pointer >>> (from an old project, not in C):
type fnptr = ref proc
repeat
(fnptr(pcptr^))^()
until stopped
More generally, I fail to see what this is trying to
demonstrate.
Not much. It is just a rare example of my using aliases for function >pointers. Because I suggested such aliases are often unnecessary and
partly used in C to get around the fiddly type syntax that would arise.
In article <11b8j17$3btus$[email protected]>, bart <[email protected]> wrote:
On 20/10/2026 20:24, Dan Cross wrote:
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote:
The point is that the name you chose is meaningless to anyone
other than you. What's a PCL? Phase Control Line? Printer
Command Language? Photon Compressor Loop?
Within the context of that application then it would be clear. You're
just being overly hostile.
Not really. You are, I presume, posting that code to try and
make some kind of point about how "readable" it is. But it's
not readable unless you already know what it does.
On the other hand, the code David posted _is_ readable, because
it uses the language to encode domain-specific information into
type names.
Yeah, you really just don't get it.One of us doesn't get it.
On Tue, 20 Oct 2026 15:11:35 +0100
bart <[email protected]> wrote:
I suppose that you wholeheartedly agree. I don't. I never found computer language design fun.
Methinks there were less than 100 people exposed to C before it became
too late. May be, just 50.
Had no-one even glanced at a Pascal spec, if there was no working
copy? It would have transformed C type syntax.
(ACTUALLY IT IS NOT TOO LATE. A secondary postfix deref op could have
been added. This could have been done 50 years ago, with the original
eventually deprecated.
But this is a common theme of mine whether I perceive a problem that
people grudgingly admit might not be idea. But nothing was ever done
to fix it even after decades.)
It was. There are many new languages.
Today, C sees little use outside of small to mid-sized mocrocontrollers
and OS kernels.
Most user-layer applications on general purpose computers are written
in newer languages.
Tim Rentsch <[email protected]> wrote:
[email protected] (Waldek Hebisch) writes:
Lawrence D?Oliveiro <[email protected]d> wrote:
On Tue, 13 Oct 2026 07:23:40 -0000 (UTC), Waldek Hebisch wrote:
So what those counts indicate: majority of loops is simple, that is >>>>> have no early exit. Vast majority of early exits is done via
'return'.
My experience in my own C code is quite the opposite. Lots of loops
have exits in the middle, leading me to use forms like ?for (;;)?. I
also try to avoid putting ?return? anywhere other than the end of a
function, to make it easier to see the flow of control.
Well, usually there is a lot of loops. Those with exit in the
middle are still significant.
Concernig 'return', having it in place where all work inside function
is done help me to see flow control and avoids complications. In
case of search functions it means return from the middle of the loop.
IMO possible alternatives like flag variables or break and retrun
after loop are worse.
I rarely use 'break' to exit a loop. Part of this is that I try to
write standard loops so that they complete as part of the loop test
(i.e., in while() or for() control expressions). That isn't the
whole story though so let me talk about 'return'.
I counted various constructs in a small suite of 2 programs (1306
lines in 3 files). There are 4 breaks outside switches and 32
loops in total. My gut feeling is that this proportion is
reasonable close to typical in my code. For comparison, there
are 67 functions and 70 'if'-s.
Most of the functions I write have exactly one return, at the end of
the function. I estimate this pattern accounts for around 85% of
all functions, let's say plus or minus 5%.
In code above about half of functions is 'void' and there are 34
explicit returns (of which at least 2 are early returns).
Sometimes functions have early returns for errors or exceptional
conditions.
Code above contains 16 occurences of 'exit(1)'. One of those is
in a macro that is used 10 times, so actually there are 25 places
which call 'exit(1)'. That is related to the programs being
simple utilities, there is no attempt to error recovery, on error
programs simply print error message and exit.
Early returns are easily seen to lie outside the main
body of function processing so they don't interfere with
understanding what the rest of the function is doing or how it
works.
A fairly common sub-pattern are functions most of whose body is a
switch() statement, with all of the switch() cases being a simple
return.
Code above has 2 switches, both are in parsing functions, where
cases either move to next state or signal error. Parsing functions
also open file and close it when finished and return data structure
with parsed info.
It does sometimes happen that a function will have a loop with a
return in the middle, and also a return at the end for what to do if
the loop terminates. To me having an in-loop return looks better
than using an assignment and a break.
A fairly rare but important pattern is what I might call vectoring
or decomposition. Here the function body serves to distinguish and
separate out different regimes of subprocessing. To continue
processing in a particular regime, a return is used not to directly
yield a value but rather to call a further function to handle that
sub-domain. The benefit here is both to keep function bodies small
and to allow re-use of commonly called sub-functions.
Two aspects are important for having these different styles work
together. One is that it's easy to distinguish the different kinds
of patterns, and by far the most simple pattern is the most common.
The other is to be sure to keep function bodies small. Keeping
function bodies small goes a long way in making them easy to
understand, which obviously is a key property in writing good code.
Also keeping function bodies small effectively prevents mixing
different styles in a single function, serving to reinforce point
one.
I think that in general my C code has similar characteristics.
But
let me note that while I have a lot of small functions, I also have
some which are bigger. I suspect that 10% or more of my code is
in functions that are bigger then 30 lines. Such functions
frequently have several variables and there is setup stage to
initialize things, actual processing and final part (cleanups,
possibly extraction of result). Stages are clearly sepatated
by their position inside function, OTOH are strongly coupled due
to use of variables. My feeling here is that in case of strongly
coupled code with no reusable parts keeping it inside single
function is more managable than trying to split it into smaller
functions.
Without typedef's, that function signature would be something like :
signed char dns_gethostbyname(const char *hostname, struct ip_addr
*addr, void (*found)(const char *name, const struct ip_addr
*ipaddr, void *callback_arg), void *callback_arg);
On 20/10/2026 22:44, Dan Cross wrote:
In article <11b8j17$3btus$[email protected]>, bart <[email protected]> wrote:
On 20/10/2026 20:24, Dan Cross wrote:
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote: >>>
The point is that the name you chose is meaningless to anyone
other than you. What's a PCL? Phase Control Line? Printer
Command Language? Photon Compressor Loop?
Within the context of that application then it would be clear. You're
just being overly hostile.
Not really. You are, I presume, posting that code to try and
make some kind of point about how "readable" it is. But it's
not readable unless you already know what it does.
What it does not relevant. This is simply defining an array of T. But >because T happens to be a function pointer, DB insists that an alias
must be created, and a new name invented.
Why? Probably because in C, the syntax for function pointers gets hairy.
On the other hand, the code David posted _is_ readable, because
it uses the language to encode domain-specific information into
type names.
Maybe we should create aliases for function signatures more often then,
then we can encode that extra info.
So that instead of, for example:
void SomeFunc(int x, int y) {printf("%d %d\n", x, y);}
you do:
typedef void Take2Ints(int x, int y);
Take2Ints SomeFunc {printf("%d %d\n", x, y);}
If you have a suite of functions sharing the signature, then it might be
a good idea. But funnily enough, you never see this being done.
(I don't know if this is legal C; but it works fine with my compiler:
c:\m>type fred.c
#include <stdio.h>
typedef void Take2Ints(int x, int y);
Take2Ints SomeFunc{printf("%d %d\n", x, y);}
int main(void) { SomeFunc(10, 20); }
c:\m>bcc -r -q fred
10 20
)
Yeah, you really just don't get it.
One of us doesn't get it.
On 20/10/2026 13:41, bart wrote:
But let us take a concrete example. These network functions are from
the LWIP network stack, which is designed to be used on small embedded systems that may not have any kind of OS - so it uses call-backs for asynchronous programming.
An example API function is this :
err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
dns_found_callback found, void *callback_arg)
The returned "err_t" can be "ERR_OK" (indicating the "hostname" is in
the DNS cache and *addr is set to the IP), "ERR_ARG" for argument
errors, or "ERR_INPROGRESS" to indicate that the stack is looking up the
DNS name, and will call the callback when there is a final result or timeout.
Without typedef's, that function signature would be something like :
signed char dns_gethostbyname(const char *hostname, struct ip_addr
*addr, void (*found)(const char *name, const struct ip_addr
*ipaddr, void *callback_arg), void *callback_arg);
Do you expect anyone to believe you if you claim this is easier to read
than the real declaration using typedefs? I'll believe you if you say
you find the original hard to read - but not if you claim the
"untypedef'ed" version is clearer.
On 19/10/2026 23:27, Janis Papanagnou wrote:[...]
* a b PN (Polish Notation)
There is no term "Polish Notation" - except as occasionally used to
mean /postfix/ as a short form of "Reverse Polish Notation". RPN was invented, or at least popularised, by the Polish logician Jan
Łukasiewicz (I admit to looking that up on Wikipedia!). There is no
"PN" opposite.
In article <11b8qqg$3ejlp$[email protected]>, bart <[email protected]> wrote:
On 20/10/2026 22:44, Dan Cross wrote:
In article <11b8j17$3btus$[email protected]>, bart <[email protected]> wrote: >>>> On 20/10/2026 20:24, Dan Cross wrote:
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote: >>>>
The point is that the name you chose is meaningless to anyone
other than you. What's a PCL? Phase Control Line? Printer
Command Language? Photon Compressor Loop?
Within the context of that application then it would be clear. You're
just being overly hostile.
Not really. You are, I presume, posting that code to try and
make some kind of point about how "readable" it is. But it's
not readable unless you already know what it does.
What it does not relevant. This is simply defining an array of T. But
because T happens to be a function pointer, DB insists that an alias
must be created, and a new name invented.
Why? Probably because in C, the syntax for function pointers gets hairy.
I dunno; your syntax didn't seem any clearer to me.
Yeah, the C is so much clearer. Of course, you would all lie through[...]
your teeth anyway before you'd admit mine might be simpler.
On 21/10/2026 01:56, Dan Cross wrote:
In article <11b8qqg$3ejlp$[email protected]>, bart <[email protected]> wrote:
On 20/10/2026 22:44, Dan Cross wrote:
In article <11b8j17$3btus$[email protected]>, bart <[email protected]> wrote: >>>>> On 20/10/2026 20:24, Dan Cross wrote:
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote: >>>>>
The point is that the name you chose is meaningless to anyone
other than you. What's a PCL? Phase Control Line? Printer
Command Language? Photon Compressor Loop?
Within the context of that application then it would be clear. You're >>>>> just being overly hostile.
Not really. You are, I presume, posting that code to try and
make some kind of point about how "readable" it is. But it's
not readable unless you already know what it does.
What it does not relevant. This is simply defining an array of T. But
because T happens to be a function pointer, DB insists that an alias
must be created, and a new name invented.
Why? Probably because in C, the syntax for function pointers gets hairy.
I dunno; your syntax didn't seem any clearer to me.
Yeah, the C is so much clearer. Of course, you would all lie through
your teeth anyway before you'd admit mine might be simpler.
bart <[email protected]> writes:
[...]
Yeah, the C is so much clearer. Of course, you would all lie through[...]
your teeth anyway before you'd admit mine might be simpler.
You preemptively accuse someone of being a liar, and then you wonder
why people are hostile to you.
Tone down the insults and hyperbole.
t to end each case-sequence in a switch statement with
a break-statement: put the break at the same indentation level as the case-clause as well as the switch-expression. That way, you can scan
your eye down a single line f
On 20/10/2026 16:02, David Brown wrote:
On 20/10/2026 16:11, bart wrote:
The other was C. There, several choices were made:
* To start with that Fortran style except that [] are used
* To decree that that 'A[20]' syntax is supposed to match indexing of
A as it might appear in an expression
* To introduce "*" as a prefix dereference operator in expressions ...
* ... which then means that a prefix "*" appears in the declaration too
* A further complication was to allow function pointers within that a
declaration list
I don't see a problem with that. If you need to declare a function
pointer, you need to declare it in a declaration list.
To me, the big disadvantage of C's declaration syntax is that it lets
you declare things of different (but related) types in the same
declaration.
Yes, but that doesn't bite so much because it is uncommon.
or, more common and therefore worse :
int * a, b;
(See below.)
I was going to say it was right-to-left, but it can be considered both* Yet one more which came later was to add 'const', where placement now
gets confusing
Some people do find it hard to understand the difference between :
const int * p;
int * const q;
const int * const r;
I note that this is despite the clear left-to-right nature of "const"
here.
and thus not clear:
const int const * const p;
1 2 3
const 1 applies to the basetype to its right.
const 2 applies to the basetype to its left.
(Both also can be in the middle with compound types like 'long long'!)
const 3 is tricky: I think it applies to the * to its left, since it
says that the pointer value itself is const. But 'p' has type 'pointer
to', so it could apply to that directly.
What about this however:
int * const * p;
1 2 3
I think here, const 2 applies to * 1, which is to it's left, and can't
apply to 'p' as that is the other side of the * 3.
Fair to say that is a complete mess, and it is error prone.
With a LTR syntax that a postfix deref would achieve, 'const' would
always be written immediately to the left of any * modifiers. (It is meaningless for arrays and functions.)
It is never applied directly to a variable name.
For base types, it can be applied on the left, but C would still allow
it on the right or in the middle, or all three with duplicates.
That means there would be an ambiguity here where there is no identifier between 'int' and 'const':
(const int const *)
For such reasons I would restrict base type const to be only on the left.)
Complicated types are a minority.
I've showed even simple types or trying to use 'const' get becomes confusing.
So, PARENTHESES HAVE BEEN ELIMINATED for purpose of disambiguating
array/pointer and pointer/array, both within expressions and within
type-declarations.
Agreed.
But does that make a significant difference? I don't think so.
It would make a HUGE difference:
(1) It helps to fix that confusion above
(2) You don't need parentheses so no need to remember if you want
(*A)[] or *A[]. Those will disappear from expressions too; less
clutter all round.
(3) It simplifies indexing of pointer-to-array from (*A)[i] to A*[i], so
that actual array pointers, which are more type-safe, could start to
appear more in C rather than the current T* idiom
(4) For pointers to structs, these are the patterns:
prefix * With -> With postfix *
(*P).m P->m P*.m
(**P).m (*P)->m P**.m
(***P).m (**P)->m P***.m
Which column looks the tidiest?
(5) With prefix *, a pointer type looks like 'T*'; notice the * is on
the right, not left! With postfix *, it would all be consistent. You
also wouldn't have 'T*A'; that would be an error (T* only happens
when there is no name)
(6) Your 'int * a, b' example would become:
int a *, b;
Much easier, even with that space, to see that '*' does not belong to
the base type but is a modifier for that variable.
It doesn't fix everything, so you'd still have this:
int p* = &a;
p* = a;
To fix this requires that all modifiers apply to the base type. But this would be a massive change. The above is merely what happens when *
becomes postfix.
A mistake that could so easily have been avoid by choosing a
different precedence as shown above. Did none of the thousand people
working at Bell Labs (according to a comment in DC's follow-ip) spot
this and say anything?
I suspect the folks at Bell Labs were too busy writing real code to be
bothered by how confused you would be with artificially complex types.
So you agree the process was very different compared to that which lead
to Ada for example? Just a couple of guys left to do their own thing.
(Maybe they were respected enough that no one dared to offer any constructive criticism, or if they did then it was dismissed. As happens here.)
(ACTUALLY IT IS NOT TOO LATE. A secondary postfix deref op could have
been added. This could have been done 50 years ago, with the original
eventually deprecated.
It /is/ too late - far, far too late. It would be a terrible idea to
add a new postfix dereference operator to give two different operators
with no benefit other than very occasionally reducing the need for
parentheses.
But a special operator P->m to do the same job as (*P).m was fine! The
new op would eliminate the need for ->.
David Brown <[email protected]> writes:
[...]
Without typedef's, that function signature would be something like :
signed char dns_gethostbyname(const char *hostname, struct ip_addr
*addr, void (*found)(const char *name, const struct ip_addr
*ipaddr, void *callback_arg), void *callback_arg);
I might write that as:
signed char dns_gethostbyname(
const char *hostname,
struct ip_addr *addr,
void (*found)(
const char *name,
const struct ip_addr *ipaddr,
void *callback_arg
),
void *callback_arg
);
so the indentation and structure reflects the semantics. I find
that much clearer than your version. (I'm not commenting on the
merits of typedefs.)
On 20/10/2026 13:58, David Brown wrote:
On 20/10/2026 13:41, bart wrote:
But let us take a concrete example. These network functions are from
the LWIP network stack, which is designed to be used on small embedded
systems that may not have any kind of OS - so it uses call-backs for
asynchronous programming.
An example API function is this :
err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
dns_found_callback found, void *callback_arg)
The returned "err_t" can be "ERR_OK" (indicating the "hostname" is in
the DNS cache and *addr is set to the IP), "ERR_ARG" for argument
errors, or "ERR_INPROGRESS" to indicate that the stack is looking up
the DNS name, and will call the callback when there is a final result
or timeout.
Without typedef's, that function signature would be something like :
signed char dns_gethostbyname(const char *hostname, struct ip_addr
*addr, void (*found)(const char *name, const struct ip_addr >> *ipaddr, void *callback_arg), void *callback_arg);
Do you expect anyone to believe you if you claim this is easier to
read than the real declaration using typedefs? I'll believe you if
you say you find the original hard to read - but not if you claim the
"untypedef'ed" version is clearer.
Neither are great. But let's first lay them out better:
err_t
dns_gethostbyname(
const char *hostname,
ip_addr_t *addr,
dns_found_callback found,
void *callback_arg
);
Here, one problem is that there are 3 types that I don't know and would
have to look up.
The long version at least has all the info in one place:
signed char
dns_gethostbyname(
const char *hostname,
struct ip_addr *addr,
void (*found)(const char *name, const struct ip_addr *ipaddr, void *callback_arg),
void *callback_arg
);
That signed char return is unusual; why not 'int'? (How would you even
print an 'err_t' value anyway)?
That 'ip_addr_t' turns out to be a struct. For those I would use
typedefs anyway; I rarely use struct tags and you have to invent an identifier in either case.
Then we come to the function pointer, which is a quite a chunky one, but let's work with it. Here, I would question whether you really need those types in there, and especially those names.
Presumably you have a regular function of your own with the same
signature? You anyway never directly 'call' this parameter with
arguments; you just pass it the address of your handler.
Or do you use that typedef as documentation?
Where does the info come from anyway; does the library export a suitable typedef? In that case you might as well use it. But if not, info must
come from elsewhere.
Anyway with some tweaks in place, using the struct typedef and using an inline function pointer type, it would look like this:
signed char
dns_gethostbyname(
const char *hostname,
IP_addr *addr,
void (*found)(char*, IP_addr*, void *),
void *arg
);
In this form, it is not wildly different from your short version.
So I would look at other ways of tidying up before resorting to
extraneous typedefs.
But here, there may well be an extra reason to use a callback typedef; I don't have the full details.
On 21/10/2026 03:04, bart wrote:
[snip]
Anyway with some tweaks in place, using the struct typedef and using an
inline function pointer type, it would look like this:
signed char
dns_gethostbyname(
const char *hostname,
IP_addr *addr,
void (*found)(char*, IP_addr*, void *),
void *arg
);
In this form, it is not wildly different from your short version.
Not wildly different, just worse by counter-productively removing the >abstractions and appropriate type names, and uselessly cluttering the >declaration with unnecessary detail.
On 20/10/2026 22:07, bart wrote:
On 20/10/2026 16:02, David Brown wrote:
On 20/10/2026 16:11, bart wrote:
* A further complication was to allow function pointers within that a
declaration list
To me, the big disadvantage of C's declaration syntax is that it lets
you declare things of different (but related) types in the same
declaration.
Yes, but that doesn't bite so much because it is uncommon.
Unfortunately not - but it is uncommon to mix objects and function declarations, or objects of wildly different real types.
const int const * const p;
1 2 3
const 1 applies to the basetype to its right.
const 2 applies to the basetype to its left.
These are redundant - they do the same thing. (I'd have preferred if
the ordering rules were strict - allowing only "const int" or "int
const" - but at least people are usually consistent in their style.)
(Both also can be in the middle with compound types like 'long long'!)
const 3 is tricky: I think it applies to the * to its left, since it
says that the pointer value itself is const. But 'p' has type 'pointer
to', so it could apply to that directly.
Yes - it is "p" that is const, not the "*".
What about this however:
int * const * p;
1 2 3
I think here, const 2 applies to * 1, which is to it's left, and can't
apply to 'p' as that is the other side of the * 3.
*p is of type "int * const" - thus you can use "*p" to access a pointer- to-int, but you can't use *p to change that pointer-to-int.
Fair to say that is a complete mess, and it is error prone.
No, it is not at all fair to say that. It is fair to say that a
different way of writing types might make it easier to understand - but that's a /long/ way from saying it is "a complete mess". And you can't call it "error prone" unless you know that people regularly use such declarations, and often have bugs in their code as a result of doing so incorrectly. I think that is an unrealistic claim.
You can write this in C++ :
// This bit is only needed once
template <typename T> using ptr = T *;
// p is a pointer to a const pointer to an int
ptr<const ptr<int>> p;
That's LTR syntax. Sure, it also has < > parentheses, but that's a
minor point since the ordering of the components is what apparently
matters so much.
Or you can write :
typedef int * p_int;
const p_int * p;
Thus p is a pointer to a "const p_int", where a "p_int" is a pointer to
an int.
These are different ways to write the same type, including one that is
LTR, and the main hinder to understanding remains the same - what is the type for?
I've showed even simple types or trying to use 'const' get becomes
confusing.
No, you haven't.
It would make a HUGE difference:
Your points below are all true, but IMHO all very minor, and do not add
up to anything much.
Your invented confusion.
That doesn't matter in practice.
I don't see that as significant.
I do agree that the decay of expressions using array types into pointer types is a source of error in C code - though I do not think it is as
bad as you do.
But I just don't see pointer-to-array expressions to be common enough
for the difference you describe to be important.
(4) For pointers to structs, these are the patterns:
prefix * With -> With postfix *
(*P).m P->m P*.m
(**P).m (*P)->m P**.m
(***P).m (**P)->m P***.m
Which column looks the tidiest?
Far and away the most common - by orders of magnitude - are pointers to structs. "p->m" looks fine to me, and I prefer it to "p*.m".
(5) With prefix *, a pointer type looks like 'T*'; notice the * is on
the right, not left! With postfix *, it would all be consistent. You
also wouldn't have 'T*A'; that would be an error (T* only happens >> when there is no name)
The C declaration syntax is "declaration follows use". If "*" were a postfix operator, then the declaration of a pointer-to-int would become:
int p*;
while the type of p would be "int *". So you would still have an inconsistency there, unless you also changed the way C has its
declarations.
(6) Your 'int * a, b' example would become:
int a *, b;
Much easier, even with that space, to see that '*' does not belong to
the base type but is a modifier for that variable.
It's still bad. I don't think finding a way to make it easier to write
bad code is a good idea.
So basically, the suggestion would change some very minor things -
mostly in subjective ways - and not actually do anything for aspects of
the language where there is more of a consensus that C is sub-optimal.
And for this, you would want a fundamental change to one of the most
used operators in all C code!
On 21/10/2026 03:04, bart wrote:
Where does the info come from anyway; does the library export a
suitable typedef? In that case you might as well use it. But if not,
info must come from elsewhere.
Of course it "exports" the typedef - it is in one of the library's headers.
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote:
On 20/10/2026 09:01, David Brown wrote:
On 19/10/2026 23:28, bart wrote:
(Funny that when I suggest that nested loop breaks are uncommon,
everyone says I'm wrong! Some even write 200-line made-up examples to
prove their point.)
I don't remember "everyone" saying you were wrong to say that nested
loop breaks are uncommon - in fact, I don't remember /anyone/ saying
that was wrong.
(There was a LOT of antipathy towards my idea to fix the common case of
'loop-break' clashing with 'switch-break', BECAUSE it did not fix the
problem of nested loop-break, which is uncommon, even though that wasn't
the aim.)
Those are two different things. No one disagrees with you that
"nested break from a switch inside of a loop" is relatively more
common than other variants.
Using that as an excuse not to provide a more general mechanism
because you already have a proposal for the specific case is
what I and others took you to task for. I find this ironic,
since you rail against things in C that you do not like, citing
the most ridiculous examples you can think of that do not show
up in actual programs, yet for something where it is pointed out
to you that your solution does not generalize, you claim that it
does not need to because ... the general case rarely shows up in
a real program.
There is no reason to abstract away that function pointer type.
You probably do so in C /because/ the type involves * () and [] but
have somehow persuaded yourself that it just better that way.
Do you hear that whooshing noise? It is the sound of the point flying
far above your head.
Here is an example of some sensible function typedefs, all from third-
party code (so not my "peculiar" style)
typedef void (*TimerCallbackFunction_t)( TimerHandle_t xTimer );
TimerHandle_t xTimerCreate( const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void * pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
typedef void (*lwip_thread_fn)(void *arg);
typedef void (*tcpip_init_done_fn)(void *arg);
typedef void (*tcpip_callback_fn)(void *ctx);
typedef void (* sys_timeout_handler)(void *arg);
typedef void (*dns_found_callback)(const char *name,
const ip_addr_t *ipaddr, void *callback_arg);
This is the kind of C I find hard to read. There are lots of typedefs
but few uses of those typedefs that I can see, so I don't know how much
difference they make.
You again missed the entire point. You may not see many uses
of them, but as David says, the `typedef`s give you
domain-specific *names* understandable to the programmer: a
programmer can see the `sys_timeout_handler` type instantly know
that this has a different function than the,
`tcpip_callback_fn`, despite the having the same type.
The other point is that the ridiculous examples you make up to
illustrate your distaste for C declaration syntax basically do
not appear in real programs.
[snip]
I've left in the regular parameter names, even though C doesn't need
them, but they are quite heavy - you don't really need those
Hungarian-style prefixes.)
Well, I guess this buys you one thing: the parameter name for the last
parameter is to the right of its type, rather than be inside it. But a C
expert should not be fazed by that.
Here is the same function as I might write it in an alternative syntax.
I've kept the same names, but changed case-style and removed prefixes
and suffixes. I've capitalised user-type names:
func TimerCreate( # (retain case if FFI import)
ichar timername,
Ticktype timerperiodinticks,
Ubasetype autoreload,
ref void timerid,
ref proc(Timerhandle) callbackfn)
In this form, it's hard to see what benefit a typedef would give for
that last parameter; it is simple enough.
What is your point? Do you have one? If you don't want to use
C, don't use C.
There are plenty of languages that can do this kind of thing
that are not C and have syntax and semantics closer to what you
seem to want. Here's an example in Rust:
pub trait TimerHandle { ... }
fn CreateTimer<T>(
timer_name: &str,
period: std::time::Duration,
auto_reload: bool,
timer_id: T,
handler: fn(&dyn TimerHandle),
) -> Result<Timer<T>, TimerError>
I didn't know what an `UBaseType_t` is, and while "autoreload"
sounded pretty intuitive, I wasn't sure about the semantics, so
I looked it up (the example comes from `FreeRTOS`). In this
context, it is a boolean saying whether the timer should repeat
with the given periodicity, or whether it is a one-shot.
The timer_id is opaque to the timer, and it looks like it's used
to facilitating the handler accessing timer-specific data. In
C, passing it as a `void *` is used as a way to get a poor-man's
overloading. But Rust has generics, I just made it generic over
some type T.
If I were writing this from scratch in Rust, a language that has
generics, closures, and so sum types, I'd do the whole thing
differently; see the end for an example.
But I digress. The point here is, Bart, that alternatives exist
if you don't like C. You don't have to keep posting, over and
over again, in comp.lang.c of all places, about how oh so
terribly awful C is. If you don't want to program in C, simply
don't program in C.
Ask yourself why the typedefs are used. Look at the /names/. Those
last four are all from the same network stack library, and are all
typedefs for "void (*)(void*)".
Until you mentioned it, I hadn't noticed. So typedef has done a good job
of hiding that useful fact! But looking more closely, it is the first
four of the last five.
Let's take one:
typedef void (*lwip_thread_fn)(void *arg);
That 'arg' is not much use for a start (other than being a hint that
this particular (...) is where the parameters go).
So, maybe this is used like this:
void F(lwip_thread_fn lwip_thread_callback);
I have no idea what you're trying to say here. The obvious (and
honestly, excusable) syntax error aside, what is F? It's a
function that, what, takes two function pointers?
The type defined by `lwip_thread_fn` is a pointer to a function
that takes a void pointer (`void *`) as its sole arugment, and
returns `void` (that is, has no meaningful return value).
Intuitively, the name implies that this is the function run as
some thread, so we'd pass it to a thread creation function. The
usual shape of those things is to give them a pointer to some
function to run in the new thread, and a pointer to some
arguments to be passed to that function.
For example:
void
whatever(void *argp)
{
struct Args *args = argp;
while (keep_running()) {
// Do the thing the thread is supposed to do.
}
thread_exit(SUCCESS);
}
thread_t *
start_the_whatever_thread(void)
{
struct Args *args = malloc(sizeof(*args));
if (args == NULL) abort();
memset(args, 0, sizeof(*args));
args->whatever = something();
// etc...
thread_t *thr = thread_create(whatever, args);
if (thr == NULL) abort();
return thr;
}
Something could start this as:
thread_t *whatever_id = start_the_whatever_thread();
At some point later, if you want to wait for the thread to
exit, you'd run:
(void)thread_join(whatever_id);
Note this is decently complex behavior, but it's actually quite
intuitive from the name and the type.
Here you have two identifiers imparting the sort kind of information; a
tautology.
That's not what a tautology is.
If that function pointer pattern is common, or recurs in a suite of
functions, I might also have used a typedef, but with a common name.
Then you loose the domain specificity; you can't tell from the
name whether you need an LwIP thread, or a callback, or a
something run in a different thread, or just a plain 'ol
function you want to apply to run every now and again for a side
effect.
Then only one would be needed, say:
typedef void (*stack_callbackfn)(void);
I might have done the same in that alternate syntax as it would start to
get cluttery: 'ref proc(ref void)', but also in order to define that
common pattern in one place.
I dunno. Sounds like you have no idea what the code that David
posted is meant to do. But that's a "you" problem.
Note that 'pcl' in my example /is/ a typedef; here it makes sense as
it is used in 100s of places. This function pointer occurs in only one >>>> place.
I'm sorry, I had mistaken you for a programmer who wanted to write good, >>> clear programs. Naming things is not a shortcut to save keypresses.
Isn't that one of the main uses of typedefs? So as to give a handy,
'euphonious' one-token alias to an elaborate typedef.
It also allows you to change the type in one place without having to
update hundreds of instances.
It also allows the type to be opaque.
The point is that the name you chose is meaningless to anyone
other than you. What's a PCL? Phase Control Line? Printer
Command Language? Photon Compressor Loop?
Saving keypresses is bonus benefit, but if it is shorter, then it can
also help readability as other critical elements are not overshadowed.
So I'm not sure what objection you have to this particular use of it.
Have you ever written a large program that was maintained by
anyone other than yourself?
Here is the one place I do remember using typedef for a function pointer
(from an old project, not in C):
type fnptr = ref proc
repeat
(fnptr(pcptr^))^()
until stopped
It's used as a cast, but reason I have it is because with simple cast
syntax, which is 'T(X)', the meaning without it would be ambiguous (a
grammar issue that I might fix one day).
Rather than fallback to standard cast syntax (which is 'cast(X, T)'),
this was tidier.
I can only guess at what this may mean. Hazarding a guess,
`pcptr` is a "pointer to a program counter", which is a
reference type to some type that represents some executable
memory location in the program. You then have a loop that runs
until "stopped" is true where you indirect the program counter
pointer, cast it to a pointer to a function, and then invoke
the function, right? One presumes you have the, "PC Pointer"
because it changes over time, otherwise, you'd just give
whatever it points to a name and call it.
More generally, I fail to see what this is trying to
demonstrate. If it's to show some sort of imagined superiority
over C, I don't see it; that's sort of thing is easy enough to
write:
typedef void (*fnptr)(void);
// Assume uintptr_t *pcptr is declared somewhere.
do {
((fnptr)*pcptr)();
} while (!stopped);
E.g.,
```
term% cat b.c
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
static void first(void);
typedef void (*fnptr)(void);
bool stopped = false;
uintptr_t pc = (uintptr_t)first;
uintptr_t *pcptr = &pc;
void
done(void)
{
printf("done\n");
stopped = true;
}
void
second(void)
{
printf("second\n");
*pcptr = (uintptr_t)done;
}
void
first(void)
{
printf("first\n");
*pcptr = (uintptr_t)second;
}
void
run(void)
{
do {
((fnptr)*pcptr)();
} while (!stopped);
}
int
main(void)
{
run();
return 0;
}
term% gcc-16 -std=c11 -pedantic -o b b.c
term% ./b
first
second
done
term%
```
BTW what name would be given to such a function pointer type?
I have no idea what your code is supposed to do,
It's a table of function pointers! All sharing the same signature.
That's pretty generic. Is it really that hard to guess? You don't need
to know what they do, other than at some point they will be called as
handlertable[i](arg).
That part is fine.
What's utterly mystifying is what you are trying to show, if
anything, by posting it. Is this supposed to prove some kind of
point? Your code is not _a priori_ easier to understand than
the equivalent C code; if anything, it is harder to understand
because of your poorly chosen names.
- Dan C.
Rust implementation of Timers, mentioned above<--
As mentioned above, if I were providing the FreeRTOS timers API
in an alternative language, I'd write it differently from the
start. In particular, I'd use an enumeration to describe the
behavior with respect to repeating, and I'd use a closure to
obviate the need for the opaque id. Something that isn't easy
to express in the original API is a type of repeating timer that
waits for the initial period, and then repeats with some
different period.
Something like this:
```rust
pub mod timer {
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
/// Errors that may occur when working with timers.
#[derive(Clone, Copy, Debug)]
pub enum Error {
Running,
CantStop,
WontStop,
}
/// Describes the kind of a timer, as defined by its
/// periodicity.
///
/// A timer can either be a `OneShot` timer, which fires
/// once, after its timeout expires, or it may be a Repeating
/// timer, which will automatically reset after its handler
/// is run and continue firing at the rate defined by the
/// initial timeout, or it can be a periodic timer, that
/// will fire the first time at the initial timeout, and
/// then repeatedly a potentially different timeout. This
/// use case can be simulated by a OneShot timer that
/// creates a repeating Timer, but
///
/// Once started, Repeating and Periodic timers continue
/// firing until explicitly stopped.
#[derive(Clone, Copy, Debug)]
pub enum Kind {
OneShot,
Repeating,
Periodic(Duration),
}
/// A named timer, that is handled by the given callback.
pub struct Timer<'a, F> {
pub name: &'a str,
pub kind: Kind,
pub timeout: Duration,
callback: F,
running: AtomicBool,
// Whatever other innards...
// ...
}
/// A read-only "view" into the timer.
pub trait TimerView {
fn name(&self) -> &str;
fn kind(&self) -> Kind;
fn timeout(&self) -> Duration;
}
impl<'a, F: Fn(&dyn TimerView)> Timer<'a, F> {
/// Creates a new named timer of the given kind with an
/// initial timeout. When the timeout expires, it will
/// automatically invoke the given handler.
pub fn new(
name: &'a str,
timeout: Duration,
kind: Kind,
callback: F,
) -> Timer<'a, F> {
let running = AtomicBool::new(false);
Self {
name,
kind,
callback,
timeout,
running,
}
}
/// Starts the timer.
pub fn start(&self) -> Result<(), Error> {
if self.running.swap(true, Ordering::AcqRel) {
return Err(Error::Running);
}
self.arm(self.timeout)?;
Ok(())
}
/// Stops the timer.
///
/// Note that this inherently races with the timer firing,
/// and a timer event that occurs while we are disabling
/// the timer may still invoke `fired` after this returns.
///
/// Callers are advised to determine definitively that
/// there are no events pending for this timer before
/// destroying the `Timer` object.
pub fn stop(&self) -> Result<(), Error> {
let was_running = self.running.swap(false, Ordering::AcqRel);
if !was_running {
return Err(Error::WontStop);
}
self.disarm();
Ok(())
}
// Automatically called when the timeout fires.
//
// # Safety
//
// Nothing may be mutably borrowing a reference to the
// Timer object when this is called.
pub(super) unsafe fn fired(&self) -> Result<(), Error> {
if !self.running.load(Ordering::Acquire) {
return Ok(());
}
(self.callback)(self);
match self.kind {
Kind::OneShot => Ok(()),
Kind::Repeating => self.arm(self.timeout),
Kind::Periodic(period) => self.arm(period),
}
}
// Arranges for `self.fired(self)` to be called when
// the given timeout expires.
fn arm(&self, timeout: Duration) -> Result<(), Error> {
// Does whatever one does here to actually arm the
// timer (e.g., calls a HAL to actually program a
// physical timer to interrupt after the amount of
// time specified by `Duration`, for example).
// ...
Ok(())
}
// Disables an armed timer, so that it does not fire
// after this returns.
fn disarm(&self) -> Result<(), Error> {
// whatever one does here to disarm an active timer
// ...
Ok(())
}
}
impl<F> TimerView for Timer<'_, F> {
fn name(&self) -> &str { self.name }
fn kind(&self) -> Kind { self.kind }
fn timeout(&self) -> Duration { self.timeout }
}
}
```
One might use this with something like,
```
let value = 42;
let cb = move |timer: &dyn timer::TimerView| {
println!(
"Timer '{}' fired; value is {} and duration was {} ms",
timer.name(),
value,
timer.timeout().as_millis()
);
};
let timeout = std::time::Duration::from_millis(100);
let timer = timer::Timer::new("timer", timeout, timer::Kind::OneShot, &cb);
timer.start().expect("Timer started");
//... at some point the timer fires and prints,
// 'Timer 'timer1' fired; value is 42 and duration was 100 ms'
}
```
On 21/10/2026 12:21, David Brown wrote:
On 21/10/2026 03:04, bart wrote:
Where does the info come from anyway; does the library export a
suitable typedef? In that case you might as well use it. But if not,
info must come from elsewhere.
Of course it "exports" the typedef - it is in one of the library's
headers.
You could have said that in the first place. So it's not really a choice then is it?
Then it makes sense to use what they have provided.
On 20/10/2026 22:44, Dan Cross wrote:
In article <11b8j17$3btus$[email protected]>, bart <[email protected]> wrote: >>> On 20/10/2026 20:24, Dan Cross wrote:
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]>
wrote:
The point is that the name you chose is meaningless to anyone
other than you. What's a PCL? Phase Control Line? Printer
Command Language? Photon Compressor Loop?
Within the context of that application then it would be clear. You're
just being overly hostile.
Not really. You are, I presume, posting that code to try and
make some kind of point about how "readable" it is. But it's
not readable unless you already know what it does.
What it does not relevant. This is simply defining an array of T. But because T happens to be a function pointer, DB insists that an alias
must be created, and a new name invented.
Why? Probably because in C, the syntax for function pointers gets hairy.
On the other hand, the code David posted _is_ readable, because
it uses the language to encode domain-specific information into
type names.
Maybe we should create aliases for function signatures more often then,
then we can encode that extra info.
So that instead of, for example:
void SomeFunc(int x, int y) {printf("%d %d\n", x, y);}
you do:
typedef void Take2Ints(int x, int y);
Take2Ints SomeFunc {printf("%d %d\n", x, y);}
If you have a suite of functions sharing the signature, then it might be
a good idea. But funnily enough, you never see this being done.
(I don't know if this is legal C; but it works fine with my compiler:
c:\m>type fred.c
#include <stdio.h>
typedef void Take2Ints(int x, int y);
Take2Ints SomeFunc{printf("%d %d\n", x, y);}
int main(void) { SomeFunc(10, 20); }
c:\m>bcc -r -q fred
10 20
)
Yeah, you really just don't get it.One of us doesn't get it.
On 20/10/2026 21:24, Dan Cross wrote:
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote:
[snip]
(There was a LOT of antipathy towards my idea to fix the common case of
'loop-break' clashing with 'switch-break', BECAUSE it did not fix the
problem of nested loop-break, which is uncommon, even though that wasn't >>> the aim.)
Those are two different things. No one disagrees with you that
"nested break from a switch inside of a loop" is relatively more
common than other variants.
Quibble - that is not established to my satisfaction. I am not
convinced that wanting a nested break for "switch inside loop" is more >common than wanting it for "loop inside loop". So I neither agree nor >disagree with that claim. I don't, however, think it matters much -
both are situations that turn up sometimes in code, and definitive
answers are neither possible nor useful.
[snip]
There are plenty of languages that can do this kind of thing
that are not C and have syntax and semantics closer to what you
seem to want. Here's an example in Rust:
pub trait TimerHandle { ... }
fn CreateTimer<T>(
timer_name: &str,
period: std::time::Duration,
auto_reload: bool,
timer_id: T,
handler: fn(&dyn TimerHandle),
) -> Result<Timer<T>, TimerError>
I didn't know what an `UBaseType_t` is, and while "autoreload"
sounded pretty intuitive, I wasn't sure about the semantics, so
I looked it up (the example comes from `FreeRTOS`). In this
context, it is a boolean saying whether the timer should repeat
with the given periodicity, or whether it is a one-shot.
FreeRTOS is written in C90 - a mistake, IMHO - and thus does not use
bool. Instead, it uses constants pdTRUE and pdFALSE of type
UBaseType_t. UBaseType_t is a type that is dependent on the target - >usually it is either 16-bit or 32-bit. But of course it doesn't matter
what the underlying types are - you use the typedef names, and the >documented constants.
The timer_id is opaque to the timer, and it looks like it's used
to facilitating the handler accessing timer-specific data. In
C, passing it as a `void *` is used as a way to get a poor-man's
overloading. But Rust has generics, I just made it generic over
some type T.
FreeRTOS uses "void *" to mean "pointer to internal structure that you >shouldn't be messing with". It uses this far too often, and is, IMHO, a >poor design choice. (I also dislike the silly Hungarian naming.) I
would much preferred if there had been :
struct Internal_Timer_Struct;
typedef struct Internal_Timer_Struct * timer_id_t;
and then the parameter "timer_id_t timer_id". So in a re-write, it
would not be a generic. (You might choose to use a generic for the
handler function type, so that handler callbacks could have parameters
of other types, but not for the timer id.)
I am using these declarations from FreeRTOS (and LWIP) to demonstrate
the use of function typedefs in massively popular codebases, not to
claim FreeRTOS is a paradigm of C code design!
For example:
[snip]
Note this is decently complex behavior, but it's actually quite
intuitive from the name and the type.
You have got a very clear picture here, much of it from the names of the >types. For a Rust programmer, you give a good impression of experience
with C :-)
The only mistake you made is that programmers working on systems using >FreeRTOS and the like, have a fear and loathing of "malloc", have never >heard of "abort()", and do not join our threads because they all run
until the power is switched off.
[snip]
Or just have :
fnptr pc = first;
fnptr *pcptr = &pc;
I don't see a need for "uintptr_t", except so that you have to have
casts like Bart had.
[Snip a bunch of Rust code; the point of which being that
bart need not complain about lack of an alternative to C]
David Brown <[email protected]> writes:
On 19/10/2026 23:27, Janis Papanagnou wrote:[...]
* a b PN (Polish Notation)
There is no term "Polish Notation" - except as occasionally used to
mean /postfix/ as a short form of "Reverse Polish Notation". RPN was
invented, or at least popularised, by the Polish logician Jan
Łukasiewicz (I admit to looking that up on Wikipedia!). There is no
"PN" opposite.
Yes, there most certainly is, and "* a b" is a good example of it.
https://en.wikipedia.org/wiki/Polish_notation
Jan Łukasiewicz invented what we now call Polish notation in 1924.
`+ 3 4` is an example (which yields 7). Lisp syntax is more or
less Polish notation with added parentheses. (I'm sure the phrase
"more or less" is doing a lot of work.)
Reverse Polish Notation, RPN, is very well known because it's
used by some calculators, particularly those made by HP. It's a
postfix notation. An example of RPN is `3 4 +` (which also yields 7).
I've never seen the term "Polish Notation", without "Reverse", used
to refer to postfix notation. PN is prefix; RPN is postfix.
I see that Janis already pointed out your error. I'm disappointed
that your followup did not acknowledge it. (I'm not commenting on the
rest of what Janis wrote.)
On 21/10/2026 10:20, David Brown wrote:
On 20/10/2026 22:07, bart wrote:
On 20/10/2026 16:02, David Brown wrote:
On 20/10/2026 16:11, bart wrote:
* A further complication was to allow function pointers within that a >>>>> declaration list
To me, the big disadvantage of C's declaration syntax is that it
lets you declare things of different (but related) types in the same
declaration.
Yes, but that doesn't bite so much because it is uncommon.
Unfortunately not - but it is uncommon to mix objects and function
declarations, or objects of wildly different real types.
That's what I meant.
const int const * const p;
1 2 3
const 1 applies to the basetype to its right.
const 2 applies to the basetype to its left.
These are redundant - they do the same thing. (I'd have preferred if
the ordering rules were strict - allowing only "const int" or "int
const" - but at least people are usually consistent in their style.)
(Both also can be in the middle with compound types like 'long long'!)
const 3 is tricky: I think it applies to the * to its left, since it
says that the pointer value itself is const. But 'p' has type
'pointer to', so it could apply to that directly.
Yes - it is "p" that is const, not the "*".
I would disagree. This type can also be written as:
(const int const * const)
There is no 'p' to apply to. The type describes a pointer to an integer.
The first two consts say, redundantly, that the integer value is const.
The third must then apply to the pointer.
What about this however:
int * const * p;
1 2 3
I think here, const 2 applies to * 1, which is to it's left, and
can't apply to 'p' as that is the other side of the * 3.
*p is of type "int * const" - thus you can use "*p" to access a
pointer- to-int, but you can't use *p to change that pointer-to-int.
But what exactly does this 'const' apply to?
I'm suggesting any 'const' applies either to the base type (the one on
the left) or to a particular '*'.
In that case the latter 'const's must apply right-to-left to the
preceding '*'.
Fair to say that is a complete mess, and it is error prone.
No, it is not at all fair to say that. It is fair to say that a
different way of writing types might make it easier to understand -
but that's a /long/ way from saying it is "a complete mess". And you
can't call it "error prone" unless you know that people regularly use
such declarations, and often have bugs in their code as a result of
doing so incorrectly. I think that is an unrealistic claim.
If there's any confusion about which const applies to which type
element, then mistakes can be made.
You can write this in C++ :
// This bit is only needed once
template <typename T> using ptr = T *;
// p is a pointer to a const pointer to an int
ptr<const ptr<int>> p;
That's LTR syntax. Sure, it also has < > parentheses, but that's a
minor point since the ordering of the components is what apparently
matters so much.
That it is LTR is now irrelevant because I find that incomprehensible anyway. You've turned a linear chain a nested structure ... oh never
mind, I don't even want to go there with C++.
Or you can write :
typedef int * p_int;
const p_int * p;
Thus p is a pointer to a "const p_int", where a "p_int" is a pointer
to an int.
So, a common pattern with you is to use workarounds so that you
effectively emulate LTR type patterns. Because they are easier to work
with and understand.
So you do appreciate how they facilitate things, even though they
introduce an extra level of indirection and also disseminate the type information across the program.
But you want to underplay how useful it would be to have natural LTR
type declarations within a syntax.
These are different ways to write the same type, including one that is
LTR, and the main hinder to understanding remains the same - what is
the type for?
If you create a type alias voluntarily (I don't mean structs where
either a tag or a typedef needs to be created) then yes the name should impart something useful.
But in my view this is often taken too far. Sometimes you have structs
where every member has a different user-type. When you look further, you find they are all ints. That is just obfuscation.
(I would accept enumeration types if the compiler can employ that info
to improve type safety, but that seems to be limited.)
I've showed even simple types or trying to use 'const' get becomes
confusing.
No, you haven't.
OK. That is not surprising.
It would make a HUGE difference:
Your points below are all true, but IMHO all very minor, and do not
add up to anything much.
It would eliminate half the issues with C's type syntax. Probably CDECL wouldn't need to exist. Lots of () disappear. It would make pointers-to- arrays more viable.
But that's nothing in your view. OK again.
Your invented confusion.
That doesn't matter in practice.
I don't see that as significant.
I do agree that the decay of expressions using array types into
pointer types is a source of error in C code - though I do not think
it is as bad as you do.
I didn't say anything about, and that wouldn't be affected.
But I just don't see pointer-to-array expressions to be common enough
for the difference you describe to be important.
If you're passing arrays to a function by-reference then the natural way
is to a have a pointer to the array. C can do that, but nobody ever does
so, probably because indexing is then so ugly.
With my idea, (*A)[i] turns into A*[i], a bit less ugly.
(4) For pointers to structs, these are the patterns:
prefix * With -> With postfix *
(*P).m P->m P*.m
(**P).m (*P)->m P**.m
(***P).m (**P)->m P***.m
Which column looks the tidiest?
Far and away the most common - by orders of magnitude - are pointers
to structs. "p->m" looks fine to me, and I prefer it to "p*.m".
But where's the consistency? Sometimes "." is used for member selection,
and sometimes "->". And with two pointer levels, you need both!
(6) Your 'int * a, b' example would become:
int a *, b;
Much easier, even with that space, to see that '*' does not belong to
the base type but is a modifier for that variable.
It's still bad. I don't think finding a way to make it easier to
write bad code is a good idea.
It wouldn't stay bad for long! Because if the intention was to declare
two pointers, then it's easier to see that this is wrong.
So basically, the suggestion would change some very minor things -
mostly in subjective ways - and not actually do anything for aspects
of the language where there is more of a consensus that C is sub-
optimal. And for this, you would want a fundamental change to one of
the most used operators in all C code!
Obviously you can't change prefix * now. A postfix /alternative/, in addition to prefix *, could have been introduced decades ago. So by the
time /you/ encountered C, you might have been using the latter.
On 21/10/2026 03:04, bart wrote:
Here, one problem is that there are 3 types that I don't know and
would have to look up.
Incorrect.
That signed char return is unusual; why not 'int'? (How would you even
print an 'err_t' value anyway)?
It seems that yet again, you need an explanation of fundamental points
of software development. Today's lesson is on "abstraction".
Maybe on some targets (of this portable library), err_t is "signed
char".
It is also nice to know that it can be used in a switch, and cast to an
int for printf.
Or look at the "ip_addr_t" type. It happens, at the moment, to be a struct. But it might have been a union. The size and contents of the struct depend on details of how the library is built - whether it has support for ipv4, ipv6, or both. Maybe a future version will also
support ipv8, or ipv5 (I've heard some people are trying to make an IP protocol that covers more than IPv4, but without most of the
complicating additional features of IPv6). It is an abstract type - you use it without knowing the details.
Lawrence D’Oliveiro pisze:
t to end each case-sequence in a switch statement with
a break-statement: put the break at the same indentation level as the
case-clause as well as the switch-expression. That way, you can scan
your eye down a single line f
some time ago i was saying what the proper switch should like
(imo, but im not sure if my conclusions are anough to take is a s proven)
case {} case {} case {} otherwise {}
its indeed sorta needed becouse case in fact are ifs
(not if-elses) (so some in fact could write
if {} if {} if {} otherwise {}
its the same)
the problem is you got no group alse
and here this otherwise need to check all ifs
"or" them and use group else for them
this could be written in few ways, but my case case case otherwise names it could also do
if {} or if {} or if {} else {}
so either you need logic operators here or predefined constructs like otherwise (maybe both)
and that should be included not switch wchich is bad imo
other way is to define distionary more as data construct
dict {
'mental' {/* 1 */}
'reductionists' {/* 2 */}
'suck' {/* 3 */}
}
then you could use
dict('reductionists')
to yeld to /* 2 */
this second one parallels to switch keyword
so c switch mixes them both in bad way..they should be spitet and
upbuild as showed ;c
thats my conclusion as switch topic as far by now ;c
In article <11baah2$3te3v$[email protected]>,
David Brown <[email protected]> wrote:
On 20/10/2026 21:24, Dan Cross wrote:
In article <11b7k22$2v8e5$[email protected]>, bart <[email protected]> wrote: >>>> [snip]
(There was a LOT of antipathy towards my idea to fix the common case of >>>> 'loop-break' clashing with 'switch-break', BECAUSE it did not fix the
problem of nested loop-break, which is uncommon, even though that wasn't >>>> the aim.)
Those are two different things. No one disagrees with you that
"nested break from a switch inside of a loop" is relatively more
common than other variants.
Quibble - that is not established to my satisfaction. I am not
convinced that wanting a nested break for "switch inside loop" is more
common than wanting it for "loop inside loop". So I neither agree nor
disagree with that claim. I don't, however, think it matters much -
both are situations that turn up sometimes in code, and definitive
answers are neither possible nor useful.
Ok, that's fair; I shouldn't say "no one disagrees".
[snip]
There are plenty of languages that can do this kind of thing
that are not C and have syntax and semantics closer to what you
seem to want. Here's an example in Rust:
pub trait TimerHandle { ... }
fn CreateTimer<T>(
timer_name: &str,
period: std::time::Duration,
auto_reload: bool,
timer_id: T,
handler: fn(&dyn TimerHandle),
) -> Result<Timer<T>, TimerError>
I didn't know what an `UBaseType_t` is, and while "autoreload"
sounded pretty intuitive, I wasn't sure about the semantics, so
I looked it up (the example comes from `FreeRTOS`). In this
context, it is a boolean saying whether the timer should repeat
with the given periodicity, or whether it is a one-shot.
FreeRTOS is written in C90 - a mistake, IMHO - and thus does not use
bool. Instead, it uses constants pdTRUE and pdFALSE of type
UBaseType_t. UBaseType_t is a type that is dependent on the target -
usually it is either 16-bit or 32-bit. But of course it doesn't matter
what the underlying types are - you use the typedef names, and the
documented constants.
Thanks for the context. Your point that the underlying type
doesn't matter is salient: it's opaque to the programmer, but
99% of the time the programmer doesn't need to worry about the
details.
The timer_id is opaque to the timer, and it looks like it's used
to facilitating the handler accessing timer-specific data. In
C, passing it as a `void *` is used as a way to get a poor-man's
overloading. But Rust has generics, I just made it generic over
some type T.
FreeRTOS uses "void *" to mean "pointer to internal structure that you
shouldn't be messing with". It uses this far too often, and is, IMHO, a
poor design choice. (I also dislike the silly Hungarian naming.) I
would much preferred if there had been :
struct Internal_Timer_Struct;
typedef struct Internal_Timer_Struct * timer_id_t;
and then the parameter "timer_id_t timer_id". So in a re-write, it
would not be a generic. (You might choose to use a generic for the
handler function type, so that handler callbacks could have parameters
of other types, but not for the timer id.)
I am using these declarations from FreeRTOS (and LWIP) to demonstrate
the use of function typedefs in massively popular codebases, not to
claim FreeRTOS is a paradigm of C code design!
Oh interesting; in this case, I had assumed it was treated as
a callback-specific type so one could plumb extra context into
the handler; the documentation I saw suggested it could be used
by the handler to disambiguate several timers reusing the same
handler function.
For example:
[snip]
Note this is decently complex behavior, but it's actually quite
intuitive from the name and the type.
You have got a very clear picture here, much of it from the names of the
types. For a Rust programmer, you give a good impression of experience
with C :-)
I've been known to dabble.
The only mistake you made is that programmers working on systems using
FreeRTOS and the like, have a fear and loathing of "malloc", have never
heard of "abort()", and do not join our threads because they all run
until the power is switched off.
Ha, fair; that was just a made-up example, based on other thread
libraries I have used (in C). I didn't mean for it to be
interpreted strictly in the context of FreeRTOS! :-D
[snip]
Or just have :
fnptr pc = first;
fnptr *pcptr = &pc;
I don't see a need for "uintptr_t", except so that you have to have
casts like Bart had.
Yes. But I wanted to remain faithful to his original, to show
that one could write a more-or-less exact transliteration in C
that was extremely similar to his chosen syntax.
[Snip a bunch of Rust code; the point of which being that
bart need not complain about lack of an alternative to C]
On 21/10/2026 12:21, David Brown wrote:
On 21/10/2026 03:04, bart wrote:
Here, one problem is that there are 3 types that I don't know and
would have to look up.
Incorrect.
If I wanted to use function from a language that is not C and for which nobody has yet created a set of bindings, then I would have to
investigate every single abstract type.
Even then, I might find that a year later, 'err_t' has been defined to
be something slightly different. Standard types are easier to deal with
and more likely to be stable.
On 21/10/2026 12:21, David Brown wrote:
On 21/10/2026 03:04, bart wrote:
Here, one problem is that there are 3 types that I don't know and
would have to look up.
Incorrect.
If I wanted to use function from a language that is not C and for which >nobody has yet created a set of bindings, then I would have to
investigate every single abstract type.
Even then, I might find that a year later, 'err_t' has been defined to
be something slightly different. Standard types are easier to deal with
and more likely to be stable.
That signed char return is unusual; why not 'int'? (How would you even
print an 'err_t' value anyway)?
It seems that yet again, you need an explanation of fundamental points
of software development. Today's lesson is on "abstraction".
OK. I've just looked at several graphics libraries. Those have chosen to
use predominantly standard C types for function return values. And
standard C types for numeric arguments.
Sometimes they might be prefixed, eg. GL_int, SDL_bool, probably as >abstraction from the vagaries of standard C.
It seems a trend to invent pointless extra types for everything. In C >itself, there are about 35 denotations for integer types, and that's
before you get into clock_t, time_t, offset_t and everything else.
In general most boil down to one of i32 u32 i64 u64.
So you can go over the top with abstraction.
Maybe on some targets (of this portable library), err_t is "signed
char".
Why not define it on top of 'int'? Is it likely that large numbers of
error codes are going to be stored within structs and arrays so that the >size must be minimal?
It is also nice to know that it can be used in a switch, and cast to an
int for printf.
How would you know that? I thought it was abstract! Maybe err_t is a
small struct.
Or look at the "ip_addr_t" type. It happens, at the moment, to be a
struct. But it might have been a union. The size and contents of the
struct depend on details of how the library is built - whether it has
support for ipv4, ipv6, or both. Maybe a future version will also
support ipv8, or ipv5 (I've heard some people are trying to make an IP
protocol that covers more than IPv4, but without most of the
complicating additional features of IPv6). It is an abstract type - you >> use it without knowing the details.
I haven't said much about that. It is a struct so some username is
needed. I renamed it to IP_addr in my example.
But I'm not sure it needs the _t suffix. (Is it a thing now for every >typedef name to need _t?)
I notice however that the argument is a pointer: if ip_addr_t* values
are commonly passed around, I would put an abstraction around that.
(However that's partly because how my language works is different; to
access a member of the struct, I don't need to know if the type of X is
an actual struct or is a pointer to one; I write X.addr in both cases.)
In article <11baiuc$11ac$[email protected]>, bart <[email protected]> wrote:
On 21/10/2026 12:21, David Brown wrote:
On 21/10/2026 03:04, bart wrote:
Here, one problem is that there are 3 types that I don't know and
would have to look up.
Incorrect.
If I wanted to use function from a language that is not C and for which
nobody has yet created a set of bindings, then I would have to
investigate every single abstract type.
That is true of every programming language.
Even then, I might find that a year later, 'err_t' has been defined to
be something slightly different. Standard types are easier to deal with
and more likely to be stable.
That is also true of every programming language.
You can write some library in BartM or whatever language you
like, and someone might write a binding to call it from, say,
Pascal; and then a year down the road, you might change your
compiler (since I gather you don't bother with a well-defined
ABI, based on your not seeming to understand them
Welcome to programming. It's Hard(TM).
In general most boil down to one of i32 u32 i64 u64.
Judicious use of types can render entire categories of errors
unexpressible. Alexis King wrote a wonderful post about this,
expressed using Haskell, but the general principles apply more
broadly.
It is also nice to know that it can be used in a switch, and cast to an
int for printf.
How would you know that? I thought it was abstract! Maybe err_t is a
small struct.
Because the documentation about it tells you that you can: "The
type `err_t` is used to represent errors. It can be cast to
`int`." Really, this is table-stakes software development.
On 21/10/2026 16:37, Dan Cross wrote:
You can write some library in BartM or whatever language you
like, and someone might write a binding to call it from, say,
Pascal; and then a year down the road, you might change your
compiler (since I gather you don't bother with a well-defined
ABI, based on your not seeming to understand
You still don't get what an ABI is.
bart <[email protected]> writes:
On 21/10/2026 16:37, Dan Cross wrote:
You can write some library in BartM or whatever language you
like, and someone might write a binding to call it from, say,
Pascal; and then a year down the road, you might change your
compiler (since I gather you don't bother with a well-defined
ABI, based on your not seeming to understand
You still don't get what an ABI is.
Please, enlighten us. Be specific. What exactly
does the term ABI mean to you?
On 21/10/2026 18:21, Scott Lurndal wrote:
bart <[email protected]> writes:
On 21/10/2026 16:37, Dan Cross wrote:
You can write some library in BartM or whatever language you
like, and someone might write a binding to call it from, say,
Pascal; and then a year down the road, you might change your
compiler (since I gather you don't bother with a well-defined
ABI, based on your not seeming to understand
You still don't get what an ABI is.
Please, enlighten us. Be specific. What exactly
does the term ABI mean to you?
It's what I have to deal with in a compiler back-end if I want to
support an FFI in a language.
It's not the same problem as using that FFI to write a set of bindings >corresponding with a particular API.
The latter problem needs to be solved even if there was no back-end and
no ABI to deal with (eg. transpiling to another language, or lowering to >some VM).
I don't why I'm bothering, since somebody will find another stick to
beat me over the head with or to somehow try to catch me out, but here
is an example of a function inside MSVCRT.DLL..
In the C API (ie. stdio.h) it will be expressed like this:
int puts(const char*);
In my FFI and in my syntax, it is expressed like this:
func puts (ichar)i32
So, this is 'creating a binding'. This can be done manually for this
one-off example. It's not perfect: on my platform, the C parameter has
'ref i8' type, but mine is more like 'ref u8'.
At this point, the ABI doesn't come into it.
That becomes relevant within the backend for a particular target and >platform.
So for this call:
puts(s)
the ABI for x64 running Windows will tell me that 's' must be passed in
rcx, the stack needs a shadow space, it needs to be 16-byte aligned, and
the 32-bit result is placed in eax.
For ARM64 running Linux (SYS V), then 's' is passed in x0, and the
result placed in w0. The stack will always properly aligned.
The only overlap in API/ABI may be to do with details of how structs may
be laid out in memory. But generally, C APIs will just follow the C
rules; I don't consider it an ABI thing. It would be something to deal
with even if no ABI existed and no native code was generated.
For my purposes, ABI is about calling conventions. ABI references may
cover a lot more (eg. for SYS V which likes to make everything as >complicated as possible).
So, now tell me what I've got wrong.
On 21/10/2026 15:22, Dan Cross wrote:
[snip]
Actually, I have mixed these up, and you are correct - the void* id is >user-assigned, and you use it as you wish. There are other places in >FreeRTOS where pointer types get "erased" and reduced to void* >unnecessarily, but this was not one of them. (In my poor defence, the >FreeRTOS code I have doesn't use timers, and the bits it does use -
threads and queues, mainly - is abstracted to a C++ interface.)
It was interesting to see the Rust code, but it made one thing clear to
me - Rust should be used for writing Rust code, and not for writing C
code in Rust syntax.
[snip]
You still don't get what an ABI is.
On 21/10/2026 18:21, Scott Lurndal wrote:
bart <[email protected]> writes:
On 21/10/2026 16:37, Dan Cross wrote:
You can write some library in BartM or whatever language you
like, and someone might write a binding to call it from, say,
Pascal; and then a year down the road, you might change your
compiler (since I gather you don't bother with a well-defined
ABI, based on your not seeming to understand
You still don't get what an ABI is.
Please, enlighten us. Be specific. What exactly
does the term ABI mean to you?
It's what I have to deal with in a compiler back-end if I want to
support an FFI in a language.
In article <11baur1$63id$[email protected]>, bart <[email protected]> wrote:And Wow, your reply is exactly the kind I expected!
So, now tell me what I've got wrong.
Wow. You really, truly, have no idea how any of this works. I
don't even know where to begin. You just throw around words but
have no idea what they mean in context.
It's breathtaking, really.
bart <[email protected]> writes:
On 21/10/2026 18:21, Scott Lurndal wrote:
bart <[email protected]> writes:
On 21/10/2026 16:37, Dan Cross wrote:
You can write some library in BartM or whatever language you
like, and someone might write a binding to call it from, say,
Pascal; and then a year down the road, you might change your
compiler (since I gather you don't bother with a well-defined
ABI, based on your not seeming to understand
You still don't get what an ABI is.
Please, enlighten us. Be specific. What exactly
does the term ABI mean to you?
It's what I have to deal with in a compiler back-end if I want to
support an FFI in a language.
Ah, so you don't know what an ABI is.
An Application Binary Interface (ABI) is a
low-level contract in computer science that
defines how two compiled binary program modules
interact with each other at the machine-code level.
If you want your compiler to leverage existing libraries
and/or code written in another language, you need to follow
the platform ABI. It is that simple.
Whether you like it or not, is completely irrelevent.
The stack pointer alignment requirement should be obvious.
On 21/10/2026 19:38, Dan Cross wrote:
In article <11baur1$63id$[email protected]>, bart <[email protected]> wrote:
So, now tell me what I've got wrong.
Wow. You really, truly, have no idea how any of this works. I
don't even know where to begin. You just throw around words but
have no idea what they mean in context.
It's breathtaking, really.
And Wow, your reply is exactly the kind I expected!
Of course, you're not going to tell me what API means versus ABI, and
you're not going to answer my question about what I've got wrong.
Because actually you don't know.
This was apparent from things you've said in the past.
I have actually wondered what you're doing here, and this appears to be
it: being hostile, patronising, condescending and constantly taking the >contrary view no matter what.
In other words, being a troll.
In article <11bb47i$889c$[email protected]>, bart <[email protected]> wrote:
On 21/10/2026 19:38, Dan Cross wrote:
In article <11baur1$63id$[email protected]>, bart <[email protected]> wrote:
So, now tell me what I've got wrong.
Wow. You really, truly, have no idea how any of this works. I
don't even know where to begin. You just throw around words but
have no idea what they mean in context.
It's breathtaking, really.
And Wow, your reply is exactly the kind I expected!
Of course, you're not going to tell me what API means versus ABI, and
you're not going to answer my question about what I've got wrong.
Honestly? No, I'm not. It's clear that if I tried, you would
either not understand, or deliberately ignore it so you could
blindly continue in your self-imposed ignorance.
Because actually you don't know.
Umm.....
This was apparent from things you've said in the past.
You know, it's one thing to be ignorant yourself. It's quite
another to project that onto others.
I have actually wondered what you're doing here, and this appears to be
it: being hostile, patronising, condescending and constantly taking the
contrary view no matter what.
In other words, being a troll.
It's apparent that you really, truly, do not understand why so
many others seem like they are "having a go" at you. I actually
feel kind of bad for you.
On 21/10/2026 21:36, Dan Cross wrote:
In article <11bb47i$889c$[email protected]>, bart <[email protected]> wrote:
On 21/10/2026 19:38, Dan Cross wrote:
In article <11baur1$63id$[email protected]>, bart <[email protected]> wrote: >>>
So, now tell me what I've got wrong.
Wow. You really, truly, have no idea how any of this works. I
don't even know where to begin. You just throw around words but
have no idea what they mean in context.
It's breathtaking, really.
And Wow, your reply is exactly the kind I expected!
Of course, you're not going to tell me what API means versus ABI, and
you're not going to answer my question about what I've got wrong.
Honestly? No, I'm not. It's clear that if I tried, you would
either not understand, or deliberately ignore it so you could
blindly continue in your self-imposed ignorance.
Because actually you don't know.
Umm.....
This was apparent from things you've said in the past.
You know, it's one thing to be ignorant yourself. It's quite
another to project that onto others.
I've seen zero evidence that you know anything about the matter. Just >bluster.
Just start using the switch statement. It's useful in very very very
many cases.
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
fir wrote:
Lawrence D’Oliveiro pisze:Just start using the switch statement. It's useful in very very very
t to end each case-sequence in a switch statement with
a break-statement: put the break at the same indentation level as the
case-clause as well as the switch-expression. That way, you can scan
your eye down a single line f
some time ago i was saying what the proper switch should like
(imo, but im not sure if my conclusions are anough to take is a s proven)
case {} case {} case {} otherwise {}
its indeed sorta needed becouse case in fact are ifs
(not if-elses) (so some in fact could write
if {} if {} if {} otherwise {}
its the same)
the problem is you got no group alse
and here this otherwise need to check all ifs
"or" them and use group else for them
this could be written in few ways, but my case case case otherwise
names it
could also do
if {} or if {} or if {} else {}
so either you need logic operators here or predefined constructs like
otherwise (maybe both)
and that should be included not switch wchich is bad imo
other way is to define distionary more as data construct
dict {
'mental' {/* 1 */}
'reductionists' {/* 2 */}
'suck' {/* 3 */}
}
then you could use
dict('reductionists')
to yeld to /* 2 */
this second one parallels to switch keyword
so c switch mixes them both in bad way..they should be spitet and
upbuild as showed ;c
thats my conclusion as switch topic as far by now ;c
many cases. You'll get the hang of it right away. Next, it doesn't just
test variable type 'int', also notably 'char', among others.
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to most
code that is used in connection with FreeRTOS, or LWIP. (Of course
there will be some overlap - bits of code that are intended to run on a >microcontroller but tested with code running native on a PC.)
I don't know if the "_t" convention for type identifiers started with
POSIX, but it has certainly far outgrown POSIX. And I think the smart
folks behind POSIX know this, and will not assume that just because they >pick a new type name ending in _t, it will not conflict with some user
code. As C doesn't have namespaces, there is always a risk of
conflicting names - you just have to try to avoid clashes in things you
are likely to see.
On 21/10/2026 21:36, Dan Cross wrote:
In article <11bb47i$889c$[email protected]>, bart <[email protected]> wrote:
On 21/10/2026 19:38, Dan Cross wrote:
In article <11baur1$63id$[email protected]>, bart <[email protected]> wrote: >>>
So, now tell me what I've got wrong.
Wow. You really, truly, have no idea how any of this works. I
don't even know where to begin. You just throw around words but
have no idea what they mean in context.
It's breathtaking, really.
And Wow, your reply is exactly the kind I expected!
Of course, you're not going to tell me what API means versus ABI, and
you're not going to answer my question about what I've got wrong.
Honestly? No, I'm not. It's clear that if I tried, you would
either not understand, or deliberately ignore it so you could
blindly continue in your self-imposed ignorance.
Because actually you don't know.
Umm.....
This was apparent from things you've said in the past.
You know, it's one thing to be ignorant yourself. It's quite
another to project that onto others.
I've seen zero evidence that you know anything about the matter. Just bluster.
I have actually wondered what you're doing here, and this appears to be
it: being hostile, patronising, condescending and constantly taking the
contrary view no matter what.
In other words, being a troll.
It's apparent that you really, truly, do not understand why so
many others seem like they are "having a go" at you. I actually
feel kind of bad for you.
If you don't know this stuff, that would be perfectly fine, not everyone
is into compilers.
But refusing to admit that you mixed up API/ABI and instead gaslighting others into thinking they're the ones in the wrong is unacceptable and childish.
I've looked at the 40 or so posts you've made in the last few days, half
of them were replies to me, all unpleasant exchanges.
This is just persecution, constantly attacking and belittling at the personal level. Maybe you're some sick fuck and and you get a kick out
of it, then you should get help together with JP, that other wonderful person.
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to most
code that is used in connection with FreeRTOS, or LWIP. (Of course
there will be some overlap - bits of code that are intended to run on a microcontroller but tested with code running native on a PC.)
I don't know if the "_t" convention for type identifiers started with
POSIX, but it has certainly far outgrown POSIX. And I think the smart
folks behind POSIX know this, and will not assume that just because they pick a new type name ending in _t, it will not conflict with some user
code. As C doesn't have namespaces, there is always a risk of
conflicting names - you just have to try to avoid clashes in things you
are likely to see.
Anyway, the point is that the `_t` convention predates POSIX
(and ANSI C) by about a decade.
On 2026-10-22, David Brown <[email protected]> wrote:
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to most
code that is used in connection with FreeRTOS, or LWIP. (Of course
there will be some overlap - bits of code that are intended to run on a
microcontroller but tested with code running native on a PC.)
I don't know if the "_t" convention for type identifiers started with
POSIX, but it has certainly far outgrown POSIX. And I think the smart
folks behind POSIX know this, and will not assume that just because they
pick a new type name ending in _t, it will not conflict with some user
code. As C doesn't have namespaces, there is always a risk of
conflicting names - you just have to try to avoid clashes in things you
are likely to see.
These namespace declarations are really just a "heads up". POSIX
isn't saying, don't have an identifier ending in _t in a namespace
shared by typedefs. Rather, it is saying that new typedefs appearing
in POSIX will be in that namespace.
Consider this argument: whenever POSIX or ISO C introduces a new
public identifier, it's necessarily going to start with "a", or else if
not, then with "b", or else with "c", ... or else with "z"
or perhaps the underscore.
That doesn't mean you stop using identifiers in programming.
"nullptr" is now a keyword, previously a valid identifier not in
any proclaimed reserved namespace. Progrems which used it have
to be changed to work with the newer language.
Avoiding proclaimed namespaces will not protect you from clashes;
only from clashes that would occur in those namespaces.
Some spaces like _t are too attractive to avoid, because they are tied
to an important, popular convention that everyone understands,
and the benefits outweigh the unrealized risk of a future clash.
On 2026-10-22, David Brown <[email protected]> wrote:
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to most
code that is used in connection with FreeRTOS, or LWIP. (Of course
there will be some overlap - bits of code that are intended to run on a
microcontroller but tested with code running native on a PC.)
I don't know if the "_t" convention for type identifiers started with
POSIX, but it has certainly far outgrown POSIX. And I think the smart
folks behind POSIX know this, and will not assume that just because they
pick a new type name ending in _t, it will not conflict with some user
code. As C doesn't have namespaces, there is always a risk of
conflicting names - you just have to try to avoid clashes in things you
are likely to see.
These namespace declarations are really just a "heads up". POSIX
isn't saying, don't have an identifier ending in _t in a namespace
shared by typedefs. Rather, it is saying that new typedefs appearing
in POSIX will be in that namespace.
Consider this argument: whenever POSIX or ISO C introduces a new
public identifier, it's necessarily going to start with "a", or else if
not, then with "b", or else with "c", ... or else with "z"
or perhaps the underscore.
That doesn't mean you stop using identifiers in programming.
"nullptr" is now a keyword, previously a valid identifier not in
any proclaimed reserved namespace. Progrems which used it have
to be changed to work with the newer language.
Avoiding proclaimed namespaces will not protect you from clashes;
only from clashes that would occur in those namespaces.
Some spaces like _t are too attractive to avoid, because they are tied
to an important, popular convention that everyone understands,
and the benefits outweigh the unrealized risk of a future clash.
These namespace declarations are really just a "heads up". POSIX[...]
isn't saying, don't have an identifier ending in _t in a namespace
shared by typedefs. Rather, it is saying that new typedefs appearing
in POSIX will be in that namespace.
Kaz Kylheku <[email protected]> writes:
[...]
These namespace declarations are really just a "heads up". POSIX[...]
isn't saying, don't have an identifier ending in _t in a namespace
shared by typedefs. Rather, it is saying that new typedefs appearing
in POSIX will be in that namespace.
No, it says that all conforming applications are required to avoid
symbols ending in "_t".
https://pubs.opengroup.org/onlinepubs/9799919799/xrat/V4_xsh_chap01.html B.2.11.1 Defined Types
The requirement that additional types defined in this section
end in "_t" was prompted by the problem of name space pollution.
It is difficult to define a type (where that type is not one
defined by POSIX.1-2024) in one header file and use it in another
without adding symbols to the name space of the program. To
allow implementors to provide their own types, all conforming
applications are required to avoid symbols ending in "_t",
which permits the implementor to provide additional types.
Because a major use of types is in the definition of structure
members, which can (and in many cases must) be added to the
structures defined in POSIX.1-2024, the need for additional
types is compelling.
Of course you don't have to avoid defining symbols ending with "_t"
if you don't want to, but if you do so you don't have a "conforming application" as far as POSIX is concerned.
It is, of course, an imperfect solution.
Kaz Kylheku <[email protected]> writes:
[...]
These namespace declarations are really just a "heads up". POSIX[...]
isn't saying, don't have an identifier ending in _t in a namespace
shared by typedefs. Rather, it is saying that new typedefs appearing
in POSIX will be in that namespace.
No, it says that all conforming applications are required to avoid
symbols ending in "_t".
Of course you don't have to avoid defining symbols ending with "_t"
if you don't want to, but if you do so you don't have a "conforming application" as far as POSIX is concerned.
On 10/22/2026 9:54 AM, Kaz Kylheku wrote:
On 2026-10-22, David Brown <[email protected]> wrote:
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to most
code that is used in connection with FreeRTOS, or LWIP. (Of course
there will be some overlap - bits of code that are intended to run on a
microcontroller but tested with code running native on a PC.)
Avoiding proclaimed namespaces will not protect you from clashes;
only from clashes that would occur in those namespaces.
Some spaces like _t are too attractive to avoid, because they are tied
to an important, popular convention that everyone understands,
and the benefits outweigh the unrealized risk of a future clash.
Touche. How about _this vs this_. I just use self and be done with it.
On 2026-10-22, Keith Thompson <[email protected]> wrote:
Kaz Kylheku <[email protected]> writes:
[...]
These namespace declarations are really just a "heads up". POSIX[...]
isn't saying, don't have an identifier ending in _t in a namespace
shared by typedefs. Rather, it is saying that new typedefs appearing
in POSIX will be in that namespace.
No, it says that all conforming applications are required to avoid
symbols ending in "_t".
That concept is needed in order to make it the application's fault
when it suddenly fails to build because it's using foo_t, and
POSIX decides to introduced that into <sys/types.h>.
If you use _t, a clash may happen, and if it does, then since POSIX told-you-so, it must be your program that is nonconforming, and not the
POSIX has a defect or the implementation is nonconforming.
Of course you don't have to avoid defining symbols ending with "_t"
if you don't want to, but if you do so you don't have a "conforming
application" as far as POSIX is concerned.
This is okay if you have a grip on the nonconformances in the
application. You know where they are and have a way to be informed when
they turn into real problems and a plan for that situation.
Remember, a program that uses nullptr as a variable name was once
conforming. Through no change in the program whatsoever, it became nonconforming. Playing the conformance game in this area is largely
a fool's errand.
On 22/10/2026 21:46, Chris M. Thomasson wrote:
On 10/22/2026 9:54 AM, Kaz Kylheku wrote:
On 2026-10-22, David Brown <[email protected]> wrote:
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to most >>>> code that is used in connection with FreeRTOS, or LWIP. (Of course
there will be some overlap - bits of code that are intended to run on a >>>> microcontroller but tested with code running native on a PC.)
Avoiding proclaimed namespaces will not protect you from clashes;
only from clashes that would occur in those namespaces.
Some spaces like _t are too attractive to avoid, because they are tied
to an important, popular convention that everyone understands,
and the benefits outweigh the unrealized risk of a future clash.
Touche. How about _this vs this_. I just use self and be done with it.
Imagine, just for a moment, that the rest of us are not privy to the
jumble of thoughts and ideas that jump around in your head. I don't
have the context of what you are thinking about. So I have no idea what you mean by this.
Instead of posting random out-of-context snippets of thought, either
write posts that say what you are talking about, or don't bother. (And
do /not/ imagine that posting reams of unconnected code is a useful alternative.)
If you are trying to say something about avoiding C++ keywords when
picking identifiers in C coding, say that. If you are trying to say something about naming conventions for C++ class members, feel free to
talk about that too - in comp.lang.c++. If you are trying to say
something else, say it. Or drop it, if you prefer.
I like self.
void foo(struct foo* const self);
On Fri, 23 Oct 2026 14:21:15 -0700, Chris M. Thomasson wrote:
I like self.
void foo(struct foo* const self);
The trouble with a fixed name is, how do you refer to the instance of
an outer class?
On 10/23/2026 12:37 AM, David Brown wrote:
On 22/10/2026 21:46, Chris M. Thomasson wrote:
On 10/22/2026 9:54 AM, Kaz Kylheku wrote:
On 2026-10-22, David Brown <[email protected]> wrote:
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to most >>>>> code that is used in connection with FreeRTOS, or LWIP. (Of course >>>>> there will be some overlap - bits of code that are intended to run
on a
microcontroller but tested with code running native on a PC.)
Avoiding proclaimed namespaces will not protect you from clashes;
only from clashes that would occur in those namespaces.
Some spaces like _t are too attractive to avoid, because they are tied >>>> to an important, popular convention that everyone understands,
and the benefits outweigh the unrealized risk of a future clash.
Touche. How about _this vs this_. I just use self and be done with it.
Imagine, just for a moment, that the rest of us are not privy to the
jumble of thoughts and ideas that jump around in your head. I don't
have the context of what you are thinking about. So I have no idea
what you mean by this.
Instead of posting random out-of-context snippets of thought, either
write posts that say what you are talking about, or don't bother.
(And do /not/ imagine that posting reams of unconnected code is a
useful alternative.)
If you are trying to say something about avoiding C++ keywords when
picking identifiers in C coding, say that. If you are trying to say
something about naming conventions for C++ class members, feel free to
talk about that too - in comp.lang.c++. If you are trying to say
something else, say it. Or drop it, if you prefer.
Or, Well,
_this
vs
this_
Are they both legal?
I like self.
void foo(struct foo* const self);
vs
void foo(struct foo* const _this);
void foo(struct foo* const this);
void foo(struct foo* const this_);
? For some reason I do not want to use this in C.
On 10/23/2026 3:40 PM, Lawrence D’Oliveiro wrote:
The trouble with a fixed name is, how do you refer to the instance
of an outer class?
Well, self can be internal to the API logic.
On Fri, 23 Oct 2026 18:33:56 -0700, Chris M. Thomasson wrote:
On 10/23/2026 3:40 PM, Lawrence D’Oliveiro wrote:
The trouble with a fixed name is, how do you refer to the instance
of an outer class?
Well, self can be internal to the API logic.
If “self” refers to the current instance of the innermost class, how
do you refer to an instance of an outer class?
On Fri, 23 Oct 2026 18:33:56 -0700, Chris M. Thomasson wrote:
On 10/23/2026 3:40 PM, Lawrence D’Oliveiro wrote:
The trouble with a fixed name is, how do you refer to the instance
of an outer class?
Well, self can be internal to the API logic.
If “self” refers to the current instance of the innermost class, how
do you refer to an instance of an outer class?
On 23/10/2026 23:21, Chris M. Thomasson wrote:
On 10/23/2026 12:37 AM, David Brown wrote:
On 22/10/2026 21:46, Chris M. Thomasson wrote:
On 10/22/2026 9:54 AM, Kaz Kylheku wrote:
On 2026-10-22, David Brown <[email protected]> wrote:
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to most >>>>>> code that is used in connection with FreeRTOS, or LWIP. (Of course >>>>>> there will be some overlap - bits of code that are intended to run >>>>>> on a
microcontroller but tested with code running native on a PC.)
Avoiding proclaimed namespaces will not protect you from clashes;
only from clashes that would occur in those namespaces.
Some spaces like _t are too attractive to avoid, because they are tied >>>>> to an important, popular convention that everyone understands,
and the benefits outweigh the unrealized risk of a future clash.
Touche. How about _this vs this_. I just use self and be done with it.
Imagine, just for a moment, that the rest of us are not privy to the
jumble of thoughts and ideas that jump around in your head. I don't
have the context of what you are thinking about. So I have no idea
what you mean by this.
Instead of posting random out-of-context snippets of thought, either
write posts that say what you are talking about, or don't bother.
(And do /not/ imagine that posting reams of unconnected code is a
useful alternative.)
If you are trying to say something about avoiding C++ keywords when
picking identifiers in C coding, say that. If you are trying to say
something about naming conventions for C++ class members, feel free
to talk about that too - in comp.lang.c++. If you are trying to say
something else, say it. Or drop it, if you prefer.
Or, Well,
_this
vs
this_
Are they both legal?
What do you mean, "legal" ? Identifiers in C can start with any letter (including most Unicode "letters") or underscore, or any other implementation-defined characters. Subsequent characters can be any of these or a normal digit from the basic source character set.
The only identifiers you may not use are ones that match keywords.
There are various patterns that are "reserved", depending on header
usage, but using them is still "legal". The main ones to avoid are identifiers starting with two underscores, or one underscore and a
capital letter.
I like self.
void foo(struct foo* const self);
vs
void foo(struct foo* const _this);
void foo(struct foo* const this);
void foo(struct foo* const this_);
? For some reason I do not want to use this in C.
Use whichever you like. I would personally avoid using an identifier in
C that matches a keyword (or "contextual keyword") in C++, to make it
easier to re-use the same code in C++. But you don't have to do the same.
On 10/24/2026 3:58 AM, David Brown wrote:
On 23/10/2026 23:21, Chris M. Thomasson wrote:
On 10/23/2026 12:37 AM, David Brown wrote:
On 22/10/2026 21:46, Chris M. Thomasson wrote:
On 10/22/2026 9:54 AM, Kaz Kylheku wrote:Imagine, just for a moment, that the rest of us are not privy to the
On 2026-10-22, David Brown <[email protected]> wrote:
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to >>>>>>> most
code that is used in connection with FreeRTOS, or LWIP. (Of course >>>>>>> there will be some overlap - bits of code that are intended to
run on a
microcontroller but tested with code running native on a PC.)
Avoiding proclaimed namespaces will not protect you from clashes;
only from clashes that would occur in those namespaces.
Some spaces like _t are too attractive to avoid, because they are >>>>>> tied
to an important, popular convention that everyone understands,
and the benefits outweigh the unrealized risk of a future clash.
Touche. How about _this vs this_. I just use self and be done with it. >>>>
jumble of thoughts and ideas that jump around in your head. I don't >>>> have the context of what you are thinking about. So I have no idea
what you mean by this.
Instead of posting random out-of-context snippets of thought, either
write posts that say what you are talking about, or don't bother.
(And do /not/ imagine that posting reams of unconnected code is a
useful alternative.)
If you are trying to say something about avoiding C++ keywords when
picking identifiers in C coding, say that. If you are trying to say >>>> something about naming conventions for C++ class members, feel free
to talk about that too - in comp.lang.c++. If you are trying to say >>>> something else, say it. Or drop it, if you prefer.
Or, Well,
_this
vs
this_
Are they both legal?
What do you mean, "legal" ? Identifiers in C can start with any
letter (including most Unicode "letters") or underscore, or any other
implementation-defined characters. Subsequent characters can be any
of these or a normal digit from the basic source character set.
The only identifiers you may not use are ones that match keywords.
There are various patterns that are "reserved", depending on header
usage, but using them is still "legal". The main ones to avoid are
identifiers starting with two underscores, or one underscore and a
capital letter.
I like self.
void foo(struct foo* const self);
vs
void foo(struct foo* const _this);
void foo(struct foo* const this);
void foo(struct foo* const this_);
? For some reason I do not want to use this in C.
Use whichever you like. I would personally avoid using an identifier
in C that matches a keyword (or "contextual keyword") in C++, to make
it easier to re-use the same code in C++. But you don't have to do
the same.
_this good, _This bad?
_this good, _This bad?
On 25/10/2026 05:42, Chris M. Thomasson wrote:
On 10/24/2026 3:58 AM, David Brown wrote:
On 23/10/2026 23:21, Chris M. Thomasson wrote:
On 10/23/2026 12:37 AM, David Brown wrote:
On 22/10/2026 21:46, Chris M. Thomasson wrote:
On 10/22/2026 9:54 AM, Kaz Kylheku wrote:
On 2026-10-22, David Brown <[email protected]> wrote:
On 21/10/2026 22:02, Chris M. Thomasson wrote:
On 10/21/2026 5:17 AM, David Brown wrote:
[...]
*_t intrudes into POSIX.
I don't program for POSIX, so I don't care. The same applies to >>>>>>>> most
code that is used in connection with FreeRTOS, or LWIP. (Of course >>>>>>>> there will be some overlap - bits of code that are intended to >>>>>>>> run on a
microcontroller but tested with code running native on a PC.)
Avoiding proclaimed namespaces will not protect you from clashes; >>>>>>> only from clashes that would occur in those namespaces.
Some spaces like _t are too attractive to avoid, because they are >>>>>>> tied
to an important, popular convention that everyone understands,
and the benefits outweigh the unrealized risk of a future clash. >>>>>>>
Touche. How about _this vs this_. I just use self and be done with >>>>>> it.
Imagine, just for a moment, that the rest of us are not privy to
the jumble of thoughts and ideas that jump around in your head. I >>>>> don't have the context of what you are thinking about. So I have
no idea what you mean by this.
Instead of posting random out-of-context snippets of thought,
either write posts that say what you are talking about, or don't
bother. (And do /not/ imagine that posting reams of unconnected
code is a useful alternative.)
If you are trying to say something about avoiding C++ keywords when >>>>> picking identifiers in C coding, say that. If you are trying to
say something about naming conventions for C++ class members, feel
free to talk about that too - in comp.lang.c++. If you are trying >>>>> to say something else, say it. Or drop it, if you prefer.
Or, Well,
_this
vs
this_
Are they both legal?
What do you mean, "legal" ? Identifiers in C can start with any
letter (including most Unicode "letters") or underscore, or any other
implementation-defined characters. Subsequent characters can be any
of these or a normal digit from the basic source character set.
The only identifiers you may not use are ones that match keywords.
There are various patterns that are "reserved", depending on header
usage, but using them is still "legal". The main ones to avoid are
identifiers starting with two underscores, or one underscore and a
capital letter.
I like self.
void foo(struct foo* const self);
vs
void foo(struct foo* const _this);
void foo(struct foo* const this);
void foo(struct foo* const this_);
? For some reason I do not want to use this in C.
Use whichever you like. I would personally avoid using an identifier
in C that matches a keyword (or "contextual keyword") in C++, to make
it easier to re-use the same code in C++. But you don't have to do
the same.
_this good, _This bad?
You figure it out. I'm done trying to understand your silly little
posts and silly little questions, and then spoon-feed you basics about
the C language.
if {} or if {} or if {} else {}
fir pisze:
if {} or if {} or if {} else {}
this form in fact is not bad, it simply showst two things
1) you may use or outside the if clause (if this () can be named clause)
2) else in fact work on logical group but ias sole if is alos a case of logical group so else work on it sole in special case
otherwiste thse keywords here if or and else are quite 'legit'
if () {}
or if () {}
or if() {}
else {}
seems quite legit and it seem to ba a switchExcellent. A great thing about this is, this can also be legal C, that
On 26/10/2026 12:07, fir wrote:
fir pisze:Excellent. A great thing about this is, this can also be legal C, that
if {} or if {} or if {} else {}
this form in fact is not bad, it simply showst two things
1) you may use or outside the if clause (if this () can be named clause)
2) else in fact work on logical group but ias sole if is alos a case
of logical group so else work on it sole in special case
otherwiste thse keywords here if or and else are quite 'legit'
if () {}
or if () {}
or if() {}
else {}
seems quite legit and it seem to ba a switch
works now, if you just precede with this:
#define or else
bartc pisze:
On 26/10/2026 12:07, fir wrote:this wouldnt work imo as far as im aware becouse this last else dont
fir pisze:Excellent. A great thing about this is, this can also be legal C, that
if {} or if {} or if {} else {}
this form in fact is not bad, it simply showst two things
1) you may use or outside the if clause (if this () can be named clause) >>>
2) else in fact work on logical group but ias sole if is alos a case
of logical group so else work on it sole in special case
otherwiste thse keywords here if or and else are quite 'legit'
if () {}
or if () {}
or if() {}
else {}
seems quite legit and it seem to ba a switch
works now, if you just precede with this:
#define or else
work on "group'
the last else is what i name "otherwise" (its else in all other case"You seem to have named it 'else' in your example. In any case it would
On 26/10/2026 12:20, fir wrote:
bartc pisze:
On 26/10/2026 12:07, fir wrote:this wouldnt work imo as far as im aware becouse this last else dont
fir pisze:Excellent. A great thing about this is, this can also be legal C,
if {} or if {} or if {} else {}
this form in fact is not bad, it simply showst two things
1) you may use or outside the if clause (if this () can be named
clause)
2) else in fact work on logical group but ias sole if is alos a case
of logical group so else work on it sole in special case
otherwiste thse keywords here if or and else are quite 'legit'
if () {}
or if () {}
or if() {}
else {}
seems quite legit and it seem to ba a switch
that works now, if you just precede with this:
#define or else
work on "group'
This works fine:
#define or else
for (int i=0; i<=5; ++i)
if (i==1) {puts("One");}
or if (i==2) {puts("Two");}
or if (i==3) {puts("Three");}
else {puts("Other");}
Output is:
Other
One
Two
Three
Other
Other
The point is you eventually came up with syntax that is actually just C
but using 'or' in place of 'else'.
the last else is what i name "otherwise" (its else in all other case"You seem to have named it 'else' in your example. In any case it would
just be a slightly different choice of keyword; it buys you very little.
On Sat, 24 Oct 2026 21:42:50 -0700, Chris M. Thomasson wrote:
_this good, _This bad?
If asked “how many letters are there in the English alphabet?”, what answer do you think (normal) people are more likely to give: “26” or “52”?
I think the instinctive answer most people would give is “26”.
bartc pisze:
On 26/10/2026 12:20, fir wrote:maybe try with like
bartc pisze:
On 26/10/2026 12:07, fir wrote:this wouldnt work imo as far as im aware becouse this last else dont
fir pisze:Excellent. A great thing about this is, this can also be legal C,
if {} or if {} or if {} else {}
this form in fact is not bad, it simply showst two things
1) you may use or outside the if clause (if this () can be named
clause)
2) else in fact work on logical group but ias sole if is alos a
case of logical group so else work on it sole in special case
otherwiste thse keywords here if or and else are quite 'legit'
if () {}
or if () {}
or if() {}
else {}
seems quite legit and it seem to ba a switch
that works now, if you just precede with this:
#define or else
work on "group'
This works fine:
#define or else
for (int i=0; i<=5; ++i)
if (i==1) {puts("One");}
or if (i==2) {puts("Two");}
or if (i==3) {puts("Three");}
else {puts("Other");}
Output is:
Other
One
Two
Three
Other
Other
The point is you eventually came up with syntax that is actually just
C but using 'or' in place of 'else'.
the last else is what i name "otherwise" (its else in all other case"You seem to have named it 'else' in your example. In any case it would
just be a slightly different choice of keyword; it buys you very little.
case x%2==0 //2 4 6 8 10 12
case x%3==0 //3 6 9 12
default // 1 5 7 11 13
the default should run if none of above cases catch (as i remember coz i dont use switch) and thse cases should catch each time
im maybe talkong about some more general switch here
(abstract) it is more important then normal one - as thsi general covers various possible casesYou seem fixated on that 'or'. Either use 'else', or create 'or' as an
using if or you can implement i it
if(x%2==0) {}
or if(x%3==0) {}
else {}
without or (or something analogic) as i understand if im not wrong you cant
On 26/10/2026 16:03, fir wrote:
bartc pisze:
On 26/10/2026 12:20, fir wrote:maybe try with like
bartc pisze:
On 26/10/2026 12:07, fir wrote:this wouldnt work imo as far as im aware becouse this last else dont
fir pisze:Excellent. A great thing about this is, this can also be legal C,
if {} or if {} or if {} else {}
this form in fact is not bad, it simply showst two things
1) you may use or outside the if clause (if this () can be named
clause)
2) else in fact work on logical group but ias sole if is alos a
case of logical group so else work on it sole in special case
otherwiste thse keywords here if or and else are quite 'legit'
if () {}
or if () {}
or if() {}
else {}
seems quite legit and it seem to ba a switch
that works now, if you just precede with this:
#define or else
work on "group'
This works fine:
#define or else
for (int i=0; i<=5; ++i)
if (i==1) {puts("One");}
or if (i==2) {puts("Two");}
or if (i==3) {puts("Three");}
else {puts("Other");}
Output is:
Other
One
Two
Three
Other
Other
The point is you eventually came up with syntax that is actually just
C but using 'or' in place of 'else'.
the last else is what i name "otherwise" (its else in all other case"You seem to have named it 'else' in your example. In any case it
would just be a slightly different choice of keyword; it buys you
very little.
case x%2==0 //2 4 6 8 10 12
case x%3==0 //3 6 9 12
No, cases '6' and '12' are also true for x%2==0. Unless you want these
to be non-exclusive?
default // 1 5 7 11 13
the default should run if none of above cases catch (as i remember coz
i dont use switch) and thse cases should catch each time
OK. C doesn't have a direct syntax for this. But it does have if-else
chains for precisely this job. What is the problem with that? You can
write it like this if you like:
if (0)
else if (x%2==0) {}
else if (x%3==0) {}
if you want consistency. There's no point in creating a slightly
different syntax for the same thing.
im maybe talkong about some more general switch here
What does 'switch' mean to you? It seems that every day it is something
with more and more capabilities and it gets more ambiguous. At some
point it will its own AI to divine your intentions.
but this general
(abstract) it is more important then normal one - as thsi generalYou seem fixated on that 'or'. Either use 'else', or create 'or' as an
covers various possible cases
using if or you can implement i it
if(x%2==0) {}
or if(x%3==0) {}
else {}
without or (or something analogic) as i understand if im not wrong you
cant
alias as I suggested.
bartc pisze:
On 26/10/2026 16:03, fir wrote:
bartc pisze:
On 26/10/2026 12:20, fir wrote:maybe try with like
bartc pisze:
On 26/10/2026 12:07, fir wrote:this wouldnt work imo as far as im aware becouse this last else
fir pisze:Excellent. A great thing about this is, this can also be legal C, >>>>>> that works now, if you just precede with this:
if {} or if {} or if {} else {}
this form in fact is not bad, it simply showst two things
1) you may use or outside the if clause (if this () can be named >>>>>>> clause)
2) else in fact work on logical group but ias sole if is alos a >>>>>>> case of logical group so else work on it sole in special case
otherwiste thse keywords here if or and else are quite 'legit'
if () {}
or if () {}
or if() {}
else {}
seems quite legit and it seem to ba a switch
#define or else
dont work on "group'
This works fine:
#define or else
for (int i=0; i<=5; ++i)
if (i==1) {puts("One");}
or if (i==2) {puts("Two");}
or if (i==3) {puts("Three");}
else {puts("Other");}
Output is:
Other
One
Two
Three
Other
Other
The point is you eventually came up with syntax that is actually
just C but using 'or' in place of 'else'.
the last else is what i name "otherwise" (its else in all other case" >>>> You seem to have named it 'else' in your example. In any case itwould just be a slightly different choice of keyword; it buys you
very little.
case x%2==0 //2 4 6 8 10 12
case x%3==0 //3 6 9 12
No, cases '6' and '12' are also true for x%2==0. Unless you want these
to be non-exclusive?
default // 1 5 7 11 13
the default should run if none of above cases catch (as i remember
coz i dont use switch) and thse cases should catch each time
OK. C doesn't have a direct syntax for this. But it does have if-else
chains for precisely this job. What is the problem with that? You can
write it like this if you like:
if (0)
else if (x%2==0) {}
else if (x%3==0) {}
you want it the above to pront "divides by 2" "divides by 3" for 6 and
12 "divides by 2" for 4 8 and 'divided by 3" for 2 9 in case it not
divides by 2 or 3 pronts "no divides "
this above will not work for 6 for example as it only will prit "divides
by 2"
without or (or something analogic) as i understand if im not wrong youYou seem fixated on that 'or'. Either use 'else', or create 'or' as an
cant
alias as I suggested.
bartc pisze:
without or (or something analogic) as i understand if im not wrongYou seem fixated on that 'or'. Either use 'else', or create 'or' as an
you cant
alias as I suggested.
imo you should try to understand the example
for(int i = 1; i < 20; i++)
{
if(x%2==0) printf("\n divides by 2");
or if(x%3==0) printf("\n divides by 3");
else printf("\n no divides (by 2 or 3)");
}
you understand how this would work? i think you do
and how in normal c without this "or" it would look,
for exampel in your if else model?
On 26/10/2026 16:45, fir wrote:
bartc pisze:
without or (or something analogic) as i understand if im not wrongYou seem fixated on that 'or'. Either use 'else', or create 'or' as
you cant
an alias as I suggested.
imo you should try to understand the example
for(int i = 1; i < 20; i++)
{
if(x%2==0) printf("\n divides by 2");
or if(x%3==0) printf("\n divides by 3");
else printf("\n no divides (by 2 or 3)");
}
you understand how this would work? i think you do
and how in normal c without this "or" it would look,
for exampel in your if else model?
Show me exactly what the output should be, when it is written like this:
if(x%2==0) printf("\n%d divides by 2", i);
or if(x%3==0) printf("\n%d divides by 3", i);
else printf("\n%d no divides (by 2 or 3)", i);
You might also want to look at the FizzBuzz program.
bartc pisze:
On 26/10/2026 16:45, fir wrote:1 no divides (by 2 or 3)
bartc pisze:
without or (or something analogic) as i understand if im not wrongYou seem fixated on that 'or'. Either use 'else', or create 'or' as
you cant
an alias as I suggested.
imo you should try to understand the example
for(int i = 1; i < 20; i++)
{
if(x%2==0) printf("\n divides by 2");
or if(x%3==0) printf("\n divides by 3");
else printf("\n no divides (by 2 or 3)");
}
you understand how this would work? i think you do
and how in normal c without this "or" it would look,
for exampel in your if else model?
Show me exactly what the output should be, when it is written like this:
if(x%2==0) printf("\n%d divides by 2", i);
or if(x%3==0) printf("\n%d divides by 3", i);
else printf("\n%d no divides (by 2 or 3)", i);
You might also want to look at the FizzBuzz program.
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
fir pisze:
bartc pisze:
On 26/10/2026 16:45, fir wrote:1 no divides (by 2 or 3)
bartc pisze:
without or (or something analogic) as i understand if im not wrong >>>>>> you cantYou seem fixated on that 'or'. Either use 'else', or create 'or' as >>>>> an alias as I suggested.
imo you should try to understand the example
for(int i = 1; i < 20; i++)
{
if(x%2==0) printf("\n divides by 2");
or if(x%3==0) printf("\n divides by 3");
else printf("\n no divides (by 2 or 3)");
}
you understand how this would work? i think you do
and how in normal c without this "or" it would look,
for exampel in your if else model?
Show me exactly what the output should be, when it is written like this: >>>
if(x%2==0) printf("\n%d divides by 2", i);
or if(x%3==0) printf("\n%d divides by 3", i);
else printf("\n%d no divides (by 2 or 3)", i);
You might also want to look at the FizzBuzz program.
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
in fact i had more such in my mind
for(int i=0; i<20; i++)
{
printf("\n %d,i);
if(x%2==0) printf("\n divides by 2");
or if(x%3==0) printf("\n divides by 3");
else printf("\n no divides (by 2 or 3)");
}
so the output is
1
no divides (by 2 or 3)
2
divides by 2
3
divides by 3
4
divides by 2
5
no divides (by 2 or 3)
6
divides by 2
divides by 3
7
no divides (by 2 or 3)
8
divides by 2
9
divides by 3
10
divides by 2
11
no divides (by 2 or 3)
12
divides by 2
divides by 3
13
no divides (by 2 or 3)
14
divides by 2
15
divides by 3
16
divides by 2
17
no divides (by 2 or 3)
18
divides by 2
divides by 3
19
no divides (by 2 or 3)
On 26/10/2026 16:37, fir wrote:[...]
bartc pisze:
On 26/10/2026 16:03, fir wrote:
bartc pisze:
On 26/10/2026 12:20, fir wrote:
bartc pisze:
On 26/10/2026 12:07, fir wrote:
fir pisze:
if {} or if {} or if {} else {}
[...]if () {}
or if () {}
or if() {}
else {}
[...]#define or else
for (int i=0; i<=5; ++i)
if (i==1) {puts("One");}
or if (i==2) {puts("Two");}
or if (i==3) {puts("Three");}
else {puts("Other");}
[...]case x%2==0 //2 4 6 8 10 12
case x%3==0 //3 6 9 12
default // 1 5 7 11 13
[...]if (0)
else if (x%2==0) {}
else if (x%3==0) {}
if (x%2==0) {}
if (x%3==0) {}
Here it is clear they are non-exclusive.
You're also in luck: this is exactly how C works now!
On 2026-10-26 17:42, bartc wrote:
On 26/10/2026 16:37, fir wrote:[...]
bartc pisze:
On 26/10/2026 16:03, fir wrote:
bartc pisze:
On 26/10/2026 12:20, fir wrote:
bartc pisze:
On 26/10/2026 12:07, fir wrote:
fir pisze:
if {} or if {} or if {} else {}
[...]if () {}
or if () {}
or if() {}
else {}
[...]#define or else
for (int i=0; i<=5; ++i)
if (i==1) {puts("One");}
or if (i==2) {puts("Two");}
or if (i==3) {puts("Three");}
else {puts("Other");}
[...]case x%2==0 //2 4 6 8 10 12
case x%3==0 //3 6 9 12
default // 1 5 7 11 13
[...]if (0)
else if (x%2==0) {}
else if (x%3==0) {}
if (x%2==0) {}
if (x%3==0) {}
Here it is clear they are non-exclusive.
You're also in luck: this is exactly how C works now!
I'm not sure what fir actually wants; I cannot decipher his writings
quoted by you. But, given that he not yet seems satisfied with your
replies and suggestions, could it, by any chance, be that what he
wants is some non-deterministic construct like Dijkstra's Guards?
I.e., that with two guards 'x%2==0' and 'x%3==0' and an input of "6"
only _one_ of the two gets _arbitrarily_ triggered?
(Otherwise his post appears quite pointless to me.)
Janis
bartc pisze:
On 26/10/2026 16:45, fir wrote:1 no divides (by 2 or 3)
bartc pisze:
without or (or something analogic) as i understand if im not wrongYou seem fixated on that 'or'. Either use 'else', or create 'or' as
you cant
an alias as I suggested.
imo you should try to understand the example
for(int i = 1; i < 20; i++)
{
if(x%2==0) printf("\n divides by 2");
or if(x%3==0) printf("\n divides by 3");
else printf("\n no divides (by 2 or 3)");
}
you understand how this would work? i think you do
and how in normal c without this "or" it would look,
for exampel in your if else model?
Show me exactly what the output should be, when it is written like this:
if(x%2==0) printf("\n%d divides by 2", i);
or if(x%3==0) printf("\n%d divides by 3", i);
else printf("\n%d no divides (by 2 or 3)", i);
You might also want to look at the FizzBuzz program.
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
On 26/10/2026 17:06, fir wrote:
bartc pisze:
On 26/10/2026 16:45, fir wrote:1 no divides (by 2 or 3)
bartc pisze:
without or (or something analogic) as i understand if im not wrong >>>>>> you cantYou seem fixated on that 'or'. Either use 'else', or create 'or' as >>>>> an alias as I suggested.
imo you should try to understand the example
for(int i = 1; i < 20; i++)
{
if(x%2==0) printf("\n divides by 2");
or if(x%3==0) printf("\n divides by 3");
else printf("\n no divides (by 2 or 3)");
}
you understand how this would work? i think you do
and how in normal c without this "or" it would look,
for exampel in your if else model?
Show me exactly what the output should be, when it is written like this: >>>
if(x%2==0) printf("\n%d divides by 2", i);
or if(x%3==0) printf("\n%d divides by 3", i);
else printf("\n%d no divides (by 2 or 3)", i);
You might also want to look at the FizzBuzz program.
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
OK, thanks. So the pattern you're talking about is this:
case (c1) {s1}
case (c2) {s2}
case (c3) {s3}
else {s4}
where each of s1/s2/s3 is executed if the corresponding c1/c2/c3 is
true, independently of the others. At least one statement will be
executed in 7 of the 8 possible boolean combinations in this example.
s4 is only executed when each of c1/c2/c3 is false. In other words:
if (c1) {s1}
if (c2) {s2}
if (c3) {s3}
if (!c1 && !c2 && !c3) {s4}
Assuming c1/c2/c3 are not modified by s1/s2/s3, but this is also partly
the case with your proposal.
Or maybe it can be done like this:
if (c1 || c2 || c3) {
s4
else if (c1) {s1)
....
The syntax will anyway need some work to tie all those case/if parts together (as s2 for example could contain nested versions).
Or you can forget about having to create a hard-to-grasp and awkward-to-implement feature like this, and either use workarounds like
my C examples, or use another approach to the problem.
bartc pisze:
hahaha1 no divides (by 2 or 3)
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
OK, thanks. So the pattern you're talking about is this:
case (c1) {s1}
case (c2) {s2}
case (c3) {s3}
else {s4}
where each of s1/s2/s3 is executed if the corresponding c1/c2/c3 is
true, independently of the others. At least one statement will be
executed in 7 of the 8 possible boolean combinations in this example.
s4 is only executed when each of c1/c2/c3 is false. In other words:
if (c1) {s1}
if (c2) {s2}
if (c3) {s3}
if (!c1 && !c2 && !c3) {s4}
Assuming c1/c2/c3 are not modified by s1/s2/s3, but this is also
partly the case with your proposal.
Or maybe it can be done like this:
if (c1 || c2 || c3) {
s4
else if (c1) {s1)
....
The syntax will anyway need some work to tie all those case/if parts
together (as s2 for example could contain nested versions).
Or you can forget about having to create a hard-to-grasp and awkward-
to-implement feature like this, and either use workarounds like my C
examples, or use another approach to the problem.
lol ye use worakarounds instead of simple right solution
(this solution may come in some plavours as i said before, but this or ketword for reasons mentioned is not bad)
On 26/10/2026 19:39, fir wrote:
bartc pisze:
hahaha1 no divides (by 2 or 3)
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
OK, thanks. So the pattern you're talking about is this:
case (c1) {s1}
case (c2) {s2}
case (c3) {s3}
else {s4}
where each of s1/s2/s3 is executed if the corresponding c1/c2/c3 is
true, independently of the others. At least one statement will be
executed in 7 of the 8 possible boolean combinations in this example.
s4 is only executed when each of c1/c2/c3 is false. In other words:
if (c1) {s1}
if (c2) {s2}
if (c3) {s3}
if (!c1 && !c2 && !c3) {s4}
Assuming c1/c2/c3 are not modified by s1/s2/s3, but this is also
partly the case with your proposal.
Or maybe it can be done like this:
if (c1 || c2 || c3) {
s4
else if (c1) {s1)
....
The syntax will anyway need some work to tie all those case/if parts
together (as s2 for example could contain nested versions).
Or you can forget about having to create a hard-to-grasp and awkward-
to-implement feature like this, and either use workarounds like my C
examples, or use another approach to the problem.
lol ye use worakarounds instead of simple right solution
The right solution to what problem? It took multiple posts before you
even managed to explain how your proposal is supposed to behave.
(And then tomorrow it'll probably do something else.)
(this solution may come in some plavours as i said before, but this or
ketword for reasons mentioned is not bad)
OK, try a simple experiment: convert some code using your 'or' keyword
to regular C syntax and post it here. Preferably on a real example.
Because I've not convinced it comes up often enough to be worth a
dedicated feature.
Then, consider examples like this:
case (a==b and c==d) {}
case (a==b and e==f) {}
case (a<b) {}
case (a>=b) {}
case (c==d) {}
You'll find, when converting to regular C, that detecting the case of
all false will mean checking all conditions, but now those will contain duplicates. It is hard to cleanly express, which is a bad sign as a prospective language feature.
On 26/10/2026 19:39, fir wrote:
bartc pisze:
hahaha1 no divides (by 2 or 3)
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
OK, thanks. So the pattern you're talking about is this:
case (c1) {s1}
case (c2) {s2}
case (c3) {s3}
else {s4}
where each of s1/s2/s3 is executed if the corresponding c1/c2/c3 is
true, independently of the others. At least one statement will be
executed in 7 of the 8 possible boolean combinations in this example.
s4 is only executed when each of c1/c2/c3 is false. In other words:
if (c1) {s1}
if (c2) {s2}
if (c3) {s3}
if (!c1 && !c2 && !c3) {s4}
Assuming c1/c2/c3 are not modified by s1/s2/s3, but this is also
partly the case with your proposal.
Or maybe it can be done like this:
if (c1 || c2 || c3) {
s4
else if (c1) {s1)
....
The syntax will anyway need some work to tie all those case/if parts
together (as s2 for example could contain nested versions).
Or you can forget about having to create a hard-to-grasp and awkward-
to-implement feature like this, and either use workarounds like my C
examples, or use another approach to the problem.
lol ye use worakarounds instead of simple right solution
The right solution to what problem? It took multiple posts before you
even managed to explain how your proposal is supposed to behave.
(And then tomorrow it'll probably do something else.)
(this solution may come in some plavours as i said before, but this or
ketword for reasons mentioned is not bad)
OK, try a simple experiment: convert some code using your 'or' keyword
to regular C syntax and post it here. Preferably on a real example.
Because I've not convinced it comes up often enough to be worth a
dedicated feature.
Then, consider examples like this:
case (a==b and c==d) {}
case (a==b and e==f) {}
case (a<b) {}
case (a>=b) {}
case (c==d) {}
You'll find, when converting to regular C, that detecting the case of
all false will mean checking all conditions, but now those will contain duplicates. It is hard to cleanly express, which is a bad sign as a prospective language feature.
bartc pisze:
On 26/10/2026 19:39, fir wrote:
bartc pisze:
hahaha1 no divides (by 2 or 3)
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
OK, thanks. So the pattern you're talking about is this:
case (c1) {s1}
case (c2) {s2}
case (c3) {s3}
else {s4}
where each of s1/s2/s3 is executed if the corresponding c1/c2/c3 is
true, independently of the others. At least one statement will be
executed in 7 of the 8 possible boolean combinations in this example.
s4 is only executed when each of c1/c2/c3 is false. In other words:
if (c1) {s1}
if (c2) {s2}
if (c3) {s3}
if (!c1 && !c2 && !c3) {s4}
Assuming c1/c2/c3 are not modified by s1/s2/s3, but this is also
partly the case with your proposal.
Or maybe it can be done like this:
if (c1 || c2 || c3) {
s4
else if (c1) {s1)
....
The syntax will anyway need some work to tie all those case/if parts
together (as s2 for example could contain nested versions).
Or you can forget about having to create a hard-to-grasp and
awkward- to-implement feature like this, and either use workarounds
like my C examples, or use another approach to the problem.
lol ye use worakarounds instead of simple right solution
The right solution to what problem? It took multiple posts before you
even managed to explain how your proposal is supposed to behave.
(And then tomorrow it'll probably do something else.)
(this solution may come in some plavours as i said before, but this
or ketword for reasons mentioned is not bad)
OK, try a simple experiment: convert some code using your 'or' keyword
to regular C syntax and post it here. Preferably on a real example.
you cant properly convert this or/and groups to c in good way becouse
there is flaw in c you cannot express all needed combinations generally
with sole if 's and else's
as was showed here
Because I've not convinced it comes up often enough to be worth a
dedicated feature.
Then, consider examples like this:
case (a==b and c==d) {}
case (a==b and e==f) {}
case (a<b) {}
case (a>=b) {}
case (c==d) {}
You'll find, when converting to regular C, that detecting the case of
all false will mean checking all conditions, but now those will
contain duplicates. It is hard to cleanly express, which is a bad sign
as a prospective language feature.
i dont like get what you talk here..overally this is a work for compiler
to simplify it in output
btw you think i should defend the things i was talking about -
i more see its a waste of time if someone dont understand things
it is for him if he understoods or not, i have not so much time to
defend obvious things against the people who not care to much to
understand things
i would sy like its taking hours repairing a code that is
good - whou would like to do it?
generally such time spanding that you got good code and some weird
people come nad put a bulshit its wrong and expect me to explain this is
not its not a good time spending imo
i would rather expect if some will find some 'bug ' in code then he
first should understand it
bartc pisze:
On 26/10/2026 19:39, fir wrote:
bartc pisze:
hahaha1 no divides (by 2 or 3)
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
OK, thanks. So the pattern you're talking about is this:
case (c1) {s1}
case (c2) {s2}
case (c3) {s3}
else {s4}
where each of s1/s2/s3 is executed if the corresponding c1/c2/c3 is
true, independently of the others. At least one statement will be
executed in 7 of the 8 possible boolean combinations in this example.
s4 is only executed when each of c1/c2/c3 is false. In other words:
if (c1) {s1}
if (c2) {s2}
if (c3) {s3}
if (!c1 && !c2 && !c3) {s4}
Assuming c1/c2/c3 are not modified by s1/s2/s3, but this is also
partly the case with your proposal.
Or maybe it can be done like this:
if (c1 || c2 || c3) {
s4
else if (c1) {s1)
....
The syntax will anyway need some work to tie all those case/if parts
together (as s2 for example could contain nested versions).
Or you can forget about having to create a hard-to-grasp and
awkward- to-implement feature like this, and either use workarounds
like my C examples, or use another approach to the problem.
lol ye use worakarounds instead of simple right solution
The right solution to what problem? It took multiple posts before you
even managed to explain how your proposal is supposed to behave.
well i was surprised how slow you think it is the reason you get things
slow - and that s why it took multiple posts
and i make laugh becouse its funny how some slowly take some things and
how bad answer thay give - its kinda laughable
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or' keyword
to regular C syntax and post it here. Preferably on a real example.
you cant properly convert this or/and groups to c in good way becouse
there is flaw in c you cannot express all needed combinations generally
with sole if 's and else's
as was showed here
You'll find, when converting to regular C, that detecting the case of
all false will mean checking all conditions, but now those will
contain duplicates. It is hard to cleanly express, which is a bad sign
as a prospective language feature.
i dont like get what you talk here..overally this is a work for compiler
to simplify it in output
btw you think i should defend the things i was talking about -
i more see its a waste of time if someone dont understand things
it is for him if he understoods or not, i have not so much time to
defend obvious things against the people who not care to much to
understand things
i would sy like its taking hours repairing a code that is
good - whou would like to do it?
generally such time spanding that you got good code and some weird
people come nad put a bulshit its wrong and expect me to explain this is
not its not a good time spending imo
i would rather expect if some will find some 'bug ' in code then he
first should understand it
On 26/10/2026 20:32, fir wrote:
bartc pisze:
There are a couple of reasons to express it in C:OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a real
example.
you cant properly convert this or/and groups to c in good way becouse
there is flaw in c you cannot express all needed combinations
generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
You'll find, when converting to regular C, that detecting the case of
all false will mean checking all conditions, but now those will
contain duplicates. It is hard to cleanly express, which is a bad
sign as a prospective language feature.
i dont like get what you talk here..overally this is a work for compiler
to simplify it in output
In my case the compiler is my job too!
btw you think i should defend the things i was talking about -
i more see its a waste of time if someone dont understand things
it is for him if he understoods or not, i have not so much time to
defend obvious things against the people who not care to much to
understand things
i would sy like its taking hours repairing a code that is
good - whou would like to do it?
generally such time spanding that you got good code and some weird
people come nad put a bulshit its wrong and expect me to explain this
is not its not a good time spending imo
i would rather expect if some will find some 'bug ' in code then he
first should understand it
Why bother posting in a public forum if you don't care about people understand what you're on about? Do you not want people to engage?
Then post to alt.test instead.
On 26/10/2026 20:13, fir wrote:
bartc pisze:
On 26/10/2026 19:39, fir wrote:
bartc pisze:
hahaha1 no divides (by 2 or 3)
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
OK, thanks. So the pattern you're talking about is this:
case (c1) {s1}
case (c2) {s2}
case (c3) {s3}
else {s4}
where each of s1/s2/s3 is executed if the corresponding c1/c2/c3 is >>>>> true, independently of the others. At least one statement will be
executed in 7 of the 8 possible boolean combinations in this example. >>>>>
s4 is only executed when each of c1/c2/c3 is false. In other words:
if (c1) {s1}
if (c2) {s2}
if (c3) {s3}
if (!c1 && !c2 && !c3) {s4}
Assuming c1/c2/c3 are not modified by s1/s2/s3, but this is also
partly the case with your proposal.
Or maybe it can be done like this:
if (c1 || c2 || c3) {
s4
else if (c1) {s1)
....
The syntax will anyway need some work to tie all those case/if
parts together (as s2 for example could contain nested versions).
Or you can forget about having to create a hard-to-grasp and
awkward- to-implement feature like this, and either use workarounds >>>>> like my C examples, or use another approach to the problem.
lol ye use worakarounds instead of simple right solution
The right solution to what problem? It took multiple posts before you
even managed to explain how your proposal is supposed to behave.
well i was surprised how slow you think it is the reason you get
things slow - and that s why it took multiple posts
Mainly from you failing to explain? You wrote comments like this:
"this wouldnt work imo as far as im aware becouse this last else dont
work on "group'"
IMO? It either works or it doesn't, and if not, explain why 'or' was not just an alias for 'else'.
and i make laugh becouse its funny how some slowly take some things
and how bad answer thay give - its kinda laughable
Well, this is the thing: given a well-specified, well-thought-out
feature, I can probably implement it in one of my compilers within a day.
That can serve as a proof-of-concept, and can be used to see how well it stands up and how useful it actually is.
This one wouldn't pass that bar. But also, I've not convinced that you
put much thought into it. If I implemented it, you'd change your mind
about it, or add new twists, or get bored and think up something else.
It would be a waste of time.
So what's the purpose of these hundreds of wacky, random ideas: do you expect someone else to implement them for you? If so, in which language?
Today was a bit of fun, but I can't take your ideas seriously.
Today was a bit of fun, but I can't take your ideas seriously.
On 26/10/2026 20:32, fir wrote:
bartc pisze:
There are a couple of reasons to express it in C:OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a real
example.
you cant properly convert this or/and groups to c in good way becouse
there is flaw in c you cannot express all needed combinations
generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}Also, if f1 succeeds, then f2 might not have to be called at all because
Here f1/f2 are called twice. This means making internal copies or
setting flags.
bartc pisze:
Today was a bit of fun, but I can't take your ideas seriously.
definitely was not it was boring and a time waste ..i could do much
btter things
escept maybe cooking this example with if {} or if {} else {}
this example is good as its small and shows the lacks of ifs and elses
logic in c (so its quite otable example)
but besides that it was timewaste
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a real
example.
you cant properly convert this or/and groups to c in good way becouse
there is flaw in c you cannot express all needed combinations
generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
So you call f1 and f2, then call if (!f1() && !f2()) {}. So, that is
your choice. Not the fault of C, right?
On 26/10/2026 20:13, fir wrote:
bartc pisze:
On 26/10/2026 19:39, fir wrote:
bartc pisze:
hahaha1 no divides (by 2 or 3)
2 divides by 2
3 divides by 3
4 divides by 2
5 no divides (by 2 or 3)
6 divides by 2
6 divides by 3
7 no divides (by 2 or 3)
8 divides by 2
9 divides by 3
10 divides by 2
11 no divides (by 2 or 3)
12 divides by 2
12 divides by 3
13 no divides (by 2 or 3)
14 divides by 2
15 divides by 3
16 divides by 2
17 no divides (by 2 or 3)
18 divides by 2
18 divides by 3
19 no divides (by 2 or 3)
OK, thanks. So the pattern you're talking about is this:
case (c1) {s1}
case (c2) {s2}
case (c3) {s3}
else {s4}
where each of s1/s2/s3 is executed if the corresponding c1/c2/c3 is >>>>> true, independently of the others. At least one statement will be
executed in 7 of the 8 possible boolean combinations in this example. >>>>>
s4 is only executed when each of c1/c2/c3 is false. In other words:
if (c1) {s1}
if (c2) {s2}
if (c3) {s3}
if (!c1 && !c2 && !c3) {s4}
Assuming c1/c2/c3 are not modified by s1/s2/s3, but this is also
partly the case with your proposal.
Or maybe it can be done like this:
if (c1 || c2 || c3) {
s4
else if (c1) {s1)
....
The syntax will anyway need some work to tie all those case/if
parts together (as s2 for example could contain nested versions).
Or you can forget about having to create a hard-to-grasp and
awkward- to-implement feature like this, and either use workarounds >>>>> like my C examples, or use another approach to the problem.
lol ye use worakarounds instead of simple right solution
The right solution to what problem? It took multiple posts before you
even managed to explain how your proposal is supposed to behave.
well i was surprised how slow you think it is the reason you get
things slow - and that s why it took multiple posts
Mainly from you failing to explain? You wrote comments like this:
"this wouldnt work imo as far as im aware becouse this last else dont
work on "group'"
IMO? It either works or it doesn't, and if not, explain why 'or' was not just an alias for 'else'.
and i make laugh becouse its funny how some slowly take some things
and how bad answer thay give - its kinda laughable
Well, this is the thing: given a well-specified, well-thought-out
feature, I can probably implement it in one of my compilers within a day.
That can serve as a proof-of-concept, and can be used to see how well it stands up and how useful it actually is.
This one wouldn't pass that bar. But also, I've not convinced that you
put much thought into it. If I implemented it, you'd change your mind
about it, or add new twists, or get bored and think up something else.
It would be a waste of time.
So what's the purpose of these hundreds of wacky, random ideas: do you expect someone else to implement them for you? If so, in which language?
Today was a bit of fun, but I can't take your ideas seriously.
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a real
example.
you cant properly convert this or/and groups to c in good way becouse
there is flaw in c you cannot express all needed combinations
generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
No, the 'if f2(){}' line must be executed whether f1() was true or also.if (!f1() && !f2()) {}Also, if f1 succeeds, then f2 might not have to be called at all because
Here f1/f2 are called twice. This means making internal copies or
setting flags.
it already broke the contract?
On 26/10/2026 21:43, Chris M. Thomasson wrote:
On 10/26/2026 2:11 PM, bartc wrote:No, the 'if f2(){}' line must be executed whether f1() was true or also.
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a real
example.
you cant properly convert this or/and groups to c in good way
becouse there is flaw in c you cannot express all needed
combinations generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}Also, if f1 succeeds, then f2 might not have to be called at all
Here f1/f2 are called twice. This means making internal copies or
setting flags.
because it already broke the contract?
As I understand the feature: they are independent conditional blocks.
But the final else{} must be executed if all were false.
I think if you have to explain it, then it's a bad sign!
On 26/10/2026 21:17, Chris M. Thomasson wrote:
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a real
example.
you cant properly convert this or/and groups to c in good way
becouse there is flaw in c you cannot express all needed
combinations generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
So you call f1 and f2, then call if (!f1() && !f2()) {}. So, that is
your choice. Not the fault of C, right?
It's not the fault of C. But the C illustrates the logic of this new feature: it must only call the 'else' clause when none of the conditions
are true.
But if the most direct way of expressing it has this issue, then extra workarounds are needed, for example:
flag=1;
if f1() {flag=0;...)
if f2() {flag=0;...)
if (flag) {}
(Note the logic here is slightly different: the else block is executed
when none of the previous blocks have been entered. Because conditionals
may have different values at this point. But we don't know the proper
spec.)
This actually isn't too bad, but in that case, why do we even need this
new feature?
My main problem with it is that it is unintuitive and that its use-cases
are limited. It's also likely to morph into something else when fir gets bored with it.
On 26/10/2026 22:50, bartc wrote:
On 26/10/2026 21:17, Chris M. Thomasson wrote:
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a real >>>>>> example.
you cant properly convert this or/and groups to c in good way
becouse there is flaw in c you cannot express all needed
combinations generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
So you call f1 and f2, then call if (!f1() && !f2()) {}. So, that is
your choice. Not the fault of C, right?
It's not the fault of C. But the C illustrates the logic of this new
feature: it must only call the 'else' clause when none of the
conditions are true.
But if the most direct way of expressing it has this issue, then extra
workarounds are needed, for example:
flag=1;
if f1() {flag=0;...)
if f2() {flag=0;...)
if (flag) {}
(Note the logic here is slightly different: the else block is executed
when none of the previous blocks have been entered. Because
conditionals may have different values at this point. But we don't
know the proper spec.)
This actually isn't too bad, but in that case, why do we even need
this new feature?
My main problem with it is that it is unintuitive and that its
use-cases are limited. It's also likely to morph into something else
when fir gets bored with it.
#define fir_switch _Bool flag = 1; {
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it
should at least be called "and_if"), but it comes very close to the
syntax and semantics Fir appears to want.
David Brown pisze:
On 26/10/2026 22:50, bartc wrote:
On 26/10/2026 21:17, Chris M. Thomasson wrote:
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a
real example.
you cant properly convert this or/and groups to c in good way
becouse there is flaw in c you cannot express all needed
combinations generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
So you call f1 and f2, then call if (!f1() && !f2()) {}. So, that is
your choice. Not the fault of C, right?
It's not the fault of C. But the C illustrates the logic of this new
feature: it must only call the 'else' clause when none of the
conditions are true.
But if the most direct way of expressing it has this issue, then
extra workarounds are needed, for example:
flag=1;
if f1() {flag=0;...)
if f2() {flag=0;...)
if (flag) {}
(Note the logic here is slightly different: the else block is
executed when none of the previous blocks have been entered. Because
conditionals may have different values at this point. But we don't
know the proper spec.)
This actually isn't too bad, but in that case, why do we even need
this new feature?
My main problem with it is that it is unintuitive and that its
use-cases are limited. It's also likely to morph into something else
when fir gets bored with it.
#define fir_switch _Bool flag = 1; {
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it
should at least be called "and_if"), but it comes very close to the
syntax and semantics Fir appears to want.
totally no, its not also i want this i just makec conclusion if-else
system is flawed
you may ment it on some ways lik
if {}
or
if {}
else {}
or
case {}
case {}
otherwise {}
in first case you got heneral system of logic operators applied to group
of ifs (coz you may use not olny or but also and or not etc),
in second you got like predefined keywords for "or or or" case
(here in fact otherwise keyword means use or for cases and of 0
evaluate otherwise)
i thing you will nned a general but predefined may be also handy so eventually language could implement both (such as it has many forms for loops to increase intentions readability)
flag is a nonsense its liek implementing else with flag
int not = 1;
if (a>2) {not =0; //...}
if(not) {}
;C
NOTE btw this case not only shows flaw in if rlse system but is just
natural fom of switch (both of them i mean "if or if else" and "case
case otherwise"..and imo thsi form is better than switch as its more
natural its grounded -its also shows lacks of switch so it shows both
if-else system is flawed and switch is flawed too
David Brown pisze:
On 26/10/2026 22:50, bartc wrote:
On 26/10/2026 21:17, Chris M. Thomasson wrote:
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a
real example.
you cant properly convert this or/and groups to c in good way
becouse there is flaw in c you cannot express all needed
combinations generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
So you call f1 and f2, then call if (!f1() && !f2()) {}. So, that is
your choice. Not the fault of C, right?
It's not the fault of C. But the C illustrates the logic of this new
feature: it must only call the 'else' clause when none of the
conditions are true.
But if the most direct way of expressing it has this issue, then
extra workarounds are needed, for example:
flag=1;
if f1() {flag=0;...)
if f2() {flag=0;...)
if (flag) {}
(Note the logic here is slightly different: the else block is
executed when none of the previous blocks have been entered. Because
conditionals may have different values at this point. But we don't
know the proper spec.)
This actually isn't too bad, but in that case, why do we even need
this new feature?
My main problem with it is that it is unintuitive and that its
use-cases are limited. It's also likely to morph into something else
when fir gets bored with it.
#define fir_switch _Bool flag = 1; {
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it
should at least be called "and_if"), but it comes very close to the
syntax and semantics Fir appears to want.
totally no, its not also i want this i just makec conclusion if-else
system is flawed
you may ment it on some ways lik
if {}
or
if {}
else {}
or
case {}
case {}
otherwise {}
in first case you got heneral system of logic operators applied to group
of ifs (coz you may use not olny or but also and or not etc),
in second you got like predefined keywords for "or or or" case
(here in fact otherwise keyword means use or for cases and of 0
evaluate otherwise)
i thing you will nned a general but predefined may be also handy so eventually language could implement both (such as it has many forms for loops to increase intentions readability)
flag is a nonsense its liek implementing else with flag
int not = 1;
if (a>2) {not =0; //...}
if(not) {}
;C
NOTE btw this case not only shows flaw in if rlse system but is just
natural fom of switch (both of them i mean "if or if else" and "case
case otherwise"..and imo thsi form is better than switch as its more
natural its grounded -its also shows lacks of switch so it shows both
if-else system is flawed and switch is flawed too
On 26/10/2026 22:50, bartc wrote:It looks pretty good and it seems to work (the !flag needs the reverse
On 26/10/2026 21:17, Chris M. Thomasson wrote:
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a real >>>>>> example.
you cant properly convert this or/and groups to c in good way
becouse there is flaw in c you cannot express all needed
combinations generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
So you call f1 and f2, then call if (!f1() && !f2()) {}. So, that is
your choice. Not the fault of C, right?
It's not the fault of C. But the C illustrates the logic of this new
feature: it must only call the 'else' clause when none of the
conditions are true.
But if the most direct way of expressing it has this issue, then extra
workarounds are needed, for example:
flag=1;
if f1() {flag=0;...)
if f2() {flag=0;...)
if (flag) {}
(Note the logic here is slightly different: the else block is executed
when none of the previous blocks have been entered. Because
conditionals may have different values at this point. But we don't
know the proper spec.)
This actually isn't too bad, but in that case, why do we even need
this new feature?
My main problem with it is that it is unintuitive and that its use-
cases are limited. It's also likely to morph into something else when
fir gets bored with it.
#define fir_switch _Bool flag = 1; {
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it
should at least be called "and_if"), but it comes very close to the
syntax and semantics Fir appears to want.
On 26/10/2026 22:37, David Brown wrote:
On 26/10/2026 22:50, bartc wrote:It looks pretty good and it seems to work (the !flag needs the reverse logic). The 'and_if' makes more sense too.
On 26/10/2026 21:17, Chris M. Thomasson wrote:
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a
real example.
you cant properly convert this or/and groups to c in good way
becouse there is flaw in c you cannot express all needed
combinations generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
So you call f1 and f2, then call if (!f1() && !f2()) {}. So, that is
your choice. Not the fault of C, right?
It's not the fault of C. But the C illustrates the logic of this new
feature: it must only call the 'else' clause when none of the
conditions are true.
But if the most direct way of expressing it has this issue, then
extra workarounds are needed, for example:
flag=1;
if f1() {flag=0;...)
if f2() {flag=0;...)
if (flag) {}
(Note the logic here is slightly different: the else block is
executed when none of the previous blocks have been entered. Because
conditionals may have different values at this point. But we don't
know the proper spec.)
This actually isn't too bad, but in that case, why do we even need
this new feature?
My main problem with it is that it is unintuitive and that its use-
cases are limited. It's also likely to morph into something else when
fir gets bored with it.
#define fir_switch _Bool flag = 1; {
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it
should at least be called "and_if"), but it comes very close to the
syntax and semantics Fir appears to want.
But of course it's not good enough for fir; there's always something.
On 10/5/2026 4:11 PM, bart wrote:
On 05/10/2026 22:48, Kaz Kylheku wrote:
On 2026-10-05, bart <[email protected]> wrote:
A lot of what big compilers do is what used to be called 'linting'.
I don't suspect you can get rid of that in any language.
The reason is that as experience with the given language grows, it is
found that programmers make certain mistakes, where making formal
syntactic and semantic rules against those mistakes, and sticking
them into the language, would be a poor idea.
At some point, you are trying to design a pencil that cannot be
used to draw an optical illusion.
I don't consider that to be their job, which should be to verify my
program and turn it into runnable code, and not give opinions.
That's a waste of potential; why would you refuse a machine that
can apply hundreds of deterministic pattern matching rules against
possible trouble situations in hundreds of thousands of lines of code,
in seconds.
I simply don't care about it. I don't have seconds to waste either.
Why not?
[...]
On 07/10/2026 22:06, Chris M. Thomasson wrote:
On 10/7/2026 5:52 AM, bart wrote:
On 07/10/2026 01:42, Kaz Kylheku wrote:
On 2026-10-05, bart <[email protected]> wrote:
On 05/10/2026 22:48, Kaz Kylheku wrote:
On 2026-10-05, bart <[email protected]> wrote:
A lot of what big compilers do is what used to be called 'linting'. >>>>>>I don't suspect you can get rid of that in any language.
The reason is that as experience with the given language grows, it is >>>>>> found that programmers make certain mistakes, where making formal
syntactic and semantic rules against those mistakes, and sticking
them into the language, would be a poor idea.
At some point, you are trying to design a pencil that cannot be
used to draw an optical illusion.
I don't consider that to be their job, which should be to verify my >>>>>>> program and turn it into runnable code, and not give opinions.
That's a waste of potential; why would you refuse a machine that
can apply hundreds of deterministic pattern matching rules against >>>>>> possible trouble situations in hundreds of thousands of lines of
code,
in seconds.
I simply don't care about it. I don't have seconds to waste either.
Your implementation of the same thing would take milliseconds, of
course.
I wouldn't want it at all.
But if I had to implement it, I don't know how long it would take. If
I found that it was taking disproportionately long (compared to the
main task of generating a binary), then I would separate it out from
the compiler, as I've suggested.
For example, if 90% of compile-time was spent on it.
Here are some common C-compiling scenarios:
* You want to build a finished, working, debugged program from source. >>>>> This does need the compiler spending time double-guessing the >>>>> author's
intentions, and in any case the person building it is not going to >>>>> mess with the source
* You are building a program which is machine-transpiled C code. It
should be valid C with no errors. (If there are, that is the
responsibility of the transpiler author.) But again you don't care >>>>> about style, or the fact that there are lots of unused labels for >>>>> example (common in such code)
Then
* you still want linting in the source language.
Possibly. I don't care too much about that either. In my stuff, I do
very little in the way of advisory reports, which are only enabled
infrequently.
But the context here is using linting to warn about things that are a
consequence of C's design, such as switch 'break' that is the subject
of the thread.
I prefer to deal with that with a better language design.
Are you making a "new" C?[...]
I'm not making anything.
I have long maintained a personal systems language which fixes most of
my moans about C (and even deals with some of fir's needs, but those
seem to change erratically).
It would have been good for /someone else/ to have evolved C in a
direction I'd have found useful, but current evolvement of C is not interesting to me and IMO misguided.
Since I have my own solutions for the little coding I do now, this
doesn't matter so much - let C aficionados be masochists if they want.
But I am still interested in tooling (which has its own masochists!).
On 07/10/2026 01:45, Lawrence D’Oliveiro wrote:
On Tue, 6 Oct 2026 16:08:25 -0700, Chris M. Thomasson wrote:
On 10/6/2026 3:41 AM, David Brown wrote:
Anyone who sometimes makes mistakes should enable warnings. And
that means /everyone/ should enable copious warnings.
Coin that!
Then there is “confirmation fatigue”, where you get too inured to
ignoring spurious warnings, and miss the important one(s) in among the
noise.
Enabling lots of warning options does not mean triggering lots of warnings!
I don’t think there is any idiot-proof way to avoid being an idiot ...
On 26/10/2026 22:37, David Brown wrote:
On 26/10/2026 22:50, bartc wrote:It looks pretty good and it seems to work (the !flag needs the reverse logic). The 'and_if' makes more sense too.
On 26/10/2026 21:17, Chris M. Thomasson wrote:
On 10/26/2026 2:11 PM, bartc wrote:
On 26/10/2026 20:32, fir wrote:
bartc pisze:There are a couple of reasons to express it in C:
OK, try a simple experiment: convert some code using your 'or'
keyword to regular C syntax and post it here. Preferably on a
real example.
you cant properly convert this or/and groups to c in good way
becouse there is flaw in c you cannot express all needed
combinations generally with sole if 's and else's
as was showed here
* To illustrate exactly how you want the semantics to work, via
an existing language whose behaviour is well known
* To highlight the problem areas
For example:
if (f1()) {}
if (f2()) {}
...
if (!f1() && !f2()) {}
Here f1/f2 are called twice. This means making internal copies or
setting flags.
So you call f1 and f2, then call if (!f1() && !f2()) {}. So, that is
your choice. Not the fault of C, right?
It's not the fault of C. But the C illustrates the logic of this new
feature: it must only call the 'else' clause when none of the
conditions are true.
But if the most direct way of expressing it has this issue, then
extra workarounds are needed, for example:
flag=1;
if f1() {flag=0;...)
if f2() {flag=0;...)
if (flag) {}
(Note the logic here is slightly different: the else block is
executed when none of the previous blocks have been entered. Because
conditionals may have different values at this point. But we don't
know the proper spec.)
This actually isn't too bad, but in that case, why do we even need
this new feature?
My main problem with it is that it is unintuitive and that its use-
cases are limited. It's also likely to morph into something else when
fir gets bored with it.
#define fir_switch _Bool flag = 1; {
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it
should at least be called "and_if"), but it comes very close to the
syntax and semantics Fir appears to want.
But of course it's not good enough for fir; there's always something.
if(x>0) printf("right"); and if(x<w) printf("left"); else printf(" outside");
On 10/26/2026 2:40 PM, fir wrote:
bartc pisze:
Today was a bit of fun, but I can't take your ideas seriously.
definitely was not it was boring and a time waste ..i could do much
btter things
escept maybe cooking this example with if {} or if {} else {}
this example is good as its small and shows the lacks of ifs and elses
logic in c (so its quite otable example)
but besides that it was timewaste
Why are you wasting your time here on comp.lang.c?
bartc pisze:
On 26/10/2026 22:37, David Brown wrote:
#define fir_switch _Bool flag = 1; {It looks pretty good and it seems to work (the !flag needs the reverse
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it
should at least be called "and_if"), but it comes very close to the
syntax and semantics Fir appears to want.
logic). The 'and_if' makes more sense too.
But of course it's not good enough for fir; there's always something.
blame the scienco fo doing just like tat
(one solution is a solution untill you find better one) ..im just doing science here so its science to blame, i got no problem with that
On 27/10/2026 08:37, fir wrote:
bartc pisze:
On 26/10/2026 22:37, David Brown wrote:
#define fir_switch _Bool flag = 1; {It looks pretty good and it seems to work (the !flag needs the
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it
should at least be called "and_if"), but it comes very close to the
syntax and semantics Fir appears to want.
reverse logic). The 'and_if' makes more sense too.
But of course it's not good enough for fir; there's always something.
blame the scienco fo doing just like tat
(one solution is a solution untill you find better one) ..im just
doing science here so its science to blame, i got no problem with that
I've no idea what you mean. And I've no idea what it is you're actually after. I doubt anyone has. I doubt /you/ do!
You suggest some new statement type, in a C language forum, somebody
shows how to implement it in standard C, but your response is:
"blame the scienco fo doing just like tat"
Not:
"Wow, thanks! That's perfect."
My guess is that you're not interested in actual solutions. You're just thinking up one random idea after another. You don't care for anyone
else's opinion or input.
bartc pisze:
On 27/10/2026 08:37, fir wrote:as to ideas I got an idea. Is your goal to stir up trouble here
bartc pisze:
On 26/10/2026 22:37, David Brown wrote:
#define fir_switch _Bool flag = 1; {It looks pretty good and it seems to work (the !flag needs the
#define or_if(...) } if (__VA_ARGS__) { flag = 0;
#define otherwise } if (!flag)
Then Fir can write :
fir_switch
or_if (x % 2 == 0) printf("\n divides by 2");
or_if (x % 3 == 0) printf("\n divides by 3");
otherwise printf("\n does not divide by 2 or 3");
I haven't tested the defines, and I think it is a terrible idea (it >>>>> should at least be called "and_if"), but it comes very close to the >>>>> syntax and semantics Fir appears to want.
reverse logic). The 'and_if' makes more sense too.
But of course it's not good enough for fir; there's always something.
blame the scienco fo doing just like tat
(one solution is a solution untill you find better one) ..im just
doing science here so its science to blame, i got no problem with that
I've no idea what you mean. And I've no idea what it is you're
actually after. I doubt anyone has. I doubt /you/ do!
You suggest some new statement type, in a C language forum, somebody
shows how to implement it in standard C, but your response is:
"blame the scienco fo doing just like tat"
Not:
"Wow, thanks! That's perfect."
My guess is that you're not interested in actual solutions. You're
just thinking up one random idea after another. You don't care for
anyone else's opinion or input.
coz what yu say is like that and this is making bad content here
science does that science is finding a solution then it finds another solution so you may blame science and say you got idea what science is actually after
im just doin science - come to some conclusions than after that come to another conclusion...
why your should problems with science should interest me? im here for
doin science not to analyse personal problems of clc users
bartc pisze:
On 27/10/2026 08:37, fir wrote:
blame the scienco fo doing just like tat
(one solution is a solution untill you find better one) ..im just
doing science here so its science to blame, i got no problem with that
I've no idea what you mean. And I've no idea what it is you're
actually after. I doubt anyone has. I doubt /you/ do!
You suggest some new statement type, in a C language forum, somebody
shows how to implement it in standard C, but your response is:
"blame the scienco fo doing just like tat"
Not:
"Wow, thanks! That's perfect."
My guess is that you're not interested in actual solutions. You're
just thinking up one random idea after another. You don't care for
anyone else's opinion or input.
coz what yu say is like that and this is making bad content here
science does that science is finding a solution then it finds another solution so you may blame science and say you got idea what science is actually after
im just doin science - come to some conclusions than after that come to another conclusion...posting reams of it in comp.lang.c as though it was your personal blog.
why your should problems with science should interest me? im here for
doin science not to analyse personal problems of clc usersYour 'science' seems to be writing mostly meaningless drivel and then
On 27/10/2026 11:57, fir wrote:
bartc pisze:
On 27/10/2026 08:37, fir wrote:
blame the scienco fo doing just like tat
(one solution is a solution untill you find better one) ..im just
doing science here so its science to blame, i got no problem with that
I've no idea what you mean. And I've no idea what it is you're
actually after. I doubt anyone has. I doubt /you/ do!
You suggest some new statement type, in a C language forum, somebody
shows how to implement it in standard C, but your response is:
"blame the scienco fo doing just like tat"
Not:
"Wow, thanks! That's perfect."
My guess is that you're not interested in actual solutions. You're
just thinking up one random idea after another. You don't care for
anyone else's opinion or input.
coz what yu say is like that and this is making bad content hereposting reams of it in comp.lang.c as though it was your personal blog.
science does that science is finding a solution then it finds another
solution so you may blame science and say you got idea what science is
actually after
im just doin science - come to some conclusions than after that come
to another conclusion...
why your should problems with science should interest me? im here for
doin science not to analyse personal problems of clc usersYour
'science' seems to be writing mostly meaningless drivel and then
You don't seem to expect any feedback either, and tend to attack people
who offer opinions or try to make sense of some of your ideas.
I should have known from past experience that that never ends well.
'There's always something'.
bartc pisze:
On 27/10/2026 11:57, fir wrote:
bartc pisze:posting reams of it in comp.lang.c as though it was your personal blog.
On 27/10/2026 08:37, fir wrote:
blame the scienco fo doing just like tatI've no idea what you mean. And I've no idea what it is you're
(one solution is a solution untill you find better one) ..im just
doing science here so its science to blame, i got no problem with that >>>>
actually after. I doubt anyone has. I doubt /you/ do!
You suggest some new statement type, in a C language forum, somebody
shows how to implement it in standard C, but your response is:
"blame the scienco fo doing just like tat"
Not:
"Wow, thanks! That's perfect."
My guess is that you're not interested in actual solutions. You're
just thinking up one random idea after another. You don't care for
anyone else's opinion or input.
coz what yu say is like that and this is making bad content here
science does that science is finding a solution then it finds another
solution so you may blame science and say you got idea what science
is actually after
im just doin science - come to some conclusions than after that come
to another conclusion...
why your should problems with science should interest me? im here for
doin science not to analyse personal problems of clc usersYour
'science' seems to be writing mostly meaningless drivel and then
You don't seem to expect any feedback either, and tend to attack
people who offer opinions or try to make sense of some of your ideas.
I should have known from past experience that that never ends well.
'There's always something'.
im not posting as personal blog and i answe a lot... the problem is you should first make soem work and understand what im talkin about and then answer it not just "i dont understand it so i will make z 10 hours of
foam here"
imagine what would come if anybody would start doing that agains ant
book move piece of science in book etc...
the amounts of foam would cover the sun :/ that would be word of foam
On 27/10/2026 11:57, fir wrote:
bartc pisze:
On 27/10/2026 08:37, fir wrote:
blame the scienco fo doing just like tat
(one solution is a solution untill you find better one) ..im just
doing science here so its science to blame, i got no problem with that
I've no idea what you mean. And I've no idea what it is you're
actually after. I doubt anyone has. I doubt /you/ do!
You suggest some new statement type, in a C language forum, somebody
shows how to implement it in standard C, but your response is:
"blame the scienco fo doing just like tat"
Not:
"Wow, thanks! That's perfect."
My guess is that you're not interested in actual solutions. You're
just thinking up one random idea after another. You don't care for
anyone else's opinion or input.
coz what yu say is like that and this is making bad content hereposting reams of it in comp.lang.c as though it was your personal blog.
science does that science is finding a solution then it finds another
solution so you may blame science and say you got idea what science is
actually after
im just doin science - come to some conclusions than after that come
to another conclusion...
why your should problems with science should interest me? im here for
doin science not to analyse personal problems of clc usersYour
'science' seems to be writing mostly meaningless drivel and then
You don't seem to expect any feedback either, and tend to attack people
who offer opinions or try to make sense of some of your ideas.
I should have known from past experience that that never ends well.
'There's always something'.
| Sysop: | DaiTengu |
|---|---|
| Location: | Appleton, WI |
| Users: | 1,142 |
| Nodes: | 10 (0 / 10) |
| Uptime: | 135:29:16 |
| Calls: | 14,707 |
| Calls today: | 1 |
| Files: | 186,498 |
| D/L today: |
1,120 files (344M bytes) |
| Messages: | 2,552,863 |