Listener While-loop Variations

Other authors and users may refer to interactive while-loops instead of listener loops.

The example of a listener loop in FOPP 14.3

theSum = 0
x = -1
while (x != 0):
    x = int(input("next number to add up (enter 0 if no more numbers): "))
    theSum = theSum + x

print(theSum)

is a somewhat unique one: It does not matter whether you recognize that '0' is the sentinel before or after adding. Let's make the empty string be the sentinel. There is no neat way to transform the earlier code with the bogus initial data -1.

One standard approach, avoiding bogus data, is to get real input from the user initially before the loop, that makes sense as you first get to the while-loop heading and its condition:

theSum = 0
s = input("Next number to add up (just return if no more numbers): ")
while (s != ''):
    theSum += int(s)
    s = input("Next number to add up (just return if no more numbers): ")
print(theSum)

The essential feature to note here is that when the loop reaches the bottom and continues, it does not go back to a statement before the loop heading, but it does need a new value for the user input for the next test in the while-loop heading! The solution is to repeat the request for data at the bottom of the loop: Both the line before the loop and the line at the bottom of the loop feed back to the loop heading and its test, where you always need new data! Omitting the repeated request at the bottom of the loop body causes an infinite loop. Be careful!

Advantages of this form are:

The outline for this form of listener loop is:

# initialize variables,
# including prompting the user for the first input value!
# while (continuation condition using current user data):
    # process the latest data
    # get the next input from the user!

FOPP has other examples where a boolean variable is set to control the loop. We could try such a variation here:

theSum = 0
loopAgain = True
while (loopAgain):
    s = input("Next number to add up (just return if no more numbers): ")
    if s == '':
        loopAgain = False
    else:
        theSum += int(s)
print(theSum)

This is more verbose, and the variable loopAgain is really not very helpful: You still need to look inside the loop to see where and why it gets set to False.

If you do not like the statement duplication with the input prompt before the loop AND at the end of the loop body, and if you have looked at the section 14.5 on the break statement, here is an alternative with an apparently infinite loop:

theSum = 0
while (True):
    s = input("Next number to add up (just return if no more numbers): ")
    if s == '':
        break
    theSum += int(s)
print(theSum)

This is a matter of taste: Now the continuation condition is an artificial part, telling you nothing about what makes the loop continue. You have to examine inside the loop to see what controls the continuation of the loop, like in the boolean variable condition setting variation above. Typically you have to only look just inside the loop body like here, to find the condition for the break. Still, it takes a bit more work to understand the loop than in the double input prompt version.

There can be much more complex situations where the boolean variable condition form or having multiple tests with break statements could be very helpful, but we are not getting that complicated at this point.

The same logical variations will work in Java, too. You can try parts of the exercise below now if you like, and I will assign analogous parts a) and b) later in Java.

Make List Loop Exercise

  1. Try your favorite variation of these approaches to complete the function, and then test it several times:

    def saveLines(prompt, sentinel):
        '''  Print an initial line saying how to use the sentinel.
        Input a line from the user using the prompt string parameter.
        As long as the input is not the sentinel string, append it
        to a list, and return the list at the end.  Example:
    
        >>> words = saveLines('Enter a word: ', '/')
        Enter / when done inputting lines of data.
        Enter a word: hi
        Enter a word: there
        Enter a word: /
        >>> print (words)
        ['hi', 'there']
    
  2. Modify part a. so it ignores empty lines, unless sentinel is ''.

  3. If you choose to read the optional section on optional parameters, modify the function in part b. to have a third parameter: ignoreEmptyLines=True