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
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to