A Function is some non-REXX code (supplied by the REXX interpreter, or contained within some add-on, binary executable known as a function library) that your REXX script can call, perhaps passing some data to it upon which the Function operates. A Function performs its work, and then returns a value (which may be an error number or error string, or some other data). When a REXX script calls a Function, the script halts until the Function has completed its work and returned its value.

There are numerous Functions built into REXX, and these are automatically available to be called by a script. Functions contained within add-on libraries can also be called by your script, but first you usually must issue REXX's RXFUNCADD() Function to let the interpreter know where to find the library containing the desired function, as well as what the function's name is.

Just like instruction keywords such as SAY, a Function has a name which you use to call the Function. For example, REXX has a built-in Function named TIME. A Function is called by typing its name (case doesn't matter) immediately followed by ( (ie, there must be no space inbetween the name and open parenthesis). After the (, you put any text/data that you wish passed to the Function, and finally a closing parenthesis ). Here's an example of calling the TIME Function:

TIME() /* Some interpreters would require this to be called as a subroutine */
You'll note that we didn't place any text/data inbetween the parentheses, because we aren't passing any arguments to TIME.


Using a function's return value

The TIME Function happens to return a string containing the hours, minutes, and seconds of the current time (in 24 hour, military time), each separated by a colon. For example, the time may be reported as 01:30:44 (ie, AM).

Since a Function returns some data, you can say that the Function has a value just like a variable. Therefore, you can treat a Function exactly like a variable that has a value, except that this is a read-only variable (ie, you can't assign a new value to a Function's name). For example, just like you can assign the value of one variable to another variable, you can assign the return value of a Function to a variable.

My_Time = TIME()
The preceding instruction assigns the value of the TIME Function (ie, the current time) to the variable My_Time. For example, after executing that instruction, My_Time's value may be the string 01:30:44.

You can also use a Function anywhere you would use a variable's value. For example, here we use the value of TIME in the Conditional IF/THEN instruction. We check to see if TIME's value is 10:00:00 (ie, 10AM), and if so, we SAY "It's time".

/* Check for 10AM */
IF TIME() == '10:00:00' THEN SAY "It's time"
So here you see a primary difference between a REXX Keyword and a Function. A Function has a value, and can be used as if it were a read-only variable. REXX Keywords do not have values, and also are used only at specific places within an instruction, sometimes only in conjunction with other keywords.


Passing arguments

TIME also allows one argument. Sometimes, arguments can be optionally omitted, as we did previously with TIME. TIME allows a string to be passed which must be one of the following, depending upon how you wish TIME to format the returned time string: CIVIL, ELAPSED, HOURS, LONG, MINUTES, SECONDS, NORMAL, or RESET. If we specify the CIVIL option, then the returned time string takes the format of the hour and minutes in 12 hour format, followed by AM or PM, for example, 10:00am. Here we assign that return to My_Time.

My_Time = TIME('CIVIL')
Note that CIVIL was placed in quotes to make sure that REXX regards it as a literal string, rather than a variable name whose value should be passed to TIME. You can alternately specify variable names as arguments to a Function. In that case, REXX, as usual, replaces the variable name with its value, and that value is what gets passed to the Function as the argument. Here, we pass the string CIVIL using a variable.
My_Option = 'CIVIL'
My_Time = TIME(My_Option)

More examples of using functions

Here are some more examples of using a Function's (returned) value.

/* Use TIME's value in a conditional loop (ie, loop until 10 o'clock) */
DO UNTIL TIME() == '10:00:00'
   SAY "It's not 10 o'clock yet"
END

/* Use TIME's value as an argument for the SAY instruction (ie, print the time) */
SAY TIME()
You can even use a Function's value as an argument to another Function. Here we use the returned value of TIME as an argument to the LENGTH Function. The LENGTH Function allows one argument -- any string or numeric value -- and it returns the number of characters in that argument. Then, we use the returned value of LENGTH as an argument for the SAY instruction.
/* Use TIME's value as an argument for the LENGTH
   Function which in turn supplies an arg for SAY (ie, print
   the number of characters in the time) */
SAY LENGTH(TIME('CIVIL'))
In this case, REXX executes the lowest nested function first. Here, that's TIME. TIME is called with its argument "CIVIL'. The returned value of TIME (let's assume that it's the string 10:00am) is then passed as an argument to LENGTH. LENGTH would return the value 7 (because there are 7 characters in the string 10:00am). This 7 is then the argument for SAY, and therefore a 7 gets printed to the screen.


Throwing away a function's return value

If you wish to not use the Function's value in any way (ie, you're not assigning it to a variable, or using its value in a conditional expression, or in a conditional loop, or as an argument itself), then you must place the keyword CALL before the Function name to toss the returned value away, and omit the parentheses around any arguments (or REXX will raise a SYNTAX error). When you use the CALL keyword, you are calling the function as a subroutine. For example, here we call the DIRECTORY Function, supplying an argument that is the directory we desire to be made the current one. DIRECTORY returns a string telling what is the current directory before the change (ie, the previously current directory). We just throw away that return value.

