A colleague sent me an interesting question: What is the best way to abort a SAS/IML program? For example, you might want to abort a program if the data is singular or does not contain a sufficient number of observations or variables.
As a first attempt would be to try to use the ABORT statement, which is discussed in the article "how to stop processing your SAS/IML program if a certain condition is met". The following program contains a subtle error in logic:
proc iml; ErrorFlag = 1; if ErrorFlag then ABORT; /* does not work as intended */ print "Execute statement 1"; print "Execute statement 2"; quit;
This approach does not work because the ABORT statement terminate the IML procedure, but then SAS continues to process the next statement, which happens to be a PRINT statement. Since a PRINT statement is not a valid global SAS statement, an error occurs.
ERROR 180-322: Statement is not valid or it is used out of proper order.
Use DO blocks or reverse the logic
The obvious solution is to use an ELSE statement to specify the conditional code to execute within PROC IML. At parse time, the PROC IML parser will process all DO blocks of an IF-THEN/ELSE statement. However, at run time only the DO block for the "true" condition will be executed. Consequently, the following statements parse and run without error:
if ErrorFlag then ABORT; else do; print "Execute statement 1"; print "Execute statement 2"; end;
An alternative solution is to forget about using the ABORT statement and reverse the conditional logic:
ErrorFlag = 1; if ^ErrorFlag then do; print "Execute statement 1"; print "Execute statement 2"; end; quit;
In this alternative solution, the PRINT statements are executed if the ErrorFlag variable is zero; otherwise they are not. In either case, the QUIT statement is the first executable statement after the IF-THEN/ELSE statement, so the procedure ends.
In a complex analysis, defining a module is a good way to encapsulate a task, be it validating data or computing with the validated data. For example, suppose your algorithm requires data that has at least three variables and no missing values. The following program divides the error checking task and the computational task between two modules:
start CheckData(x); if ncol(x) < 3 then return(1); /* error */ if countmiss(x) > 0 then return(2); /* error */ return(0); /* no error */ finish; start MyComputation(x); /* only called on validated data */ print "Execute statement 1"; print "Execute statement 2"; finish; /* read x; validate data properties */ use MyData; read all var _num_ into x; close MyData; ErrorFlag = CheckData(x); if ^ErrorFlag then run MyComputation(x); quit;
With regards to defining modules, I'll also mention that you can use the RETURN statement anywhere in a module. This means that if you encounter a situation in the MyComputation module that requires you to abort the computation, you can use the RETURN statement to leave the module. Consequently, modules offer a robust mechanism for aborting a computation if an error condition occurs.
There are other ways to organize your program so that statements can conditionally execute if there is an error. However, I will stop here. Do you have a favorite way to handle errors in PROC IML? Leave a comment.