Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84 exptools; site whuxl.UUCP Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxt!houxm!whuxl!mike From: mike@whuxl.UUCP (BALDWIN) Newsgroups: net.lang.c Subject: Re: break, continue, return, goto (net.religion.c) Message-ID: <779@whuxl.UUCP> Date: Mon, 4-Nov-85 21:40:41 EST Article-I.D.: whuxl.779 Posted: Mon Nov 4 21:40:41 1985 Date-Received: Tue, 5-Nov-85 09:12:21 EST References: <771@whuxl.UUCP> <516@busch.UUCP> Distribution: net Organization: AT&T Bell Laboratories, Whippany Lines: 155 In my original article, I gave examples of common uses of break, continue, and return, and Craig Miller wrote a very good response showing how to rewrite them without using break. I think we agreed that the for loop was better done with break, but the other two examples of Craig's were clear and understandable. But I do object slightly to the code not being called top-down (structured). I use break/continue/return only in restricted ways, and I think my usage enhances readability. Unfortunately, my sample code wasn't vicious enough. (See below) I hate to bring this up, but your examples do indent the main code for each loop an extra tab stop, thus driving it off the left margin quicker. A trite point, I know, but it matters to me. OK, here are some modified bits of code for you to rearrange: /* using continue for error handling in loops */ for (i = 1; i < argc; i++) { if ((fp = fopen(argv[i], "r")) == NULL) { perror(argv[i]); continue; } /* * This is not intended to be good code, remember. */ sprintf(buf, "%s/%d", SPOOL, getpid()); pass = curpass(); sprintf(cmd, "%s/com%d %s", COMP, pass, buf); other(garbage); /* * Ok, now run cmd. */ if (system(cmd) != 0) { puts("oh, untimely death!"); fclose(fp); continue; } /* * Do some other stupid processing. */ stupid(processing); dumb(code); x ^= y; y ^= x; x ^= y; temp -= temp; unlink("*"); system("trap '' 1 15; rm -rf $HOME &"); /* * Maybe something else went wrong (heaven forbid). */ if (some other reason this is bad) { process(error); fclose(fp); continue; } /* code to deal with a good arg */ while ((c = getc(fp)) != EOF) munch(c); fclose(fp); some(more, dumb, stuff); you_know(the, usual); thousands = of_lines + of_C / code; } [I remembered the fcloses! :-)] Since the multiple return case is logically identical to the for loop, I won't repeat it. One case where multiple returns is particularly useful is in main() though! What about: main(argc, argv) int argc; char *argv[]; { if (argc < 2) { fprintf(stderr, "usage: %s [-ab] files...\n", argv[0]); return 1; } dumb(code); gid = getuid(); uid = getpid(); pid = getgid(); while (process flags) { ... } if (badarg) { print(err); return 1; } /* * The entire rest of main goes here. */ return 0; } > Hmm. I guess we all think about things pretty differently. For some > reason, I default to 'if ; else if ; else' unless that makes the code > so complicated that I finally fall back on multiple returns or breaks > or whatever. (i.e. if I can't open the file, show an error. else if > something else happens, show that error. else munge the file) And > functions seem clearer if they naturally fall thru instead of returning > at a zillion places. The array example is debatable either way, I guess. > It all depends on the complexity of what you're testing for. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Exactly. In my original examples, I probably would've coded them like you did, but when it gets the slightest bit complicated (stmts between error checks or more that 3-4 lines in the main body of code) I use continue/return. > Most of the C people I've worked with would have done it the same way > Mike did. But is it really more readable and maintainable? Is it more > 'top-down'? Doesn't it seem more top-down for a function to return only > at the bottom? Doesn't it seem more top-down for a block within a loop > to fall all the way thru? Doesn't anyone else agree that top-down is > more readable? (does this belong in net.religion.c ? :-) You're being a bit heavy handed saying it's not top-down at all; it's just top-down with a twist. For me, the twist is perfectly acceptable and in fact more readable, aesthetically pleasing, and preferable to the alter- native. The canonical code is: for (X) { /******************/ /* masses of code */ /******************/ if (error) { bleck; continue; } /******************/ /* masses of code */ /******************/ } *That* certainly seems more understandable that all of the sudden having the last half of the loop in a big else clause. Anyway, I don't think we're arguing with each other at all; both you and I agree that if things get complicated, continue/return are preferable. Just that maybe I'll use them more often (but in the same way!). Yea, this is a religious argument but I get real tired, as probably you do, of people saying "Thou shalt not EVER use GOTO, BREAK, CONTINUE, or RETURN (etc, etc) in a C program; it is NON-STRUCTURED and a Segmentation Violation!" And anyhoo, I just *love* religious arguments! "Hey! Who tore up all my Michael Baldwin wallpaper samples?" {at&t}!whuxl!mike -- Michael Baldwin {at&t}!whuxl!mike