Organizing a while loop: Sentinels versus flags
In this post I would like to discuss two different approaches for organizing code that involves while-loops. As you know, a while loop is a control mechanism that expreses the following idea: "as long as something is True, repeat this block of code".
The ideal structure of a while-loop includes the following steps:
- Initialize the loop control variable
- Evaluate the loop control variable in the while statement
- Update the loop control variable in the while-loop
As an example, let's write a program where we require a user to provide us with some number. When providing this number, there is the additional requirement that this number should fall within a specific interval of numbers. As long as the provided number is not within this interval, we will keep asking for another number.
To get the number we will use the Python
input function. This function gets any input that is provided as a string variable, so for clarity we will further assume that the user behaves nicely and always provides an actual integer number so that we can safely convert it to an integer without doing any additional input validation.
It turns out that even in this very simple case, there are already two different approaches that can be used to organize your while loop. They are referred to as the sentinal approach and the flag approach
number = int(input("Provide a number in the interval [10, 20]: ")) while not (10 <= number <= 20): print("Number not in interval") number = int(input("Provide a number in the interval [10, 20]: "))
With the sentinal approach, the loop control variable can be thought of as a sentinel or signal value that determines if the loop should continue or not. It is typically used in cases where you are handling data, which can be provided by the user or read in from a file. In the example above, the sentinel is the variable
number. It is initialized as the first line of code by getting an initial input from the user. The evaluation in the while statement ensures that the content of that variable is within the required range. Finally, the sentinel value is updated by getting another number in the while-loop.
Flag based approach
number_within_range = False while not number_within_range: number = int(input("Provide a number [10, 20]")) if 10 <= number <= 20: number_within_range = True else: print("Number not in interval")
In the flag based approach we use a boolean variable as the loop control variable. Other than that, we can see the same general structure in the construction of the while loop. The boolean variable is initialized before the start of the loop and evaluated within the while statement. Finally, the code within the loop validates the number and updates the value if the requirements are met.
Which approach to choose
Whenever there are two or more possibilities to construct code, the question naturally arises what the best approach is. I find that this is a very hard question to answer, as it will in some part depend on your personal preferences, but also on the context in which the code is being developed. In this particular example, I would prefer the flag-based approach because I find it more clear and explicit about the intent of the code (i.e., reading the while-statement makes it clear what we are doing). Because the flag-based approach uses the input function only once, this also means we only have to make a single change to the code if we want to change how the question is going to be phrased to the user.
Nevertheless, the distinction between a flag-based an sentinel-based approach is also not that clear cut. You could argue that the flag-based approach does have a sentinel value. The only difference is that this value is not used directly within the evaluation of the while-statement. In stead, the boolean variable acts as some sort of proxy for the sentinel value.
In the end, I think it is more important to know that different approaches are possible so that you can decide for yourself what works best for you in a specific situation.