Pergunta

goto is almost universally discouraged. Is using this statement ever worthwhile?

Foi útil?

Solução

This has been discussed several times on Stack Overflow, and Chris Gillum summarized the possible uses of goto:

Cleanly exiting a function

Often in a function, you may allocate resources and need to exit in multiple places. Programmers can simplify their code by putting the resource cleanup code at the end of the function all all "exit points" of the function would goto the cleanup label. This way, you don't have to write cleanup code at every "exit point" of the function.

Exiting nested loops

If you're in a nested loop and need to break out of all loops, a goto can make this much cleaner and simpler than break statements and if-checks.

Low-level performance improvements

This is only valid in perf-critical code, but goto statements execute very quickly and can give you a boost when moving through a function. This is a double-edged sword, however, because a compiler typically cannot optimize code that contains gotos.

I'd argue, as many others would argue, that in all of these cases, the usage of goto is used as a means to get out of a corner one coded oneself into, and is generally a symptom of code that could be refactored.

Outras dicas

Higher-level control flow constructs tend to correspond to concepts in the problem domain. An if/else is a decision based on some condition. A loop says to perform some action repeatedly. Even a break statement says "we were doing this repeatedly, but now we need to stop".

A goto statement, on the other hand, tends to correspond to a concept in the running program, not in the problem domain. It says to continue execution at a specified point in the program. Someone reading the code has to infer what that means with respect to the problem domain.

Of course all the higher-level constructs can be defined in terms of gotos and simple conditional branches. That doesn't mean that they're merely gotos in disguise. Think of them as restricted gotos -- and it's the restrictions that make them useful. A break statement is implemented as a jump to the end of the enclosing loop, but it's better thought of as operating on the loop as a whole.

All else being equal, code whose structure reflects that of the problem domain tends to be easier to read and maintain.

There are no cases where a goto statement is absolutely required (there's a theorem to that effect), but there are cases where it can be the least bad solution. Those cases vary from language to language, depending on what higher-level constructs the language supports.

In C, for example, I believe there are three basic scenarios where a goto is appropriate.

  1. Breaking out of a nested loop. This would be unnecessary if the language had a labeled break statement.
  2. Bailing out of a stretch of code (typically a function body) in case of an error or other unexpected event. This would be unnecessary if the language had exceptions.
  3. Implementing an explicit finite state machine. In this case (and, I think, only in this case) a goto corresponds directly to a concept in the problem domain, transitioning from one state to a specified other state, where the current state is represented by which block of code is currently executing.

On the other hand, an explicit finite state machine can also be implemented with a switch statement inside a loop. This has the advantage that every state starts at the same place in the code, which can be useful for debugging, for example.

The main use of a goto in a reasonably modern language (one that supports if/else and loops) is to simulate a control flow construct that's missing from the language.

Surely it depends on the programming language. The main reason goto has been controversial is because of its ill effects that arise when the compiler lets you use it too liberally. Problems can arise, for example, if it lets you use goto in such a way that you can now access an uninitialised variable, or worse, to jump into another method and mess with the call stack. It should be the responsibility of the compiler to disallow nonsensical control flow.

Java has attempted to “solve” this problem by disallowing goto entirely. However, Java lets you use return inside a finally block and thus cause an exception to be inadvertantly swallowed. The same problem is still there: the compiler is not doing its job. Removing goto from the language hasn’t fixed it.

In C#, goto is as safe as break, continue, try/catch/finally and return. It doesn’t let you use uninitialised variables, it doesn’t let you jump out of a finally block, etc. The compiler will complain. This is because it solves the real problem, which is like I said nonsensical control flow. goto doesn’t magically cancel definite-assignment analysis and other reasonable compiler checks.

Yes. When your loops are nested several levels deep, goto is the only way of elegantly breaking out of an inner loop. The other option is to set a flag and break out of each loop if that flag satisfies a condition. This is really ugly, and pretty error-prone. In these cases, goto is simply better.

Of course, Java's labelled break statement does the same thing, but without allowing you to jump to an arbitrary point in the code, which solves the problem neatly without allowing the things that make goto evil.

The most of the discouragement comes form a sort of "religion" that has been created aroud God Djikstra that was compelling in the early '60s about it's indiscriminate power to:

  • jump anywhere into whatever block of code
    • function not executed from the begining
    • loops not executed from the beginning
    • skipped variable initialization
  • jump away from whatever block of code without any possible cleanup.

This has nothing more to do with the goto statement of the modern languages, whose existence is merely due to support the creation of code structures other than the language provided ones.

In particular the first main point above is anymore permitted and the second is cleaned (if you goto out of a block the stack is unwinded properly and all proper destructors called)

You can refer this answer to have an idea of how even code not using goto can be unreadable. The problem is not goto itself, but the bad use of it.

I can write an entire program without using if, just for. Of course, it will not be well readable, an look clumsy and unnecessarily complicated.

But the problem is not for. It's me.

Things like break, continue, throw, bool needed=true; while(needed) {...}, etc. are noting more than masquerade goto to escape away from the scimitars of the Djikstrarian zealots, that -50 years after the invention of modern laguages- still want their prisoners. They forgot what Djikstra was talking about, they only remember the title of his note (GOTO considered harmful, and it was not even his onw title: it was changed by the editor) and blame and bash, bash and blame every contruct having those 4 letter placed in sequence.

It's 2011: it's time to understand that goto has noting to deal with the GOTO statement Djikstra was compelling about.

The odd goto here or there, so long as it's local to a function, rarely significantly harms readability. It often benefits it by drawing attention to the fact that there's something unusual going on in this code that requires the use of a somewhat uncommon control structure.

If (local) gotos are significantly harming readability, then it's usually a sign that the function containing the goto has become too complex.

The last goto I put into a piece of C code was to build a pair of interlocking loops. It doesn't fit into the normal definition of "acceptable" goto use, but the function ended up significantly smaller and clearer as a result. To avoid the goto would have required a particularly messy violation of DRY.

I think this whole issue has been a case of barking up the wrong tree.

GOTO as such doesn't seem problematic to me, but rather it's very often a symptom of an actual sin: spaghetti code.

If the GOTO causes major crossing of flow control lines then it's bad, period. If it crosses no flow control lines it's harmless. In the grey zone in between we have things like loop bailouts, there are still some languages that haven't added constructs that cover all the legit grey cases.

The only case I've found myself actually using it in many years is the case of the loop where the decision point is in the middle of the loop. You're left with either duplicated code, a flag or a GOTO. I find the GOTO solution the best of the three. There is no crossing of flow control lines here, it's harmless.

Yes, the goto can be used to benefit the experience of the developer: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

However, just as with any powerful tool (pointers, multiple inheritance, etc.), one has to be disciplined using it. The example provided in the link uses PHP, which restricts the usage of the goto construct to the same function/method and disables the ability to jump into a new control block (e.g., loop, switch statement, etc.)

Depends on the language. It's still widely used in Cobol programming, for example. I've also worked on a Barionet 50 device, whose firmware programming language is an early BASIC dialect that of course requires you to use Goto.

I would say no. If you find the need for using GOTO, I'll bet that there's a need to redesign the code.

goto may be useful when porting legacy assembler code to C. In the first instance, an instruction-by-instruction conversion to C, using goto as a replacement for the assembler's branch instruction, can enable very rapid porting.

I would argue no. They should always be replaced with a tool more specific to the problem the goto is being used to solve (unless it's not available in your language). For example, break statements and exceptions solve to previously goto-solved problems of loop escaping and error handling.

Licenciado em: CC-BY-SA com atribuição
scroll top