Working around a lack of 'goto' in python

Stephen Horne steve at ninereeds.fsnet.co.uk
Sun Mar 7 14:57:22 EST 2004


On Sun, 07 Mar 2004 13:54:33 -0500, Roy Smith <roy at panix.com> wrote:

>Stephen Horne <steve at ninereeds.fsnet.co.uk> wrote:
>
>> a goto is the natural representation of a transition between states.
>
>Except that a goto allows the code for a state to be fallen into from 
>the top.

How is this different to the more typical switch-within-loop method?
Or have you never forgotten to include a 'break'? ;-)

>The best way I know to implement a state machine in Python is one 
>function for each state, and have each function return the next state, 
>or perhaps an (output, nextState) tuple.  Your main loop then becomes 
>something like:
>
>   state = start
>   while state != end:
>      nextState, output = state (input)
>      print output
>      state = nextState

I've done similar in C++. In some extreme cases, I have used a class
heirarchy with a class for each state, using a virtual method to get
essentially the same effect. Having different members depending on the
state can be useful at times, though of course there is a price to
pay.

The same can of course be done in Python, and probably without all the
classes because of the dynamic nature of Python objects.

The point with my 'short running' example, though, is that it didn't
have input as such to worry about. Everything it needed to work on was
available at the time it was invoked. If it had needed to wait for
input sometimes I'd have needed a way to resume from a given state
anyway, implying the switch-for-the-state method or whatever.

Using functions or objects for the states would have meant making a
bunch of local variables accessible by those functions/objects, and
would have meant taking the states code out of context. Often this
would be a good thing, but not in this case - keeping the code in
context makes it much clearer.

The other consideration was that this was an inner loop in a function
that needed to run quickly. Adding function call overheads (especially
with lots of parameters) wasn't an option.

>I've implemented state machines in Perl with a huge multi-way 
>if/elif/elif/else statement.  It's pretty ugly, but it beats gotos.

If you say so. But in reality, but returning a function pointer to a
function that is immediately going to call that function pointer,
you're basically just faking the effect of a goto anyway.

Implementing a state machine using gotos (in those extremely rare
cases where it is an option) does not damage readability or
maintainability. Implementing a transition as 'return statefn;' or as
'statevar = stateid;' is really no different than implementing it as
'goto statelabel;'. All are a potential cause of spaghetti code if
abused, because all are just means of branching to a different piece
of code - its just that the goto does exactly what it says, while the
other methods achieve it indirectly. In fact its basically a special
case of the state variable method, using the processors IP as the
state variable.

That said, I did try to avoid using gotos anyway - using a goto is
basically begging to be harassed. I didn't use the loop-and-switch
method, but instead tried to pretent it wasn't really a state machine
by using a birdsnest of loops and conditionals. Never let anyone tell
you that structured code is inherently clean and simple - there's
always a special case where it all goes horribly wrong.

After three fatally buggy attempts using structured code, which I
realised I couldn't understand and thus couldn't debug, I gave up and
used gotos. The result worked first time, and other people have also
been able to understand it easily.


-- 
Steve Horne

steve at ninereeds dot fsnet dot co dot uk



More information about the Python-list mailing list