When you write a SAS function or subroutine in PROC FCMP, there are a few things we should be aware of. Where does SAS store the functions? How are the functions stored? And how do we tell SAS where to look for user-defined subroutines and functions? In this post, I will answer these questions with a few simple code examples.

The Outlib Option

SAS stores user-defined functions and subroutines in data sets. When we define a function, we use the Outlib Option to tell SAS where to store the function. The Outlib Options accepts a three-level argument. Unlike most other options. The three levels consist of a libname, a data set name and a package name. A package is the structure that the function is saved and retrieved to/from. A data set can contain multiple packages and a package can contain multiple functions.

Consider the code below. Here, I define the functions test() and test2() in the fun package in the fun data set. This code confirms a few important points. First of all, a package can contain multiple functions. Secondly, if the specified package already exists, SAS appends the new function to the existing package.

proc fcmp outlib=work.fun.fun;
    function test();
        return(100);
    endsub;
quit;
 
proc fcmp outlib=work.fun.fun;
    function test2();
        return(200);
    endsub;
quit;

Options Cmplib

When we save a function in a data set, we have to tell SAS where to find it. We do so with the Cmplib System Option. Unlike the Outlib Option, the Cmplib System Option takes a two-level argument. Thus we must only specify the libname and data set name. Consequently, SAS compiles the functions in all packages in the specified data set.

The Cmplib system option handles multiple arguments. Unlike most SAS Options, that accepts lists of arguments, Cmplib searches from right to left. Consider the code below. First, I define the function MyFunc() (returns 1) in the fun1 data set. Next, I define a similar-named function (returns 2) in the fun2 data set. Now, let us put Options Cmplib to the test. I list work.fun2 first and work.fun1 last in the argument list. SAS will compile the functions from right to left. When SAS encounters a similar-named function during the search in work.fun2, it ignores this function. Consequently, MyFunc() returns 1 in the following data step.

proc fcmp outlib=work.fun1.fun;
    function MyFunc();
        return (1);
    endsub;
quit;
 
proc fcmp outlib=work.fun2.fun;
    function MyFunc();
        return (2);
    endsub;
quit;
 
options cmplib=(work.fun2 work.fun1);
 
data test;
    a=MyFunc();
run;

As a side note, we can not specify from which package SAS should read a function from in the Data Step. However, this is possible in PROC FCMP. If two similar-names functions exist in different packages in the same data set, you can use a two level function call in PROC FCMP like this.

proc fcmp outlib=work.f.f1;
    function test();
        return(1);
    endsub;
quit;
 
proc fcmp outlib=work.f.f2;
    function test();
        return(2);
    endsub;
quit;
 
options cmplib=work.f;
 
proc fcmp;
    a=f1.test();
    b=f2.test();
    put a= / b=;
quit;

Summary

In this post, we have investigated how and where SAS stores user defined function. The same principle holds for subroutines. We have seen that the Outlib Option in the PROC FCMP Statement along with the Cmplib System options are crucial to control where to write and read functions. Furthermore, we have introduced the concept of packages and seen how SAS handles similar-named functions. Though SAS can handle this, I recommend that you do not store similar-named functions.

For more PROC FCMP posts, read Data Step Array Vs. PROC FCMP Array in SAS, The SAS Hash Object as a Cache in PROC FCMP and FCMP Functions Vs Subroutines.

You can download the entire code from this post here.