Sysop: | Amessyroom |
---|---|
Location: | Fayetteville, NC |
Users: | 43 |
Nodes: | 6 (0 / 6) |
Uptime: | 94:08:43 |
Calls: | 290 |
Calls today: | 1 |
Files: | 904 |
Messages: | 76,378 |
Michael S <already5chosen@yahoo.com> writes:
On Wed, 11 Dec 2024 17:27:53 -0800
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
[...]
My experience of multi-level break is that there are two main
use-cases:
* Used in the current loop only (not necessarily the innermost to
an observer). This is the most common
* Used to exit the outermost loop
So to support these, named or even numbered loops are not
necessary. (Eg. I use 'exit' or 'exit all'.)
I would oppose a change to C that only applied to innermost and
outermost loops. For one thing, I'm not aware of any other language
that does this (except perhaps your unnamed one). For another,
it's easy enough to define a feature that handles any arbitrary
nesting levels, by applying names (labels) to loops.
The better solution is education.
Convince teachers in unis and colleges that goto is *not* considered
harmful for this particular use case. Convince them to teach that
attempts to avoid goto [for this particular use case] are really
considered harmful. If you don't believe in authority of yourself then
ask for help from somebody famous that share this view. I would guess
that nearly all famous C programmers share it.
Backward gotos tend to be dangerous. Forward gotos are less so.
Michael S <already5chosen@yahoo.com> writes:
On Wed, 11 Dec 2024 17:27:53 -0800
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
[...]
My experience of multi-level break is that there are two main
use-cases:
* Used in the current loop only (not necessarily the innermost to
an observer). This is the most common
* Used to exit the outermost loop
So to support these, named or even numbered loops are not
necessary. (Eg. I use 'exit' or 'exit all'.)
I would oppose a change to C that only applied to innermost and
outermost loops. For one thing, I'm not aware of any other language
that does this (except perhaps your unnamed one). For another,
it's easy enough to define a feature that handles any arbitrary
nesting levels, by applying names (labels) to loops.
The better solution is education.
Convince teachers in unis and colleges that goto is *not* considered
harmful for this particular use case. Convince them to teach that
attempts to avoid goto [for this particular use case] are really
considered harmful. If you don't believe in authority of yourself then
ask for help from somebody famous that share this view. I would guess
that nearly all famous C programmers share it.
Backward gotos tend to be dangerous. Forward gotos are less so.
Dijkstras original "Go To Statement Considered Harmful" letter was
written in 1968, at a time when many languages didn't necessarily
have the structured control constructs we've come to expect since
then. Using goto to implement a loop is almost always a bad idea,
but it's something that a modern C programmer probably wouldn't
even consider doing.
I agree that gotos have valid uses.
Here's an answer I wrote on Stack Exchange some years ago to the
question "Is using goto ever worthwhile?" : https://softwareengineering.stackexchange.com/a/133523/33478
Quoting from that answer :
The main use of a goto in a reasonably modern language (one that
supports if/else and loops) is to simulate a control flow construct
that's missing from the language.
I would support adding named loops and labeled exit/continue to
a future version of C. I've used languages that have similar
features, and have found them very useful. Given that C doesn't
have multi-level break, I tend to agree that a goto statement is a
reasonable way to simulate it, often better than the alternatives.
(It's important to use a meaningful label name.) Similarly,
the C code in the Linux kernel makes extensive use of gotos for
error handling.
If C didn't have a break statement at all, it could be simulated
with goto. If that were the case, I'd still favor adding a break
statement to the language. I support adding labeled break statements
for the same reason. Goto is not the root of all evil, but it's
worth some effort to avoid it when other constructs are clearer.
On 12/12/2024 22:50, Keith Thompson wrote:
Michael S <already5chosen@yahoo.com> writes:
On Wed, 11 Dec 2024 17:27:53 -0800
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
[...]
My experience of multi-level break is that there are two main
use-cases:
* Used in the current loop only (not necessarily the innermost to >>>>> an observer). This is the most common
* Used to exit the outermost loop
So to support these, named or even numbered loops are not
necessary. (Eg. I use 'exit' or 'exit all'.)
I would oppose a change to C that only applied to innermost and
outermost loops. For one thing, I'm not aware of any other language
that does this (except perhaps your unnamed one). For another,
it's easy enough to define a feature that handles any arbitrary
nesting levels, by applying names (labels) to loops.
The better solution is education.
Convince teachers in unis and colleges that goto is *not* considered
harmful for this particular use case. Convince them to teach that
attempts to avoid goto [for this particular use case] are really
considered harmful. If you don't believe in authority of yourself then
ask for help from somebody famous that share this view. I would guess
that nearly all famous C programmers share it.
Backward gotos tend to be dangerous. Forward gotos are less so.
Dijkstras original "Go To Statement Considered Harmful" letter was
written in 1968, at a time when many languages didn't necessarily
have the structured control constructs we've come to expect since
then. Using goto to implement a loop is almost always a bad idea,
but it's something that a modern C programmer probably wouldn't
even consider doing.
I agree that gotos have valid uses.
Here's an answer I wrote on Stack Exchange some years ago to the
question "Is using goto ever worthwhile?" :
https://softwareengineering.stackexchange.com/a/133523/33478
Quoting from that answer :
The main use of a goto in a reasonably modern language (one that
supports if/else and loops) is to simulate a control flow construct >> that's missing from the language.
I would support adding named loops and labeled exit/continue to
a future version of C. I've used languages that have similar
features, and have found them very useful. Given that C doesn't
have multi-level break, I tend to agree that a goto statement is a
reasonable way to simulate it, often better than the alternatives.
(It's important to use a meaningful label name.) Similarly,
the C code in the Linux kernel makes extensive use of gotos for
error handling.
If C didn't have a break statement at all, it could be simulated
with goto. If that were the case, I'd still favor adding a break
statement to the language. I support adding labeled break statements
for the same reason. Goto is not the root of all evil, but it's
worth some effort to avoid it when other constructs are clearer.
I personally have found "goto" in C to be useful on no more than a
couple of occasions during my entire career. I'd find a labelled
"break;" statement somewhat more useful - but I think I can confidently
say I would never want to use some kind of relative numbered "break 2;"
or similar statement. Such multi-level breaks would be far too rare in
code for people to interpret "automatically" - many programmers would
need to think hard about whether the number is from the outside in, or
inside out, and starting from 0 or starting from 1. A labelled break
would be vastly clearer.
If I find I have such complicated loops and need to break out of them, I
will sometimes use local boolean flags - that gives you a convenient
place to give a name to the condition, and the compiler turns it all
into "gotos" in the generated code. Alternatively, the function can be split up - multi-level "break" from the inner loop is now just a
"return" from the "inner" function. This would be neater if C supported nested functions of some sort - perhaps a restricted form of lambdas.
(For C, it would be natural to limit these to cases where there is never
a closure object created.)
Some people don't like ordinary break either. There you could also
suggest using convoluted logic, or using a function instead But here
'break' would be clearly be simpler and easier.
(I'd like to see a lambda example that is simpler than a two-level
break or even a goto.)
I've had a quick look through my codebases (not C), and I couldn't
see an example of a numbered break. All I could find was the
equivalant of:
break # the vast majority
break all
The latter breaks out of the outermost loop.
On Fri, 13 Dec 2024 11:12:13 +0000
bart <bc@freeuk.com> wrote:
Some people don't like ordinary break either. There you could also
suggest using convoluted logic, or using a function instead But here
'break' would be clearly be simpler and easier.
Agreed.
(I'd like to see a lambda example that is simpler than a two-level
break or even a goto.)
It would not be simpler than goto, but a little easier to follow.
Relatively to two-level break, it's more general. Suppose, you have 3
levels of nested loops. Two-level break does not help for breaking
out of innermost loop *into* outermost loop.
The problem with lambda in this role is that it would be an overkill.
Also if one wants simplicity of writing then David's suggestion for
lambda without capture is not sufficient. On the other hand, lambda
with capture of full environment by reference is very easy to write,
but potentially very hard to follow and error-prone.
I am strictly inclined to think that goto is better than all
alternatives proposed so far.
I've had a quick look through my codebases (not C), and I couldn't
see an example of a numbered break. All I could find was the
equivalant of:
break # the vast majority
break all
The latter breaks out of the outermost loop.
For the reason explained above I don't like 'break all' idea.
On 13/12/2024 08:50, David Brown wrote:
On 12/12/2024 22:50, Keith Thompson wrote:
Michael S <already5chosen@yahoo.com> writes:
On Wed, 11 Dec 2024 17:27:53 -0800
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
[...]
My experience of multi-level break is that there are two main
use-cases:
* Used in the current loop only (not necessarily the innermost to >>>>>> an observer). This is the most common
* Used to exit the outermost loop
So to support these, named or even numbered loops are not
necessary. (Eg. I use 'exit' or 'exit all'.)
I would oppose a change to C that only applied to innermost and
outermost loops. For one thing, I'm not aware of any other language >>>>> that does this (except perhaps your unnamed one). For another,
it's easy enough to define a feature that handles any arbitrary
nesting levels, by applying names (labels) to loops.
The better solution is education.
Convince teachers in unis and colleges that goto is *not* considered
harmful for this particular use case. Convince them to teach that
attempts to avoid goto [for this particular use case] are really
considered harmful. If you don't believe in authority of yourself then >>>> ask for help from somebody famous that share this view. I would guess
that nearly all famous C programmers share it.
Backward gotos tend to be dangerous. Forward gotos are less so.
Dijkstras original "Go To Statement Considered Harmful" letter was
written in 1968, at a time when many languages didn't necessarily
have the structured control constructs we've come to expect since
then. Using goto to implement a loop is almost always a bad idea,
but it's something that a modern C programmer probably wouldn't
even consider doing.
I agree that gotos have valid uses.
Here's an answer I wrote on Stack Exchange some years ago to the
question "Is using goto ever worthwhile?" :
https://softwareengineering.stackexchange.com/a/133523/33478
Quoting from that answer :
The main use of a goto in a reasonably modern language (one that >>> supports if/else and loops) is to simulate a control flow construct
that's missing from the language.
I would support adding named loops and labeled exit/continue to
a future version of C. I've used languages that have similar
features, and have found them very useful. Given that C doesn't
have multi-level break, I tend to agree that a goto statement is a
reasonable way to simulate it, often better than the alternatives.
(It's important to use a meaningful label name.) Similarly,
the C code in the Linux kernel makes extensive use of gotos for
error handling.
If C didn't have a break statement at all, it could be simulated
with goto. If that were the case, I'd still favor adding a break
statement to the language. I support adding labeled break statements
for the same reason. Goto is not the root of all evil, but it's
worth some effort to avoid it when other constructs are clearer.
I personally have found "goto" in C to be useful on no more than a
couple of occasions during my entire career. I'd find a labelled
"break;" statement somewhat more useful - but I think I can
confidently say I would never want to use some kind of relative
numbered "break 2;" or similar statement. Such multi-level breaks
would be far too rare in code for people to interpret "automatically"
- many programmers would need to think hard about whether the number
is from the outside in, or inside out, and starting from 0 or starting
from 1. A labelled break would be vastly clearer.
If I find I have such complicated loops and need to break out of them,
I will sometimes use local boolean flags - that gives you a convenient
place to give a name to the condition, and the compiler turns it all
into "gotos" in the generated code. Alternatively, the function can
be split up - multi-level "break" from the inner loop is now just a
"return" from the "inner" function. This would be neater if C
supported nested functions of some sort - perhaps a restricted form of
lambdas. (For C, it would be natural to limit these to cases where
there is never a closure object created.)
Some people don't like ordinary break either. There you could also
suggest using convoluted logic, or using a function instead But here
'break' would be clearly be simpler and easier.
(I'd like to see a lambda example that is simpler than a two-level break
or even a goto.)
I've had a quick look through my codebases (not C), and I couldn't see
an example of a numbered break. All I could find was the equivalant of:
break # the vast majority
break all
The latter breaks out of the outermost loop.
Backward gotos tend to be dangerous. Forward gotos are less so.
Dijkstras original "Go To Statement Considered Harmful" letter was
written in 1968, at a time when many languages didn't necessarily
have the structured control constructs we've come to expect since
then. Using goto to implement a loop is almost always a bad idea,
but it's something that a modern C programmer probably wouldn't
even consider doing.
I agree that gotos have valid uses.
Here's an answer I wrote on Stack Exchange some years ago to the
question "Is using goto ever worthwhile?" :
[...]
I would support adding named loops and labeled exit/continue to
a future version of C. I've used languages that have similar
features, and have found them very useful. Given that C doesn't
have multi-level break, I tend to agree that a goto statement is a
reasonable way to simulate it, often better than the alternatives.
[...]
Here's an example of a small C program that completely avoids the
use of goto statements. I reserve the right to ridicule anyone who
takes this program seriously.
[ source code with lots of setjmp/longjmp ]
On 12/12/2024 22:50, Keith Thompson wrote:
Michael S <already5chosen@yahoo.com> writes:
On Wed, 11 Dec 2024 17:27:53 -0800
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
[...]
My experience of multi-level break is that there are two main
use-cases:
* Used in the current loop only (not necessarily the innermost to
an observer). This is the most common
* Used to exit the outermost loop
So to support these, named or even numbered loops are not
necessary. (Eg. I use 'exit' or 'exit all'.)
I would oppose a change to C that only applied to innermost and
outermost loops. For one thing, I'm not aware of any other language
that does this (except perhaps your unnamed one). For another,
it's easy enough to define a feature that handles any arbitrary
nesting levels, by applying names (labels) to loops.
The better solution is education.
Convince teachers in unis and colleges that goto is *not* considered
harmful for this particular use case. Convince them to teach that
attempts to avoid goto [for this particular use case] are really
considered harmful. If you don't believe in authority of yourself then
ask for help from somebody famous that share this view. I would guess
that nearly all famous C programmers share it.
Backward gotos tend to be dangerous. Forward gotos are less so.
Dijkstras original "Go To Statement Considered Harmful" letter was
written in 1968, at a time when many languages didn't necessarily
have the structured control constructs we've come to expect since
then. Using goto to implement a loop is almost always a bad idea,
but it's something that a modern C programmer probably wouldn't
even consider doing.
I agree that gotos have valid uses.
Here's an answer I wrote on Stack Exchange some years ago to the
question "Is using goto ever worthwhile?" :
https://softwareengineering.stackexchange.com/a/133523/33478
Quoting from that answer :
The main use of a goto in a reasonably modern language (one that
supports if/else and loops) is to simulate a control flow construct
that's missing from the language.
I would support adding named loops and labeled exit/continue to
a future version of C. I've used languages that have similar
features, and have found them very useful. Given that C doesn't
have multi-level break, I tend to agree that a goto statement is a
reasonable way to simulate it, often better than the alternatives.
(It's important to use a meaningful label name.) Similarly,
the C code in the Linux kernel makes extensive use of gotos for
error handling.
If C didn't have a break statement at all, it could be simulated
with goto. If that were the case, I'd still favor adding a break
statement to the language. I support adding labeled break statements
for the same reason. Goto is not the root of all evil, but it's
worth some effort to avoid it when other constructs are clearer.
I personally have found "goto" in C to be useful on no more than a
couple of occasions during my entire career. I'd find a labelled
"break;" statement somewhat more useful - but I think I can confidently
say I would never want to use some kind of relative numbered "break 2;"
or similar statement. Such multi-level breaks would be far too rare in
code for people to interpret "automatically" - many programmers would
need to think hard about whether the number is from the outside in, or
inside out, and starting from 0 or starting from 1. A labelled break
would be vastly clearer.
On 13/12/2024 12:12, bart wrote:
Some people don't like ordinary break either. There you could also
suggest using convoluted logic, or using a function instead But here
'break' would be clearly be simpler and easier.
I can only express my own opinion - if someone else doesn't like
"break;", that's up to them.
(I'd like to see a lambda example that is simpler than a two-level
break or even a goto.)
<https://godbolt.org/z/7qWf966Er>
There is a simple three-level nested loop function with an "escape" from
the inside loop, written in several different ways. There is somewhat arbitrary calculations before and after the loops, so that the it can't
just use a direct "return" from the middle of the loop - it needs some
kind of multi-level break effect when "test(x, y, z)" passes.
The
lambda version code is C++, since that has lambdas and C doesn't, but
the rest can be compiled as C or C++.
(I've also used C++ tuples for returning multiple values.
I haven't compared to a multi-level break statement, because neither C
nor C++ have such a feature (as yet).
The other big advantage of the "static inner function" version (valid C)
and the lambda version (C++ only - though lambdas are being considered
for C) is that it is immediately obvious when writing them that there is
a huge difference between breaking out of the loops when the test
passes, and falling off the end of the loops because the test never
passes. I've been lazy in this example, but you can't miss it - with
the goto to break versions, it's easily forgotten.
return std::tuple(n, n, n);
I've had a quick look through my codebases (not C), and I couldn't see
an example of a numbered break. All I could find was the equivalant of:
break # the vast majority
break all
The latter breaks out of the outermost loop.
So you have a feature (numbered breaks) in your language that you never
use, but have been recommending here as a useful addition to C?
On 13/12/2024 13:19, David Brown wrote:
On 13/12/2024 12:12, bart wrote:
Some people don't like ordinary break either. There you could also
suggest using convoluted logic, or using a function instead But here
'break' would be clearly be simpler and easier.
I can only express my own opinion - if someone else doesn't like
"break;", that's up to them.
(I'd like to see a lambda example that is simpler than a two-level
break or even a goto.)
<https://godbolt.org/z/7qWf966Er>
There is a simple three-level nested loop function with an "escape"
from the inside loop, written in several different ways. There is
somewhat arbitrary calculations before and after the loops, so that
the it can't just use a direct "return" from the middle of the loop -
it needs some kind of multi-level break effect when "test(x, y, z)"
passes.
The lambda version code is C++, since that has lambdas and C
doesn't, but the rest can be compiled as C or C++.
The lambda version needs closures from what I can see, although that
might be optimised out.
(I've also used C++ tuples for returning multiple values.
From that 'inner' function presumably; the main one returns one value.
I haven't compared to a multi-level break statement, because neither C
nor C++ have such a feature (as yet).
I've written a version in my syntax below, with some comments.
The other big advantage of the "static inner function" version (valid
C) and the lambda version (C++ only - though lambdas are being
considered for C) is that it is immediately obvious when writing them
that there is a huge difference between breaking out of the loops when
the test passes, and falling off the end of the loops because the test
never passes. I've been lazy in this example, but you can't miss it -
with the goto to break versions, it's easily forgotten.
Do you mean this line:
return std::tuple(n, n, n);
Because even without it, it seems to work for M=10 (when the break is commented out). That is, it gives the same result on versions that just
fall off the end of the outer loop.
I've had a quick look through my codebases (not C), and I couldn't
see an example of a numbered break. All I could find was the
equivalant of:
break # the vast majority
break all
The latter breaks out of the outermost loop.
So you have a feature (numbered breaks) in your language that you
never use, but have been recommending here as a useful addition to C?
I'm saying that if you don't have the general feature, then the more
limited one might be worth considering, as it will take care of most of
the use-cases not covered by break.
(My personal codebase is not expansive enough to definitely say
intermediate breaks will be never needed, or very rarely. Others may use nested loops a lot more.)
--------------------------
fun test(int x, y, z)bool = sqr(x)+sqr(y) = sqr(z)
func foo(int n)int =
for x in 2..n do
for y in 2..n do
for z in 2..n do
exit all when test(x,y,z)
od
od
od
x*10000 + y*100 + z
end
proc main=
println foo(10)
end
--------------------------
Notes:
* Your version seems to convert from 1- to 0-based; I reversed that. But
that might have been to inject some extra code outside the loops
* Despite what you say, such a example could easily just return from
inside the loop. So the example is just to illustrate multi-level
break
* (If this is supposed to find Pythagorean triples, those loops could be
shorter)
* The program size in bytes is here half the size of your foo5() example
in C++ (with other functions and cplusplus blocks removed). (288 vs
570 bytes)
* I tried your foo5 version in my dynamic language. There I found some
scoping issues that I'd need to fix. Putting workarounds in, plus
that extra return after the loops, made it much busier than my static
version. That language of course runs the simple version too, and is
somewhat shorter.