From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,99222a5bd46ef3c9 X-Google-Attributes: gid103376,public From: bobduff@world.std.com (Robert A Duff) Subject: Re: GOTO considered necessary (reworked) Date: 1997/06/17 Message-ID: X-Deja-AN: 249467292 References: <5nn2fm$11dk$1@prime.imagin.net> <33A0840B.1B41@sprintmail.com> <33A58C79.1C7A@sprintmail.com> Organization: The World Public Access UNIX, Brookline, MA Newsgroups: comp.lang.ada Date: 1997-06-17T00:00:00+00:00 List-Id: In article <33A58C79.1C7A@sprintmail.com>, John G. Volan wrote: >I could certainly be persuaded that, e.g., there are even some >situations where if statements would be a poor choice or a "last >resort". There are *lots* of situations where 'if' is a poor choice -- where 'case', or a table lookup, or a dispatching call, or a raise/handle of an exception, is a better way. That doesn't mean "last resort" -- it just means you have to use some intelligence in writing your code. >... But I think it's a matter of degree: On the structural >continuum, gotos are considerably farther down in the primitive >direction. Agreed -- I mean you'll find more if's than goto's in *my* code. >Looking at the cases Sam Mize enumerates, I think they can all >essentially be boiled down to this: A programmer has a well-defined >control structure in mind (e.g., FSA's, or loop continue), but the >language does not provide a syntax for it (although such a syntax could >easily be imagined). > >If the structure were available in the language, of course there would >be no question of using gotos for the same purpose. Barring that, gotos >can be used to _simulate_ this structure, but this will always be a >dangerous practice, because the gotos are only at best a simulation of >the actual construct the programmer has in mind. Gotos lack >"robustness"; certain important properties of the hypothetical structure >(e.g., prevention of "fall-through" between states in an FSA) cannot be >guaranteed except by programmer vigilance. Ada doesn't have any FSM feature with *exactly* the right semantics and checks. Fine, so you can *simulate* it with gotos, or with loop/case, or with a table of access-to-procedures, etc. I agree with you that in this particular case, the goto solution is not the best. But it's not too bad, either. >Yes, a very capable programmer may be quite skilled at navigating this >mine-field, and may be quite dilligent about documenting exactly what >structure is being simulated. And a very skilled maintenance programmer >may be able to take such goto-laden code (and its documentation) and, >with a great deal of dilligence, successfully modify it when necessary, >without introducing accidental bugs that violate the desired properties >of the structure. > >But even very skilled programmers are human and capable of errors or >omissions. It would be very useful if some automated tool (e.g., the >compiler) could provide the programmer with an analysis of whether this >use of goto satisfied the desired properties -- but the whole point is >that the compiler is incapable of this, by definition, because the >language lacked the desired construct in the first place. Bottom line, >the appearance of gotos in a program obligates both the original >programmer and all future maintainers to exert a greater than usual >effort to make sure that they get them right. > >Therefore, if the programmer can think of a way to apply a different >structure to the problem, one which the language does support, then this >structure should tend to be favored over simulating a hypothetical >structure with gotos. The non-goto solution should be used if it's "better", and the goto solution should be used if it's "worse" (judgement calls). If they're "equally good", then it's a toss up. It seems silly to say that ties somehow go to the non-goto solution. >... Of course, if the alternative structure reduces >efficiency or adds complexity (e.g., spurious levels of nesting, >auxiliary Boolean variables, or e.g. in an FSA, encoding the states with >an enumerated type), then this is a point against that alternative, and >the engineer must weigh this very carefully. > >On the other hand, just because _some_ workarounds for avoiding gotos >have these undesirable properties does not automatically mean _all_ >workarounds in _all_ situations will suffer from these maladies >(notwithstanding Robert Dewar's attempt to brand any suggestion along >these lines as being tantamount to advocating Boolean junk variables). Not sure what you mean here. We *all* agree that in *most* situations (the vast majority, in fact), the non-goto solution is better. If you read Robert Dewar's code, you won't find very many gotos -- so he obviously agrees. >For example, in the specific case of that Insert operation, my point >(and I believe Jeff Carter's, too) was that wrapping it up as a >subprogram with multiple returns, and then inlining the subprogram, can >be every bit as efficient, no more complex, and considerably safer from >a maintenance point of view, than inlining it by hand with gotos instead >of returns. (And neither Jeff Carter nor I made _any_ mention of Boolean >junk variables for this case.) Well, be careful about "return". It has *some* of the same dangers goto does. For example, I've more than once had a bug, where I added code to a procedure that needs to get executed just before returning from that procedure -- but I didn't notice the "return" buried deeply within some loop's and if's. This is similar to the "adding code on the wrong side of the label" bug that you can get with gotos. >Add to that the fact that, in that _specific case_, the Insert >subprogram is a useful, cohesive abstraction for an important operation >in the given problem domain, one with well-defined preconditions and >post-conditions which can be unit-tested, and one that might be usefully >called from many other places within the same program; then under these >circumstances, the choice for me at least would be very clear, and I >would look very critically at any claim that a goto solution would be >better. Yeah, but not because it's spelled "goto". Because you have some rational argument why that particular goto solution is worse than an alternative non-goto solution. >> I would also agree, if you said, "As a rule of thumb, if you think you >> want to use a goto, think twice." > >Well, that's exactly what I was trying to get across, but that's a very >nice way of putting it. OK, you like my way of putting it. I don't really like your way, which seemed to say, "If two pieces of code are equally 'good', then if one of them contains the token 'goto', then they're *not* equally good after all", which seems illogical (self-contradictory) to me. >> Usually the >> control structures are so small (within a single subprogram), that even >> if you *only* used goto for control flow (which I don't recommend, of >> course!) you could still understand the program. > >Hmm, I'm not sure what else you'd use goto for if not "control flow", >but perhaps you just mean "_local_ control flow" within a very small >procedure, as opposed to large-scale spaghetti code (which I'm sure >nobody is advocating). Sorry, my statement was confusingly ungrammatical -- the usual problem in English about how "only" binds. I didn't mean, "use goto only for control flow" -- as you say, that's a truism. I meant, "for all of your control flow, you use only goto (and not if/case/loop)". My point was just that control flow is far less important than the "bigger" stuff like packages and procedures. So even if you obfuscated all of your control flow by using goto exclusively (no if/case/loop), you would *still* end up with an understandable program, since all of your procedures would be fairly small. As compared to a program that has giant procedures, lots of global variables, puts everything in visible parts (but never, never uses goto). - Bob