Function or Subroutine Invocation A function is a routine which is called using the syntax: symbolorstring(arguments) whereas a subroutine is a routine which is called using the syntax: CALL symbolorstring arguments In each case the method of searching for and executing the routine is that detailed below. What happens when the routine returns depends upon whether the routine was called as a function or a subroutine: a function is required to return a result, whereas a subroutine need not. Also, the result from a subroutine, if any, is assigned to the special variable RESULT after the subroutine finishes. The remainder of this section describes the features which are common to subroutines and functions. There are three types of routine, which are searched in the following order: 1. Internal routines. These are not searched if the routine name is a string constant. 2. Built-in routines (a list of which is given in the next section). Note that if the routine name is a string constant, it must be in upper case for the search to succeed. 3. External routines. An internal routine is one which is stored in the currently executing program. It is introduced by a label, which takes the form name: and may be placed anywhere at the start of an instruction (or on its own on a line). When an internal function is called, all labels are checked. When a match is found, interpretation jumps to the instruction immediately following the label, and continues until the next RETURN statement (or EXIT, or the end of the program). When RETURN is reached execution continues from the point of the call (but since reaching an EXIT or the end of the program causes the program to terminate, execution cannot continue in these cases). The arguments to an internal routine may be found using the "PARSE ARG" instruction. A result may be returned to the caller by writing it as a parameter to the RETURN instruction. The name of a label or of an internal routine may contain letters, numbers, dots and characters which are valid in symbols, but must not end with a dot. The name is translated to uppercase (except in the case of string constants) but no variable substitution occurs, even after a dot. On entry to an internal function, the special variable SIGL will be set to the line number of the instruction which caused the transfer of control. This applies equally to function calls, subroutine calls with the CALL instruction, and instructions which cause a condition handler to be called (see "CALL ON"). An internal routine may or may not hide (some or all of) its variables using the PROCEDURE instruction, described below. By default, all variables remain visible during an internal routine. An external routine is any routine which is stored in a separate file on the system. It may be in Rexx or in any other language, and it may be stored singly or in a library. Libraries are searched first, in the directories named by environment variable REXXLIB, or, if that is not set, in the path chosen at compile time (see the technical reference for details on how to write a function library). If a routine is not found in a library, it is searched for in the directories named by environment variable REXXFUNC or (if that is not set) REXXPATH or (if neither of those is set) PATH. The name of the routine as given by the calling program will be translated to lower case, even if it is a string constant (though this may change in a future release). The full path name of the routine, excluding its file extension, may be given by the calling program, but in this case the name will need to be enclosed in quotes because otherwise the slash (/) would be interpreted as a division operator. An external routine or library may be written in one of four ways, which are searched for in order: - A function registered by RXFUNCADD or by using the API; - A dynamically loaded object file whose name ends with ".rxfn"; - A Rexx program whose name ends with either * the default extension, or * the interpreter-supplied extension (usually ".rexx"), or - Any Unix program whose name matches that given by the caller without a file extension. The technical reference gives details on how to write external functions which can be registered or dynamically loaded, or which are Unix programs. Note, however, that certain Unix system programs may be also called using this interface, for example: uname('-s')='SunOS' (perhaps). An external routine which is a Rexx program will be executed as if it were a completely separate process. All parameters such as NUMERIC DIGITS and ADDRESS will be set to default values, all condition traps (see "CALL ON" and "SIGNAL ON") will be reset, and none of the variables of the caller will be accessible (but see OPTIONS 'EXPOSE' below). All these things will be preserved during the external routine and restored when the routine finishes. However, OPTIONS settings may or may not be reset to their defaults and preserved. There is thus no way for one REXX program to affect the variables of another, except via parameters and results. (Note that data can be passed back and forth via the stack, however). An external routine which is a Rexx program may use the "PARSE ARG" instruction to examine its arguments, and may return a result to the caller by specifying it as a parameter to the RETURN or EXIT instructions. When the program terminates using RETURN or EXIT or when the interpreter reaches the end of the program, the caller will resume execution as normal. NOTE: Once a ".rxfn" routine or library has been found, all the routines defined within it become in effect built-in functions. When the interpreter is searching for such a routine, the name is not translated to lower case, and any leading path name is ignored. However, the name of the routine (i.e. that part which comes after the last slash) will usually be required to be in upper case - so "/my/directory/ROUTINE" is the preferred way to name a routine in /my/directory. NOTE: The above notes about case translation will change in the future. NOTE: When a single routine other than a ".rxfn" file is found, its file name is stored by the interpreter. This result will be used for any future references to routines with the same spelling (including case). This makes the call faster, but it means that files used as routines should not be renamed while the interpreter is active. A similar note applies to libraries: the interpreter reads all library definitions at the first external routine call, and therefore libraries should not be changed or renamed while the interpreter is active. Examples (assuming that the default extension is ".rexx"): foo(3,,6) calls an internal or built-in function named FOO, or an external function named foo.rxfn, foo.rexx or just foo, with arguments "3", nothing, "6". 'DATE'() always calls the built-in function DATE with no arguments. call "/bin/ABC" 6 calls an external subroutine named /bin/abc.rxfn, /bin/abc.rexx or /bin/abc with argument "6". This program uses an internal function to calculate a factorial. parse arg x /* this is an example factorial program. */ say x"!="fact(x) exit fact: parse arg p /* the argument to fact is assigned to p */ if p<3 then return p return p*fact(p-1)