Logo

Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.

DO WHILE

This is the granddaddy of loop commands. It’s been in Xbase almost from the beginning. It lets you execute a group of commands when some condition exists until that condition fails. Over the years, most of the uses for it have been superseded by more specialized commands, but it still comes in handy now and then.

Usage

DO WHILE lCondition
   Commands
   [ LOOP ]
   [ EXIT ]
ENDDO

lCondition is an expression. It’s evaluated only at the beginning of each pass through the loop. So, once you get in, you complete that pass regardless of changes to lCondition inside.

It is important to provide some way of exiting the loop. Generally, you do this by changing a variable that’s used in lCondition. Forgetting to provide a way out results in what’s known as an “infinite loop”—it’s not a pretty sight. A very good reason for leaving SET ESCAPE ON when developing.

LOOP and EXIT are escape routes from the loop. LOOP shortcuts the current execution of the loop, proceeding directly to re-evaluation of lCondition. EXIT ends the loop entirely.

We know people who routinely write loops like this:

DO WHILE .T.
   * Some processing
   IF <something or other>
      EXIT
   ENDIF
ENDDO

We think this is bad practice. It hides the structure of the loop and makes it much harder to understand what’s going on. We avoid both LOOP and EXIT and recommend you do the same.

Try something like this instead:

lcNextFile = SYS(2000,"*.DBF")     && Find the first file matching "*.DBF"
DO WHILE NOT EMPTY(lcNextFile)
  * process the file
  lcNextFile = SYS(2000,"*.DBF",1) && Find the next file matching "*.DBF"
ENDDO

If you need to do something a certain number of times, use a FOR loop instead. To touch every element of an array or collection, use FOR EACH. To process a series of records in a table, use SCAN instead.

Once in a while, you may want to combine DO WHILE with SCAN for a nested loop. You’d use this in the case where you want to look at records in some order and do something to all the records that, say, have the same key. The structure of this sort of loop is shown in the first example below.

DO WHILE works better than SCAN for the outer loop because it doesn’t automatically skip a record each time. The SCAN WHILE loop leaves the record pointer on the first record that doesn’t match the current, which is right where we want to start the next pass.

Example

* Process through a cursor, using the inner SCAN to
* make some change to the records. The outer DO ... WHILE
* doesn't move the record pointer.
GO TOP
DO WHILE NOT EOF()
  lcKey = KeyField
  SCAN WHILE KeyField = lcKey
   * Do something with the set of records having
   * this key in common.
  ENDSCAN
ENDDO

* Generate a unique file name.
* Working around non-uniqueness of SYS(3)
cFileName = SYS(3) + ".TMP"
DO WHILE FILE(cFileName)
  cFileName = SYS(3) + ".TMP"
ENDDO

See Also

Exit, For, For Each, Loop, Scan