The ‘goto’ operation has a very bad reputation when it comes to high-level programming languages. I have heard many times the sentence “never ever use goto”. I think that the fear of ‘goto’ is generally justified since it can lead to horrible spaghetti code. If really abused, it can completely corrupt the structure of a program, making it potentially impossible to track its logic.
However, I would not go as far as removing it completely from our toolbox. In general, I am careful when I hear those “never use” declarations. The root to goto’s destrcutiveness is actually its overwhelming power – it can be used to jump from anywhere to everywhere in the program (with limits, going really wild is restricted by various languages), breaking through walls, leaving destruction in its wake. Well, if it is so powerful, is it possible that there is good use to it, sometimes?
Exceptions to the “goto embargo”
One use of ‘goto’ that I personally find useful, is for resources release at the end of functions. I have seen this practice used in production and Open Source code so I think it may have become a common practice to some degree. Let me first present the underlying challenge.
Personally, I find the “one-time do-while” practice a good and clean way to write C code that properly handles errors. It looks like this:
Now assume that you have a function that includes several resource allocations. In a perfect world you would do the allocations, use them, and at the end you will release all the resources. In practice, each of the allocations can fail, and you should use something like the above in order to properly address those possible failures. However that may prove difficult since you may be looking at a variable amount of release operations.
Let’s modify the above example to do allocations that require a release, with an example. The example is a horrible way to handle the releases, and is presented just for illustration:
This is of course highly error-prone, not scalable, not maintainable and not recommended. Every change somewhere in the function may require a change in multiple other places. Moreover, the code is inflated with repetitive code. At least for this code, there is a better option:
This is nice enough when all your allocations are mallocs, but that is not the only option for resource allocation. Resources can be syncronization entities, HW resources, File System resources (e.g. file open) and so on, and not all will have a way of detecting the success of the allocation operation that is as nice as a simple comparison to NULL.
Reverse release using ‘goto’
Let’s modify the above function to do arbitrary resource allocations. Also, we will create a ‘release block’ at the bottom of the function that will arrange the release operations in an order reversed to the allocation order. This will allow us to jump into the block and execute only the appropriate release operations:
Another interseting benefit of the ‘goto’ error handling method over the “do-while” method is its robustness (credit: Avishai Gantz). The ‘break’ expression is used in a context and can only break out of the scope in which it is declared in, not further. ‘goto’ on the other hand can break a faulty flow and take it directly into the release block without further complications.
Consider the following example, in which a ‘while’ loop has to be used in the function’s flow, while the above “do-while” error-handling method is being used:
The above example illustrates the scope issue of ‘break’. This cannot happen if you use the ‘goto error block’ method.
This bug really happened in prodcution code. It is unclear if the code was written like this, or if that is a result of a refatoring operartion with the intent to improve error handling while not noticing the implications of already having a while loop there.
Handle With Care
In my opinion, beyond being a rare example of when goto can (or should) be used, the example above illustrates what are the characteristics of possible other examples:
- goto jumps inside the confines of the smallest possible scope
- goto Jumps only downwards
- All the goto’s are aimed at a specific, targeted location, not all around
- goto is used in a consistent and methodological way, constituting a clear method. If you have many of those error-handling structures in the code, the reader knows exactly where this is going after reading just few of them
So, the bottom line in my opinion is still definitely “Handle With Care”, but not “Never Use”.