bart <
bc@freeuk.com> writes:
On 12/12/2024 01:27, Keith Thompson wrote:
[...]
I'm not sure what you mean by "relative". Do you have an example?
If, say, I have a "break 2" statement (the Bourne shell uses that
syntax), and I wanted to refactor the code, I'll at least have
to pay very close attention to the number, and likely change it.
Is that what you mean by "relative"? If I have "break NAME", it's
more likely that I won't have to change it. (Disclaimer: I don't
think I've ever used the "break N" feature of the Bourne shell.)
>
Take these two loops:
>
loop A: {
loop B: {
break A // absolute
break +1; // relative
}
}
>
The two breaks in the inner one both break out of the outer loop. The
relative one uses an index counting outwards.
I would not want a break statement that takes a count, but if it were
to be added to the language, I'd want it to follow the precedent set
by the Bourne and similar shells, where "break N" breaks N enclosing
loops, 1 by default. Your "break +1;" would then be "break 2;";
"break 1;" or "break +1;" would be equivalent to "break;".
Now suppose you add a third loop C in between A and B. Those two
breaks now do different things: 'break A' is still the outermost, but
'break +1' now exist from loop C.
>
Sometimes you will want one behaviour and sometimes the other. So you
can't say one is better. I don't have enough experience of them to say
(my 'exit' and 'exit all' are effectively both absolute).
I can't think of a case where I'd want a relative break. If I did,
when changing the code I'd still have to carefully study the existing
logic and rewrite whatever code needs rewriting. I wouldn't just
add a third loop and then assume everything will still work.
A pattern I've used in Perl is (in pseudo-code):
for each file {
for each line in current file {
process line
}
}
(Sometimes I might have an extra outer loop iterating over directories,
or an extra inner loop iterating over characters.)
I might want to abort processing of the current line if there's an
error, or of the current file if the current line is some kind of
end marker, or skip the current line if it's a comment, and so on.
Since Perl has the equivalent of "break LABEL" and "continue LABEL"
(spelled "last LABEL" and "next LABEL") I can easily do that.
If the "process line" code needs to abort processing of the current
file, that means breaking out of two nested loops. The Perl syntax for
that is "next FILE;", where FILE is the label at the top of the loop. I
can't imagine the number 2 being the best way to express that.
Another issue is when you move or copy a block of code (say those two
breaks) into another loop. That 'break +1' might be OK, but probably
not 'break A'. (You don't want to break out of an unrelated loop in a
different part of the function; using 'goto' would allow that.)
If you move or copy a block of code in a way that change the nesting of
loops, you have to make sure that examine the code and make sure it
still does what you want. A break or continue that refers to the name
of a loop is likely to continue to be correct. A break or continue that
indicates *how many* loops to operate on will have to be reexamined and
very likely changed.
If duplicating within the same function, then you also need to think
about scope rules for those named labels.
That's hardly the only case where duplicating code within a function
can cause conflicts.
A common proposal is to use existing labels, whose scope is already
well defined. Labels have *function scope*. You just have to make
sure that all labels within a function are unique.
>
If function-wide label scope is used, then my A and B labels need to
be unique, so copying code around is harder.
Copying code around is almost always harder than just textual
copy-and-paste. Ensuring that the labels are unique could be an
opportunity to look through the updated code and make sure it's still
correct (to make a virtue of necessity).
If loop scopes are
private, then you can do this:
>
loop A: {
loop A: {
>
which doesn't look useful. It's all a fiddly bit of language design,
which is why I kept it simple.
Label visibility is well defined in C. I can see some benefit to
making loop names a new kind of entity rather than reusing goto
labels (Ada does this), but I think there'd be more support for
using the existing label syntax. I just don't see keeping labels
unique within a function as a problem worth worrying about.
-- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.comvoid Void(void) { Void(); } /* The recursive call of the void */