Patterns for Repetition

Version 0.0001

Alyce Faulstich Brady
Kalamazoo College, Kalamazoo, MI
abrady@kzoo.edu


This document will be a collection of elementary patterns by various authors to use in writing code that requires repeating actions.

The Repetition patterns are:

For/Repeat: Repetition with Well-defined Step
General pattern for repetition with a well-defined step to the next iteration
EXCEPTION: Well-defined step that is equivalent to the initialization (implemented as a while-loop)

Special Cases:

While/Do-while: General Repetition (good name?)
General pattern for repetition

Special Cases:

Recursive Repetition:

Overall Loop Patterns:


Counted Repetition (Repetition)

Author: Alyce Faulstich Brady

You are in a situation in which some action should be repeated a known number (N) of times, where N might be a constant number or a value in a variable. The number of repetitions does not depend on any aspect of the repeated action, i.e., you know the value of N before you start the repetition.

Therefore, use a FOR statement that creates a variable to count the number of times the action has been repeated. The counting variable is created and initialized and then, so long as the action has not been repeated too many times (the "test"), the action is done and the count is incremented (the "step"). Express the test as a Positive Condition if possible.

The structure of a FOR loop is:

Need text that recommends FOR statement in C-based languages, REPEAT statement in languages that support that construct. Repeat statements, in particular, are "safer" than while loops because the initialization and step are automatic (or have automatic defaults). C-ish FOR loops are also "safer" because they make the critical initialization and step aspects of the loop control explicit and up-front (follows Local Variables Reassigned Above Their Uses (Gabriel)).

There are two common idioms for controlling the loop. The first is to count from 0 to N-1, which is the idiom used to ensure a Valid Index in a Linear Indexed Traversal (see below for more details). For example, at the beginning of a card game each player is dealt a hand of cards:

[Future: Describe: Under what circumstances do you declare i as part of the initialization in the for loop?]

The second common idiom for controlling the loop is to count from 1 to N. For example,

You might choose to use the second alternative because it corresponds more closely with counting. On the other hand, the Linear Indexed Traversal pattern is a very common, and important, pattern because it is used to step through one of the most common data structures.

Another alternative is to count down rather than counting up. This alternative is the Reverse Counted Repetition Pattern.



Reverse Counted Repetition (Repetition)

Author: Alyce Faulstich Brady

You are in a situation in which a Counted Repetition is appropriate, but it is important that you count down as you repeat the action.

Therefore, use a FOR statement that creates a counting variable that is initialized to the high end of its range and is decremented in the loop "step." The loop condition should test whether the counting variable has reached the low end of its range. Express the test as a Positive Condition if possible.

There are two possible idioms for controlling the loop, similar to the loop control idioms in Counted Repetition. The first, which is analagous to Reverse Linear Indexed Traversal is to count from N-1 to 0.

For example, [Need example!]

The second obvious idiom for controlling the loop is to count from N to 1. For example, [Need example!]

The likelihood for error if you do not consistently stick with one idiom is similar to that with Counted Repetition. To avoid these types of errors many people find it easiest to consistently use the Reverse Linear Indexed Traversal pattern for counting down as well as for accessing indexable structures in reverse order.



Linear Indexed Traversal (Repetition)

(Also known as Definite Process All Items (Astrachan and Wallingford))

Author: Alyce Faulstich Brady

You need to access (add, set, or retrieve) all entries of a Linear Indexed Data Structure exactly once, and, if the order matters, from first to last. You know or can determine the number of elements in the Linear Indexed Data Structure in constant time.

Note that the loop control idioms and examples in this pattern are currently all C-based, i.e., they assume that valid indices range from 0 to N-1.

Therefore, use a FOR statement in which the loop control variable is a Valid Index into the linear data structure. The variable should be initialized to the index of the first element in the linear data structure, the step should increment the index by one, and the test should make sure that the index is not used in the loop body if it goes beyond the last element in the data structure.
(If your data structure is an STL or Java Vector, do not use this pattern to add new entries to the structure; use the Appended Item instead.)

The common idiom for Linear Indexed Traversal to ensure a Valid Index in a C-based language (C, C++, Objective C, Java, etc.), assuming that V is the linear indexed data structure and N is the number of elements to be accessed in V, is

If your data structure V is an STL or Java Vector, or if it is a full apvector (that is, the size of the vector accurately describes the number of meaningful entries in it), then you should use V.size() (STL or Java Vector) or V.length() (apvector) for N. If your data structure is a built-in array, or if the size of an apvector is larger than the actual number of (meaningful) elements in it, then you must keep track of the number of elements as a separate variable.

For example, if hand is an STL Vector of playing cards, then one might use the following loop to display the cards in the hand:

Using a Java Vector, the code would be

This pattern could also be used to modify the value of elements of the collection. For example, to replace existing cards in the hand with new cards obtained from a CardDeck object, deck, the following C++ code might be used:

For a Java Vector, the code would be The code to add new cards to an empty built-in array or apvector of sufficient capacity would be similar, except that hand.size() would be replaced with the number of cards to add. See the Expandable Linear Data Structure pattern for details on ensuring sufficient capacity for an array or apvector; see Appended Item for details on adding new elements to an STL or Java Vector. Both are covered in the complete Linear Indexed Data Structure pattern.

Note the condition in the FOR loop: i < N. This is the common idiom in C-based languages to ensure that the index i is always a Valid Index inside the loop. Another, logically equivalent, condition would be i <= N-1, but the common idiom is more succinct, possibly more efficient (depending on your compiler), and draws attention more clearly to the number of elements in the structure (N).

See Reverse Linear Indexed Traversal if you need to access all the entries of an indexed data structure from last to first.



Reverse Linear Indexed Traversal (Repetition)

Author: Alyce Faulstich Brady

You need to access (add, set, or retrieve) all entries of a Linear Indexed Data Structure exactly once from last to first.

Note that the loop control idioms and examples in this pattern are currently all C-based, i.e., they assume that valid indices range from 0 to N-1.

Therefore, use a FOR statement in which the loop control variable is a Valid Index into the linear data structure. The variable should be initialized to the index of the last element in the linear data structure, the step should decrement the index by one, and the test should make sure that the index is not used in the loop body if it goes "in front of" the first element in the data structure.

The common idiom for Reverse Linear Indexed Traversal to ensure a Valid Index in a C-based language (C, C++, Objective C, Java, etc.), assuming that V is the linear indexed data structure and N is the number of elements to be accessed in V, is

If your data structure V is an STL or Java Vector, or if it is a full apvector (that is, the size of the vector accurately describes the number of meaningful entries in it), then you should use V.size() (STL or Java Vector) or V.length() (apvector) for N. If your data structure is a built-in array, or if the size of an apvector is larger than the actual number of (meaningful) elements in it, then you must keep track of the number of elements as a separate variable.

For example, if hand is an STL Vector of playing cards, then one might use the following loop to display the cards in the hand in reverse order:

Using a Java Vector, the code would be

This pattern could also be used to modify the value of elements of the collection. For example, to replace existing cards in the hand with new cards obtained from a CardDeck object, the following C++ code might be used:

For a Java Vector, the code would be

Note the condition in the FOR loop: i >= N - 1. This is the common idiom in C-based languages to ensure that the index i is a Valid Index. Another, logically equivalent, condition would be i > -1, but the former idiom is more common because it is expressed in terms of the lowest Valid Index rather than a non-valid index.

See Linear Indexed Traversal if you need to access all the entries of an indexed data structure from first to last.



Copyright Alyce Faulstich Brady, 1999.