Python isn't English and iterator "labels"

13 February 2012

Us python fanboys like to think of python as similar to English and thus more readable. Let's examine a simple piece of code:
for item in big_list:
    if item.cost > 5:
        continue
    item.purchase()
For our discussion there are only 3 kinds of people:
  1. People who have never seen a line of code in their life.
  2. Have programmed in other languages but have never seen python.
  3. Python programmers.
We'll dabble between the first 2 groups and how they parse the above. Let's try to forget what we know about python or programming and read that in English:
So I'm pretty sure this isn't English. But it's fairly readable for a programmer. I believe programmers of any of the top 8 languages on the TIOBE index can understand simple python. I definitely can't say the same for Lisp and Haskell. Not that there's anything wrong with Lisp/Haskell, these languages have specialized syntax for their honorable reasons.

Continue is a silly word, what about iterator labels?

Let's say I want to break out of an outer loop from a nested loop, eg:
for item in big_list:
    for review in item.reviews:
        if review < 3.0:
            # next item or next review?
            continue
        if review > 9.0:
            # stop reading reviews or stop looking for items?
            break
Java supports specific breaks and continues by adding labels to the for loops but I think we can do better. How about this:
items_gen = (i for i in big_list)
for item in items_gen:
    for review in item.reviews:
        if review < 3.0:
            items_gen.continue()
        if review > 9.0:
            items_gen.break()
But how can that even be possible you may ask? Well, nowadays it isn't but maybe one day if python-ideas like this idea we can have nice things. Here's how I thought it could work: a for-loop on a generator can theoretically look like this:
while True:
    try:
        item = next(gen)
        # do stuff with item
    except StopIteration:
        break
But if it worked like I propose below we can support the specific breaks and continues:
while True:
    try:
        item = next(gen)
        # do stuff with item
    except gen.ContinueIteration:
        pass
    except gen.StopIteration:
        break
    except StopIteration:
        break
So every generator could have a method which throws its relevant exception and we could write specific breaks and continues. Or if you prefer a different spelling could be "break from mygen" or "continue from mygen" as continue and break aren't allowed as method names normally. I think this could be nice. Although many times I found myself using nested loops I actually preferred to break the monster into 2 functions with one loop each. That way I could use the return value to do whatever I need in the outer loop (break/continue/etc). So perhaps it's a good thing the language doesn't help me build monstrosity's and forces me to flatten my code. I wonder.