Modules with Optional and Default Arguments

You can define a module that has optional arguments. You can also assign default values to optional arguments. Optional arguments can be skipped when the module is called. Optional arguments are supported for all user-defined modules, both functions and subroutines.

By convention, optional arguments appear at the end of a module argument list.

Optional Arguments without Default Values

To designate an argument as optional, type an equal sign (=) after the argument when defining the module. Arguments that are not followed by an equal sign are required arguments. Optional arguments can be skipped when you call the module. If you skip an optional argument, the local variable is set to the empty matrix, as shown in the following example:

proc iml;
start MyAdd(x, y=);
   if ncol(y)=0 then return(x); /* y is empty matrix */
   return(x+y);
finish;

z = MyAdd(5);   /* z = 5 */
w = MyAdd(5, 3);/* w = 8 */

When the MyAdd module is called the first time, the second argument is skipped. Inside the MyAdd function, the local variable y is set to the empty matrix: it has no rows and no columns. Consequently, the IF-THEN condition is true and the function returns the value of the local variable x.

When the MyAdd module is called the second time, the second argument is provided. Inside the MyAdd function, the local variable y is not empty. Consequently, the IF-THEN condition is false and the function returns the sum of the two arguments.

Because the optional argument appears last in the module argument list, you can call the argument with a single argument. You can also skip optional arguments by not providing an argument when the module is called. For example, the following statement is valid syntax:

z = MyAdd(5, );   /* skip second argument */

In previous versions of SAS/IML software, you could skip any parameter in a user-defined subroutine. With the new syntax, you can skip only those arguments that are explicitly designated as optional.

Detecting Skipped Arguments

Arguments can be skipped in the call by using white space and a comma, or by simply not supplying the maximum number of arguments declared in the START statement.

The ISSKIPPED function enables you to determine at run time whether a module is being called with a skipped argument. The ISSKIPPED function returns 1 if the argument to the function is skipped, and 0 otherwise. For example, the following function returns the inner product (dot product) of two column vectors. If the function is called with a single argument, the function returns the inner product of the first argument with itself. If the function is called with two arguments, the function returns their inner product.

start MyDot(x, y=);
   if isskipped(y) then return(x`*x);
   return(x`*y);
finish;
z = MyDot({1,2,3});          /* z = 14 */
w = MyDot({1,2,3}, {-1,0,1});/* w = 2 */

Optional Arguments with Default Values

You can assign a default value for an optional argument by specifying the value after the equal sign in the module argument list. For example, you might define the following module:

start MySum(x=1, y=2);
   return(x+y);
finish;

In this module, if the first argument is skipped, the local variable x is assigned the value 1. Similarly, if the second argument is skipped, the local variable y is assigned the value 2. Consequently, the syntax that assigns the default values is logically equivalent to the following statements:

   if IsSkipped(x) then x=1;
   if IsSkipped(y) then y=2;

Optional Arguments with Constant Default Values

As indicated in the previous section, you can assign a default value for an optional argument by specifying the value after the equal sign in the module argument list. For example, the following module returns the vector sum $ax + y$ for vectors $x$ and $y$ and constant $a$. If the $a$ parameter is not specified, a default value of 1 is used. The default value is specified as follows:

start axpy(a=1, x, y=); /* compute ax + y */
   if isskipped(y) then return(a#x);
   else                 return(a#x + y);
finish;

p = {1 2 3};
q = {1 1 1};
z1 = axpy( , p);    /* a and y skipped; a has default value */
z2 = axpy(2, p);    /* y skipped */
z3 = axpy(2, p, q); /* no arguments are skipped */
print z1, z2, z3;

Figure 6.9: Default Values and Skipped Arguments

z1
1 2 3

z2
2 4 6

z3
3 5 7


The module is called three times. Each call uses a different combination of skipped arguments. The results are shown in Figure 6.9. During the first call, the local variable a is set to 1 inside the module, whereas y is an empty matrix. During the second call, a is set to 2 and y is an empty matrix. During the third call, no arguments are skipped.

Optional Arguments with Data-Dependent Default Values

In the previous section, a constant value was used as the default value of an argument. You can also provide an expression for a default value. If the argument is skipped, the expression is evaluated and assigned to the local variable for the skipped argument. The expression can refer to other arguments, so the default values are data dependent.

For example, the following module standardizes columns of a matrix:

start stdize(x, loc=mean(x), scale=std(x));
   return ( (x-loc)/scale );
finish;

x = {1, 1, 0, -1, -1};
z = stdize(x);             /* use default values */

center = 1;  s  = 2;
z1 = stdize(x,  center);    /* skip 3rd argument */
z2 = stdize(x,        , s); /* skip 2nd argument */
z3 = stdize(x,  center, s); /* no arguments are skipped */
print z z1 z2 z3;

Figure 6.10: Data-Dependent Default Values

z z1 z2 z3
1 0 0.5 0
1 0 0.5 0
0 -1 0 -0.5
-1 -2 -0.5 -1
-1 -2 -0.5 -1


The module is called four times. The results are shown in Figure 6.10. As discussed previously, the syntax that defines the default arguments is logically equivalent to beginning the module with the following two statements:

if IsSkipped(loc)   then loc=mean(x);
if IsSkipped(scale) then scale=std(x);

During the first call, the second and third arguments are skipped. The local variable loc is set to the mean values of the columns of the required argument, x, and the local variable scale is set to the standard deviation of the columns of x. The MEAN and STD functions are evaluated only when the second and third arguments, respectively, are skipped.

During the second call, the third argument is skipped. The local variable loc is set to the value 1, and the local variable scale is set to the standard deviation of the columns of x.

During the third call, the local variable loc is set to the mean value of the columns of x, and the local variable scale is set to 2. During the fourth call, no arguments are skipped.

The argument list is parsed from left to right. Consequently, a good programming practice is to use data-dependent expressions that depend only on arguments that appear earlier in the argument list. The syntax does not forbid referring to variables that appear later in the argument list, but it is often an error to evaluate an expression that involves unassigned (empty) matrices.

Data-dependent expressions can also use global variables that are specified in the GLOBAL statement. For example, the following statements use global variables to form a data-dependent default value:

start MyFunc(x, a=max(1,gMax)) global(gmax);
   return(a#x);
finish;

gMax = 2;
y = MyFunc(5);

Default values for skipped arguments apply only to local variables in modules. The GLOBAL statement does not support default arguments.