Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!cs.utexas.edu!uunet!kim From: kim@kim.misemi (Kim Letkeman) Newsgroups: comp.lang.c Subject: Re: The final word on GOTO (Don't I wis Message-ID: <1051@kim.misemi> Date: 2 Oct 89 13:32:01 GMT References: <20324@<1989Sep14> <225800222@uxe.cso.uiuc.edu> <4208@cbnewsh.ATT.COM> <1017@kim.misemi> <598@crdos1.crd.ge.COM> <1044@kim.misemi> <5416@merlin.usc.edu> Distribution: na Organization: MITEL Corporation, Kanata, Ontario, Canada. Lines: 98 In-reply-to: jeenglis@nunki.usc.edu's message of 30 Sep 89 05:20:50 GMT In article <5416@merlin.usc.edu> jeenglis@nunki.usc.edu (Joe English) writes: >kim@kim.misemi (Kim Letkeman) writes: >>[blah blah blah] >>As a general principle, writing a single procedure to perform a single >>function (task) is the whole point behind so called structured >>programming. Coupling and cohesion and all that. >> >>So where does the goto fit after all this? It doesn't. >What kind of control flow you use doesn't have >that much to do with coupling or cohesion; the >goto still has some valid uses. For example: You got me. I took a chance and mixed two points in successive paragraphs without making my point particularly clear. I was really trying to say that I feel that structured programming concepts are adequate for the vast majority of situations and that gotos are only necessary in extreme cases. I apologize for the lack of clarity there. >void foo() { > int k; > initialization_sequence; > > while (k = get_input()) { > switch (k) { > case 'A' : a_action(); break; > case 'B' : b_action(); break; > ... > case 'Q' : q_termination_stuff(); goto done; > case 'X' : x_termination_stuff(); goto done; > } > end_loop_processing; > } >done: > cleanup_sequence; > > return; >} >This, I submit, is an example of a cohesive function >that uses a goto. If end_loop_processing and >cleanup_sequence are nontrivial, this can't be cleanly >done any other way. I agree that this is an example of a cohesive function if the end_loop_processing and cleanup_sequence is fairly trivial. If not, it is likely that they are performing fairly significant functions that are not entirely related to the actual running of the pseudo state machine. In that case, they would be better isolated in their own procedures. This improves cohesion and makes this procedure more readable. (Your example is quite readable as shown, but would deteriorate with additional code.) >This example wasn't just invented to prove a point; I >actually wrote something similar once. (I shouldn't >have said that... now half the net will probably >accuse me of dubious programming practices :-) Just one (very quickly conceived) alternative: void foo() { int k; int done; initialization_sequence (some parms?); /* function if non-trivial */ done = 0; while (k = get_input()) { switch (k) { case 'A' : a_action(); break; case 'B' : b_action(); break; ... case 'Q' : q_termination_stuff(); done = 1; case 'X' : x_termination_stuff(); done = 1; } if (done) break; end_loop_processing (some parms?); /* function if non-trivial */ } cleanup_sequence (some parms?); /* function if non-trivial */ return; } This version looks as good to me and if the case statement gets long it means you don't get your "oh no ... a goto" bell rung every time you encounter a termination situation. To make it read better, I might use a state variable with readable names in an enumeration, or at least constants like TRUE and FALSE. But the point is that this case is not (IMO) extreme enough to warrant a goto. >Another example of (I think) a valid use for the >goto is the multi-level exception handling case >posted a while back. I believe someone posted a version without a goto. It looked fine to me. >--Joe English -- Kim Letkeman uunet!mitel!spock!kim