Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: C23 (C2x) changes Date: Wed, 22 Sep 2021 14:05:18 -0700 Organization: None to speak of Lines: 91 Message-ID: <87mto4micx.fsf@nosuchdomain.example.com> References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Info: reader02.eternal-september.org; posting-host="b5fd9637bf49c8f43a3bd672d60f3caf"; logging-data="1329"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/TJEBxHBz0pr4RPdb53ysb" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:qH8pBVneJ/GD8BHg8yICIWevnyM= sha1:920eLicnWXnlPjOE5MssEM8uimU= Xref: csiph.com comp.lang.c:162822 Philipp Klaus Krause writes: > Am 22.09.21 um 20:27 schrieb Guillaume: > >> - Tagged blocks/tagged loop constructs. >> >>[…] >> >> That would be more elegant and easier to statically analyze than goto's. > > No. It would not be better than goto. Neither for users nor for static > analysis. AFAIK this has been proposed and rejected multiple times > before (e.g. N1989 at the London 2016 WG14 meeting). > > Regarding analysis (and likely also code readability), one important > parameter is the tree-width of the control-flow graph. For C this is > bounded by a constant plus the number of labels for goto used per > function. The situation is similar for many other languages. And at > least for tree-width, it has been proven that unlimited use of labeled > break / labeled continue, like Java has, would be just as bad as > unlimited use of goto. > > If you need to get out of an inner loop, just use goto. Avoiding goto by > introducing another variant of goto that just isn't called goto won't > make the standard better. The proposal in N1989 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1989.htm was to have "break 2;" break out of two enclosing loops. (The Bourne shell has this feature.) Personally, I dislike this. It's easy to forget to update the number when the code is rearranged, and it forces the programmer and reader to count nesting levels -- and counting, after all, is something that computers are really really good at. What I'd like to see is *named* loops, with "break" and "continue" optionally taking an argument that names the loop to be operated on. I've used other languages with this feature, and I've found it quite useful. It would, of course, be equivalent to a goto targeting a point after the end of the loop ("continue" might be a little more complicated), but the point is that it's restricted ("break foo" can't jump to an arbitrary location) and it documents what it's doing. I think of "break foo" as an operation on the loop named "foo", not an operation that refers to a specific location in the code. It would make no difference to static analysis, but in my opinion it would make for more legible code in the (perhaps not very common) case where you want to break out of nested loops. Ada has this feature. It uses a deliberately heavy syntax for goto labels: << LABEL >> -- ... goto LABEL; but a simple identifier followed by a colon for labeled loops: Loop_Name: for I in 1..10 loop -- ... exit Loop_Name; -- Ada spells "break" as "exit" end loop; Perl uses the same syntax for goto labels and loop names, which means if you see a loop name you can't be sure without checking that there isn't a goto somewhere that targets it. I haven't found that to be a problem in practice: Loop_Name: for my $i (1 .. 10) { # ... last Loop_Name; # Perl spells "break" as "last" } In both languages, if you omit the label on a break/exit/last statement it applies to the innermost enclosing loop. Of course C would have to do the same. Off the top of my head, I can't think of a good simple syntax for loop labels that's distinct from the syntax for goto labels, so perhaps a "break name" construct could just refer to a goto label that's applied to an iteration or switch statement. "break foo;" where "foo" is a label that *doesn't* apply to an iteration or switch statement would be a constraint violation. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips void Void(void) { Void(); } /* The recursive call of the void */