FCMP Procedure

Concepts: FCMP Procedure

Creating Functions and Subroutines

PROC FCMP enables you to write functions and CALL routines using DATA step syntax. PROC FCMP functions and CALL routines are stored in a data set and can be called from several SAS/STAT, SAS/ETS, or SAS/OR procedures such as the NLIN, MODEL, and NLP procedures. You can create multiple functions and CALL routines in a single FCMP procedure step.
Functions are equivalent to routines that are used in other programming languages. They are independent computational blocks that require zero or more arguments. A subroutine is a special type of function that has no return value. All variables that are created within a function or subroutine block are local to that subroutine.

Creating Functions and Subroutines: An Example

This following example defines a function and a subroutine. The function begins with the FUNCTION statement, and the subroutine begins with the SUBROUTINE statement. The DAY_DATE function converts a date to a numeric day of the week, and the INVERSE subroutine calculates a simple inverse. Each ends with an ENDSUB statement.
proc fcmp outlib =
sasuser.MySubs.MathFncs;

   function day_date(indate, type $);
      if type = "DAYS" then wkday = weekday(indate);
      if type = "YEARS" then wkday = weekday(indate*365);
      return(wkday);
   endsub;

   subroutine inverse(in, inv);
      outargs inv;
      if in = 0 then inv = .;
      else inv = 1/in;
   endsub;

run;
The function and subroutine follow DATA step syntax. Functions and subroutines that are already defined in the current FCMP procedure step, as well as most DATA step functions, can be called from within these routines as well. In the example above, the DATA step function WEEKDAY is called by DAY_DATE.
The routines in the example are saved to the data set sasuser.MySubs, inside a package called MathFncs. A package is any collection of related routines that are specified by the user. It is a way of grouping related subroutines and functions within the data set. The OUTLIB= option in the PROC FCMP statement tells PROC FCMP where to store the subroutines that it compiles, and the LIBRARY= option tells it where to read in libraries (C or SAS).
Note: Function and subroutine names must be unique within a package. However, different packages can have subroutines and functions with the same names. To select a specific subroutine when there is ambiguity, use the package name and a period as the prefix to the subroutine name. For example, to access the MthFncs version of INVERSE, use MthFncs.inverse.

Writing Your Own Functions

Advantages of Writing Your Own Functions and CALL Routines

PROC FCMP enables you to write functions and CALL routines by using DATA step syntax. The advantages of writing user-defined functions and CALL routines include the following:
  • The function or CALL routine makes a program easier to read, write, and modify.
  • The function or CALL routine is independent. A program that calls a routine is not affected by the routine's implementation.
  • The function or CALL routine is reusable. Any program that has access to the data set where the function or routine is stored can call the routine.
Note: PROC FCMP routines that you create cannot have the same name as built-in SAS functions. If the names are the same, then SAS generates an error message stating that a built-in SAS function or subroutine already exists with the same name.

Writing a User-Defined Function

The following program shows the syntax that is used to create and call a PROC FCMP function from a DATA step. This example computes the study day during a drug trial.
The example creates a function named STUDY_DAY in a package named TRIAL. A package is a collection of routines that have unique names and is stored in the data set sasuser.funcs. STUDY_DAY accepts two numeric arguments, intervention_date and event_date. The body of the routine uses DATA step syntax to compute the difference between the two dates, where days that occur before intervention_date begin at -1 and become smaller, and days that occur after and including intervention_date begin at 1 and become larger. This function never returns 0 for a study day.
STUDY_DAY is called from DATA step code as if it were any other function. When the DATA step encounters a call to STUDY_DAY, it will not find this function in its traditional library of functions. Instead, SAS searches each of the libraries or data sets that are specified in the CMPLIB system option for a package that contains STUDY_DAY. In this example, STUDY_DAY is located in sasuser.funcs.trial. The program calls the function, passing the variable values for start and today, and returns the result in the variable SD.
options pageno=1 nodate;

proc fcmp outlib=sasuser.funcs.trial;
   function study_day(intervention_date, event_date);
       n=event_date-intervention_date;
       if n <= 0 then
       n=n+1;
       return (n);
   endsub;

options cmplib=sasuser.funcs;
data _null_;
   start = '15Feb2006'd;
   today = '27Mar2006'd;
   sd = study_day(start, today);
   put sd=;
run;
Output from the STUDY_DAY User-Defined Function

