Path: utzoo!mnetor!uunet!seismo!sundc!pitstop!sun!quintus!ok From: ok@quintus.UUCP (Richard A. O'Keefe) Newsgroups: comp.lang.c Subject: Re: Re^3: gotos Message-ID: <921@cresswell.quintus.UUCP> Date: 30 Apr 88 09:03:45 GMT References: <2606@ttrdc.UUCP> <3950004@hplvly.HP.COM> Organization: Quintus Computer Systems, Mountain View, CA Lines: 45 Summary: Just to be iconoclastic... In a fine series of postings, kenny@uiucdcsb.cs.uiuc.edu showed us how the gotos in Knuth's "Structured ... Gotos" could be avoided in a "modern" language by using (1) gotos (alias 'break', 'continue', 'return') (2) adding state variables (the very special case of ungetc()) (3) duplicating code Dijkstra's original argument against 'goto's was that when you look at a labelled statement you may have no idea what it means for the program to have reached that point. While 'break' and 'continue' are tamer than general gotos, in that they can only be used to exit control structures, not to enter them improperly, I suggest that they can be much _worse_ for program maintenance than the gotos Knuth was advocating. What gives me such a crazy idea? The fact that they are anonymous. If I want to see where a break or continue takes me, I may have to scrabble around matching braces. The big advantage of a goto in C is that the label has a name. _If_ you adopt the practice of always flushing labels left, _if_ you use gotos with _care_, and _if_ you put a comment after each label saying what it means to be at that point, it can be a lot easier for someone to figure out what is going on. I will take a goto over "break 2" any day (fortunately C hasn't got "break 2", but it has been suggested several times in this newsgroup). The ideal, of course, is something which combines the clarity of a label with the tameness of a 'break', to wit a named exit. (Escape functions are even nicer, but they're not C's style.) While C hasn't got a named exit, we can get the same effect with macros: #define BEGIN(id) { #define END(id) ; id:; } #define LEAVE(id) goto id /*example*/ BEGIN(search) for (i = n; --i >= 0; ) if (a[i] == sought) { /* "found" processing */ LEAVE(search); } /* "not found" processing */ END(search) A fairly straightforward awk script can be used to check that BEGIN and END match up and that LEAVE is properly in scope. [Left as an exercise for the reader (:-).]