Goto (Posting On Python-List Prohibited)

bartc bc at freeuk.com
Sat Dec 30 09:41:09 EST 2017


On 30/12/2017 03:05, Lawrence D’Oliveiro wrote:
> On Saturday, December 30, 2017 at 12:12:23 PM UTC+13, bartc wrote:
>> Looking at 14 million lines of Linux kernel sources, which are in C,
>> over 100,000 of them use 'goto'. About one every 120 lines.
> 
> That kind of thing leads to spaghetti code.
> 
> Here <https://github.com/ldo/dvd_menu_animator> is an example I like to bring up: writing a Python extension module in C. As you know, this requires a lot of careful memory management to cope with errors and avoid either memory leaks or double-frees. The coding convention I came up with looks like this:
> 
>      ... initialize pointers to allocated storage to NULL ...
>      do /*once*/
>        {
>          ... processing ...
>          allocate some storage;
>          if (error)
>              break;
>          ... more processing ...
>          allocate more storage;
>          if (error)
>              break;
>          ... even more processing ...
>        }
>      while (false);
>      ... free allocated storage ...
> 
> Basically, it becomes possible to satisfy yourself, by inspection, that every possible control path through the above code will pass once, and only once, through the storage deallocation.
> 
> Things get slightly more complicated where allocation has to happen in a loop. Actually, that’s where the interesting cases happen. My technique can be adapted to cope elegantly with this, too--see the code.
> 

I tend to use goto to share small sequences of code:

    if cond1:
       A
       B
    elif cond2:
       C
    elif cond3:
       D
       B
    elif cond4:
       C
    ...

Here, A, B, C, D represent small blocks of code. The conditions have to 
be tested in this order.


B and C occur twice, so a goto is a quick way to reuse B and C without 
needing to duplicate code, or go through the upheaval of extracting them 
to functions. (And then the code develops so that the two Bs /are/ 
different, and then you have to get rid of the function. Or the second C 
was temporary anyway.)

Any other way of doing it will obfuscate the structure:

    if cond1:
       A
    elif cond2 or (not cond3 and cond4):
       C
    elif cond3:
       D

    if cond1 or (not cond2 and cond3):
       B

I can no longer be sure if this right. Plus executing A, C, D can change 
the conditions if they are tested again.

(I had introduced a special language feature just for this kind of 
thing, but it was unsatisfactory. Goto was simpler and understood by 
everyone. And portable to any other language - that hasn't done away 
with goto. But it worked like this (not Python):

a:=20

case a
when 10 then
fred::
     println "one"

when 20 then
     @fred
     println "two"

end

Output is "one" "two" when a is 20.

fred:: names a block, and @fred 'calls' that block, without having to 
move it out of context. Actually this goes beyond what 'goto' can do, as 
it can also 'come back'. But as you can see, it looks a bit naff. A bit 
1970s.)

-- 
bartc



More information about the Python-list mailing list