[Edu-sig] a short essay about programming

Mark Engelberg mark.engelberg at gmail.com
Sun Apr 22 22:44:50 CEST 2012


John Zelle wrote:
guess = int(input("Guess? "))
while(guess != secret):  // as long as the user didn't get it, get another
guess
   print("Nope, try again")
   guess = int(input("Guess? "))
// Here we know the condition is false
print("You guessed it")


I mostly find John Zelle's version to be more elegant, but I dislike that
the line:
guess = int(input("Guess? "))
occurs in two places.

In general, we should be discouraging writing the same line twice.  What if
you want to change the prompt?  What if you want to create more complex
error checking for the input.  Are you going to remember to change it in
both places?

One reasonable option is to break this out into a separate getGuess()
function.  You'd still end up with two calls to the getGuess() function,
but at least the logic of getting the guess could easily be changed in one
place.

This begs the question, though, as to whether it is possible to rework the
code to only have one line which gets the guess, without involving
continue, break, or while(True).

I don't believe there is a way.  If Python had tail recursion, one way to
rewrite this that satisfies all those constraints would be:

def repeatUntilSecretIsGuessed():
  guess = int(input("Guess? "))
  if (guess == secret):
    print("You guessed it")
  else:
    print("Nope, try again")
    repeatUntilSecretIsGuessed()

This would be bad form for Python, though.

One other thought about while/continue/break.  I am always thinking about
the fact that we're training kids for the languages and programming styles
that will emerge over the next 10+ years.  To better understand the future
we're preparing them for, I spend a lot of time studying emerging
languages, looking for clues about what styles will best "future-proof" my
students.

In the case of while loops, I think it's instructive to look at Scala, a
language that is currently being hailed as the most plausible successor to
Java.  Scala doesn't have break or continue at all.  The idea is that if
you have a loop that requires a break, it is far clearer to make that loop
into a separate helper function, and use return instead of break.  So for
example, looking at Kirby's code:

while True:  # no ifs ands or buts
   guess = int(input("Guess?: ")
   if guess == secret:
       print("You guessed it!")
       break
   else:
       print("Nope, try again...")

you'd instead write it as:

def repeatUntilSecretIsGuessed():
  while True:
    guess = int(input("Guess?: ")
    if guess == secret:
        print("You guessed it!")
        return
# It's a bit easier to understand this code because we see it completely
exits the function here, not  just the while loop
    else:
        print("Nope, try again...")

In this example, the distinction seems a little silly, but I would argue
that the vast majority of while loops are, semantically speaking,
"returning a value".  They do this by setting up some accumulator variable
before the while loop, and then pounding on the variable, changing it each
time through the while loop.  It can take a bit of analysis to determine
which is the variable(s) you care about, and what it contains at the time
you break out of a loop.  By breaking the loop into a separate function,
and actually returning the value you care about with a return statement,
the code becomes much easier to understand.

So for example, let's say you want to keep looping until you get a guess
from 1 to 10.

Standard way (using while True and break) would be something like this:

while True:
  guess = int(input("Guess a number from 1 to 10? "))
  if (guess < 1 or guess > 10):
     print ("Try again")
  else:
     break
# at this point we continue our code, and we know guess contains a number
from 1 to 10

Better way:

def getNumberFrom1To10():
  while True:
    guess = int(input("Guess a number from 1 to 10? "))
    if (guess < 1 or guess > 10):
       print ("Try again")
    else:
       return guess
# Now, it's really obvious what is the value that is being "set" by the
while loop.

In any case, whether you prefer Kirby's while True version or John's
version which requires asking for a guess both before the loop and inside
the loop, the main idea here is to get kids thinking each time they have a
loop, especially a loop that involves break, whether maybe the code would
be better if they factored out the loop into a separate function.

--Mark
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/edu-sig/attachments/20120422/1b7214a9/attachment.html>


More information about the Edu-sig mailing list