sd=41

Using Library Options

You can use PROC FCMP with the OUTLIB= or INLIB= options. The syntax for this procedure has the following form:
proc fcmp
outlib=libname.dataset.package
          inlib=in-libraries;
routine-declarations;
The OUTLIB= option is required and specifies the package where routines declared in the routine-declarations section are stored.
Routines that are declared in the routine-declarations section can call FCMP routines that exist in other packages. To find these routines and to check the validity of the call, SAS searches the data sets that are specified in the INLIB= option. The format for the INLIB= option is as follows:
inlib=library.dataset
inlib=(library1.dataset1 library2.dataset2 ... libraryN.datasetN)
inlib=library.datasetM - library.datasetN
If the routines that are being declared do not call FCMP routines in other packages, then you do not need to specify the INLIB= option.

Declaring Functions

You declare one or more functions or CALL routines in the routine-declarations section of the program. A routine consists of four parts:
  • a name
  • one or more parameters
  • a body of code
  • a RETURN statement
You specify these four parts between the FUNCTION or SUBROUTINE keyword and an ENDSUB keyword. For functions, the syntax has the following form:
function
name(argument-1, ... , argument-n);
   program-statements;
   return (expression);
endsub;
After the FUNCTION keyword, you specify the name of the function and its arguments. Arguments in the function declaration are called formal arguments and can be used within the body of the function. To specify a string argument, place a dollar sign ($) after the argument name. For functions, all arguments are passed by value. This means that the value of the actual argument, variable, or value that is passed to the function from the calling environment is copied before being used by the function. This copying ensures that any modification of the formal argument by the function does not change the original value.
The RETURN statement is used to return a value to a function. The RETURN statement accepts an expression that is enclosed in parentheses, and contains the value that is returned to the calling environment. The function declaration ends with an ENDSUB statement.

Declaring CALL Routines

CALL routines are declared within routine-declarations by using the SUBROUTINE keyword instead of the FUNCTION keyword. Functions and CALL routines have the same form, except CALL routines do not return a value, and CALL routines can modify their parameters. You specify the arguments to be modified on an OUTARGS statement. The syntax of a CALL routine declaration is as follows:
subroutine
name(argument-1, ..., argument-n);
   outargs out-argument-1, ..., out-argument-N;
   program-statements;
   return;
endsub;
The formal arguments that are listed in the OUTARGS statement are passed by reference instead of by value. This means that any modification of the formal argument by the CALL routine will modify the original variable that was passed. It also means that the value is not copied when the CALL routine is invoked. Reducing the number of copies can improve performance when you pass large amounts of data between a CALL routine and the calling environment.
A RETURN statement is optional within the definition of the CALL routine. When a RETURN statement executes, execution is immediately returned to the caller. A RETURN statement within a CALL routine does not return a value.

Writing Program Statements

The program-statements section of the program is a series of DATA step statements that describe the work to be done by the function or CALL routine. Most DATA step statements and functions are accessible from PROC FCMP routines. The DATA step file and the data set I/O statements (for example, INPUT, FILE, SET, and MERGE) are not available from PROC FCMP routines. However, some functionality of the PUT statement is supported. See PROC FCMP and DATA Step Differences for more information.

Using Functions as Formats

PROC FCMP enables you to use functions to format values by first performing a function on a value. By using a function to format values, you can create customized formats. PROC FORMAT describes the process. For more information, see PROC FORMAT, “Using a Function to Format Values,” in the Base SAS Procedures Guide.

Using DATA Step Statements with PROC FCMP

You can use DATA step statements with PROC FCMP. However, there are some differences in the syntax and functionality for PROC FCMP. See PROC FCMP and DATA Step Differences for a list of statements and the differences.
The behaviors of the DROP, KEEP, FORMAT, and LENGTH statements are the same in PROC FCMP and in the DATA step.
The following DATA step statements are not supported in PROC FCMP:
  • DATA
  • SET
  • MERGE
  • UPDATE
  • MODIFY
  • INPUT
  • INFILE
The support for the FILE statement is limited to LOG and PRINT destinations in PROC FCMP. The OUTPUT statement is supported in PROC FCMP, but it is not supported within a function or subroutine.
The following statements are supported in PROC FCMP but not in the DATA step:
  • FUNCTION
  • STRUCT
  • SUBROUTINE
  • OUTARGS