Bram Cohen (bramcohen) wrote,

Maybe goto isn't so bad after all.

I've used this pattern a lot over the last few days:

for eggs in spam:
    for jello in eggs:
        if jello is the one I want:
            break
    else:
        continue
    break
else:
    return
do stuff with eggs and jello


People familiar with my code will find this amount of complex control flow unsurprising. But the reasoning here is different from my past practices. In the past I always optimized to have as few lines of code as possible, regardless of how upside down and backwards it made everything be organized, but that could be done much better in this case like so:

for eggs in spam:
    for jello in eggs:
        if jello is the one I want:
            do stuff with eggs and jello
            return


There are two reasons I find this construct objectionable. First is that it leads to a lot of code having a lot of indentation (the 'do stuff' is in many cases dozens of lines) which isn't good for readability. Second is that the natural flow of the code is 'scan for the thing I want, and then do something with it' which is the flow of the structure I've been using. I suppose one could write it like this:

def my_little_func():
    for eggs in spam:
        for jello in eggs:
            if jello is the one I want:
                return eggs, jello
    return None, None

eggs, jello = my_little_func()
if eggs is None:
    return
do stuff with eggs and jello


But that's hardly elegant and forces the flow to jump around in terms of the visual layout of the code, which goes against what I'm trying to accomplish.

At the risk of starting a religious war, I'd like to point out that the most readable and versatile way of doing what I want is like so:

for eggs in spam:
    for jello in eggs:
        if jello is the one I want:
            goto x
return
x: do stuff with eggs and jello


But short of that the following may be the best option currently available. I might switch to it:

for eggs in spam:
    for jello in eggs:
        if jello is the one I want:
            after_func(eggs, jello)
            return

def after_func(eggs, jello):
    do stuff with eggs and jello


But it still doesn't look as nice as the version with a goto.
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded  

  • 13 comments