CALL DIRECTORY 'C:\TEMP'
Actually, the return value is not thrown away when you use CALL, but rather, REXX stores it in the special variable named RESULT.

Note: Reginald supports using the CALL keyword in conjunction with the parentheses around the arguments. So you can do:

CALL DIRECTORY( 'C:\TEMP' )
Alternately, if you wish the option to throw away return values from functions at will, without needing to use the CALL keyword, you can put the following line at the top of your script:

ADDRESS NULL

But note that this prevents you from launching external (non-REXX) programs just by typing the program's name. You would instead need to use the ADDRESS keyword to launch such a program.


Omitting arguments

When a Function allows more than one argument, each argument must be separated by a comma. For example, the LINEOUT Function allows 3 arguments. The first arg is the name of the file to which data is written. The second arg is the actual data to be written (ie, a string, numeric value, variable's value, or Function's value). The third arg is a 1 if you want to overwrite any existing file, or omit the arg if you wish to append the data to the end of any existing file. For example, here we write the string more data to the file C:\DATAFILE, overwriting any existing file.

err = LINEOUT('C:\DATAFILE', 'more data', 1)
Note that I added blank spaces around the arguments for readability. This is always optional.

To omit an arg, simply put its comma, with nothing before the comma. For example, if you omit the first arg to LINEOUT, then the Function defaults to writing the line to the display (ie, same thing as the SAY command). Here I omit the first arg.

err = LINEOUT(, 'more data', )
Omitting the last arg is even easier. You just omit it, and then you can omit the comma of the previous arg too (ie, which separates the two args).
err = LINEOUT(, 'more data')
In fact, if you wish to omit several args, and they are all at the end of the calling template, then you just omit those args, as well as any trailing comma (after the last arg that isn't omitted).


Built-in functions

The following sections list the built-in functions you'll find in most interpreters. This book lists the functions by type, for example, all of the functions that operate upon files or directories are listed on one page named "Files and Directories".

For each function, a short description is given of its purpose.

Below this, its template is shown. The template lists the arguments passed to the function, and gives a description of the purpose of each argument. Arguments that you must specify are listed in blue and arguments that you may specify or omit are listed in red. You can replace those arguments in the template with whatever items you wish to pass, be it the value of some variable, a literal string, the return value of another function, etc.

Below the template, the return value of the function is described.

Below this are any notes about the function.

Finally, there is a chart showing several examples of calling the function with various example arguments (literal strings in these examples), and the return value for each example is shown on the right-hand side of the chart.

Note: If you pass incorrect arguments to a built-in function, then this raises a SYNTAX error. Conditions are discussed later. There are many reasons why arguments may be seen as incorrect, for example, passing more arguments to a function than it allows, or omitting required arguments. Another situation could be passing a non-numeric value when the function expects a numeric value. Another situation could be passing some unrecognized value for an argument when the function expects the argument's value to one of a limited choice of specific values. And there are other situations where the arguments may be seen as incorrect.

In addition to raising SYNTAX condition if the arguments are seen as incorrect, the stream (ie, file create/read/write) functions may raise the NOTREADY condition if something goes wrong with the actual file operation, for example, LINEOUT() failing to properly write a line to the file.