SAS programmers who have experience with other programming languages sometimes wonder whether the SAS language supports statements that are equivalent to the "break" and "continue" statements in other languages. The answer is yes. The LEAVE statement in the SAS DATA step is equivalent to the "break" statement. It provides a way to immediately exit from an iterative loop. The CONTINUE statements in the SAS DATA step skips over any remaining statements in the body of a loop and starts the next iteration.
Not all languages in SAS support those statements. The SAS/IML language added support for the LEAVE and CONTINUE statements in SAS/IML 15.1. However, you can use an alternative syntax to implement the same logical behavior, as shown in this article.
To review the syntax of various DO, DO-WHILE, and DO-UNTIL loops in SAS, see "Loops in SAS."
The LEAVE statement
The LEAVE statement exits a DO loop, usually as part of an IF-THEN statement to test whether a certain condition is met.
To illustrate the LEAVE statement consider a DATA step that simulates tossing a coin until "heads" appears. (Represent "tails" by a 0 and "heads" by a 1, chosen at random.) In the following SAS DATA step, the DO WHILE statement is always true, so the program potentially contains an infinite loop. However, the LEAVE statement is used to break out of the loop when "heads" appears. This coin-tossing experiment is repeated 100 times, which is equivalent to 100 draws from the geometric distribution:
/* toss a coin until "heads" (1) */ data Toss; call streaminit(321); do trial = 1 to 100; /* simulate an experiment 100 times */ count = 0; /* how many tosses until heads? */ do while (1); /* loop forever */ coin = rand("Bernoulli", 0.5); /* random 0 or 1 */ if coin = 1 then LEAVE; /* exit loop when "heads" */ count + 1; /* otherwise increment count */ end; output; end; keep trial count; run; |
Some people like this programming paradigm (set up an infinite loop, break out when a condition is satisfied), but I personally prefer a DO UNTIL loop because the exit condition is easier to see when I read the program. For example, the code for each trial could be rewritten as
count = 0; /* how many tosses until heads? */ done = 0; /* initialize flag variable */ do until (done); /* exit loop when "heads" */ coin = rand("Bernoulli", 0.5); /* random 0 or 1 */ done = (coin = 1); /* update flag variable */ if ^done then /* otherwise increment count */ count + 1; end; output; |
Notice that the LEAVE statement exits only the inner loop. In this example, the LEAVE statement does not affect the iteration of the DO TRIAL loop.
The CONTINUE statement
The CONTINUE statement tells the DATA step to skip the remaining body of the loop and go to the next iteration. It is used to skip processing when a condition is true. To illustrate the CONTINUE statement, let's simulate a coin-tossing experiment in which you toss a coin until "heads" appears OR until you have tossed the coin five times. In the following SAS DATA step, if tails (0) appears the CONTINUE statement executes, which skips the remaining statements and begins the next iteration of the loop. Consequently, the DONE=1 assignment is not executed when coin=0. Only if heads (1) appears does the DONE variable get assigned to a nonzero value, thereby ending the DO-UNTIL loop:
data Toss2; call streaminit(321); do trial = 1 to 100; /* simulate an experiment 100 times */ done = 0; /* initialize flag variable */ do count = 0 to 4 until (done); /* iterate at most 5 times */ coin = rand("Bernoulli", 0.5); /* random 0 or 1 */ if coin = 0 then CONTINUE; /* tails: go to next iteration */ done = 1; /* exit loop when "heads" */ end; output; end; keep trial count; run |
The CONTINUE statement is not strictly necessary, although it can be convenient. You can always use an IF-THEN statement to bypass the remainder of the loop, as follows:
coin = rand("Bernoulli", 0.5); /* random 0 or 1 */ /* wrap the remainder of the body in an IF-THEN statement */ if coin ^= 0 then do; /* heads: abort the loop */ done = 1; /* exit loop when "heads" */ /* other computations, as needed */ end; |
The CONTINUE and the LEAVE statements are examples of "jump statements" that tell the program the location of the next statement to execute. Both statements jump to a statement that might be far away. Consequently, programs that contain these statements are less structured than programs that avoid them. I try to avoid these statements in my programs, although sometimes the LEAVE statement is the simplest way to abort a loop when the program has to check for multiple exit conditions.
While we are on the topic, another jump statement in SAS is the GOTO statement, which can be used to emulate the behavior of LEAVE and CONTINUE. I avoid the GOTO statement because I think programs are easier to read and maintain when the logical flow of the program is controlled by using the DO-WHILE, DO-UNTIL, and IF-THEN statements. I also use those control statements in the SAS/IML language, which did not support the CONTINUE or LEAVE statements until 15.1 (although it has always supported the GOTO statement).
What are your views? Do you use the CONTINUE or LEAVE statement to simplify the error-handling logic of your programs? Or do you avoid them in favor of a more structured programming style? Why?
4 Comments
I would use the LEAVE statement when I am searching for something (e.g. my car keys) using a DO loop. When I have found what I was looking for, further looping does not make sense anymore, so I break out of the DO loop using LEAVE:
data _null_;
do i=1 to n;
set houseitems point=i nobs=n;
found = (item eq 'my car keys');
if found then leave;
end;
put found=;
stop;
run;
Nice tip Rick!
In the 'leave' examples, the count variable is not incremented for the iteration where the leave condition becomes true, so the answer is 1 short.
Thanks for writing. It depends what you are counting. As written, 'count' records the number of tails before the appearance of the first heads. Thus 'count' can be 0, 1, 2, .... If you want to count the number of tosses before the appearance of the first heads, then you would need to add 1, as you point out, and 'count' would have the values 1, 2, 3,....