SAS®9 Techie Tip
By Peter Eberhardt

How many times have you tried to simplify your code with LINK/RETURN statements?

How much grief have you put yourself through trying to create macro functions to encapsulate business logic?

How many times have you uttered "If only I could call this DATA Step as a function"?

If any of these statements describe you, then the new features of PROC FCMP are for you. If none of these statements describe you, then you really need the new features of PROC FCMP.

What I am about to describe is not so much a techie tip, but more a brief introduction to the SAS PROC FCMP and its new ability to create your own DATA Step functions and CALL routines using DATA Step syntax. If you are a statistician you may be familiar with PROC FCMP; a number of SAS/STAT® and SAS/ETS® procedures already had the ability to call functions created with PROC FCMP. This ability now extends to the DATA Step programmer. For a concise overview of PROC FCMP see the paper by Jason Secosky.

You can create functions, as my example shows. You can also create CALL routines. You can pass in ARRAYS. And your functions can even be recursive. All in all, PROC FCMP will allow for creative encapsulation of your programming and business logic.

Getting started:
You need a library to store the functions. In my example I will be using a WORK. Although this is fine for developing your functions, you will need to keep them in a permanent location where all users can access them. You also have to tell SAS where to find the functions; the OPTIONS CMPLIB= statement does this.

Example:
I commonly have to do some simple division of two values in a data set. This is simple until we discover that some of the variables have unexpected missing values, or a value of 0. The following code shows the “old way” by explicitly checking values before each division; even with only two divisions my code is becoming repetitive. The “new way” uses two functions I created to do the same divisions; note how much cleaner the new code is.

* create a test data set;
DATA wonkyData;
drop i;
do i = 1 to 100;
if mod(i,3) = 0
then divisor = 0;
else if mod(i,13) = 0
then divisor = .M;
else divisor = i;
dividend1 = (int(ranuni(1) * 10) * i ) + (int(ranuni(2) * 10) * i );
dividend2 = dividend1 * 2;
output;
end;
RUN;

* process the data;
* divByMissingResult set to .X missing so it is easy to see;
* a common problem is to use IF divisor = . ;
DATA oldWay;
set wonkyData;
retain divByZeroResult 0
divByMissingResult1 .X
divByMissingResult2 .F ;
drop divByZeroResult divByMissingResult1 divByMissingResult2;
* only 2 tests, but it could be more;
if divisor = 0 then answer1 = divByZeroResult;
else if missing(divisor) then answer1 = divByMissingResult1;
else answer1 = dividend1 / divisor;

if divisor = 0 then answer2 = divByZeroResult;
else if missing(divisor) then answer2 = divByMissingResult2;
else answer2 = dividend2 / divisor;
run;

*----------------------------------------------;
* repeat, but use a function ;
*----------------------------------------------;

* outlib= tells FCMP where to store the functions;
PROC FCMP outlib=work.funcs.math;

* this function takes explicit values for divByZeroResult and divByMissingResult;
FUNCTION divX(dividend, divisor, divByZeroResult, divByMissingResult);
if divisor = 0 then answer = divByZeroResult;
else if missing(divisor) then answer = divByMissingResult;
else answer = dividend / divisor;
return(answer);
ENDSUB;

* this function uses fixed values for divByZeroResult and divByMissingResult;
FUNCTION div(dividend, divisor);
if divisor = 0 then answer = 0;
else if missing(divisor) then answer = .F;
else answer = dividend / divisor;
return(answer);
ENDSUB;
RUN;

* tell SAS where to look for functions;
options cmplib= work.funcs;
* much simpler code;
DATA newWay;
set wonkyData;
answer1 = divX(dividend1, divisor, 0, .X);
answer2 = div(dividend2, divisor);
RUN;

* compare the results;
PROC COMPARE BASE=oldWay COMPARE=newWay;
RUN;

SAS and all other SAS Institute Inc. product or service names are registered trademarks \or trademarks of SAS Institute Inc. in the USA and other countries. ® indicates USA registration. Other brand and product names are trademarks of their respective companies. Copyright © 2008, SAS Institute Inc. All rights reserved.