See the section Functions for a general discussion of Functions.

You can write your own Functions in REXX, placing them in your script (or putting them in a separate script that you call from your script). To identify a Function in your script, you need to put a label at the start of it. The following script contains an internal Function named square, and calls it with some data (ie, passes it 1 argument). This Function simply squares that argument and returns the result as its value.

/* Call the Function square() with an arg,
   and print the Function's returned value */
SAY "The results are:" square(3) square(5) square(9)
EXIT

square:/* here's a function to square its argument */
   PARSE ARG myarg
   RETURN myarg*myarg

The output of this script is: "The results are: 9 25 81".

Remember that a Function is called by typing its name, immediately followed by a (, then any passed args, and finally a closing ). A Function should also return a value.

When REXX encounters the Function call square(3), it searches the script for a label called "square". It finds that label on line 5 in the above example. REXX then executes the instructions starting at that line, until it encounters a RETURN instruction, whereupon it resumes executing the instruction that originally called the Function, replacing that Function call with the returned value (ie, square(3) gets replaced by its returned value of 9, and that's what the SAY instruction displays).

Note: The EXIT instruction in the above script causes REXX to finish executing at that line instead of running down into the Function. It's important to make sure that you don't let REXX accidentally drop down into Functions at the bottom of your script. It's best to put all your Functions at the bottom of the script, and place one EXIT above them all. Note that a Function can never accidentally drop down into another Function below it as long as it ends with RETURN, since RETURN jumps back to the instruction that originally called the Function.

While that Function is being executed, the arguments to the Function can be determined with PARSE ARG in the same way as the arguments to a script. In the above example, we parse the argument passed to square() into a variable named myarg. So, for the call square(3), myarg is assigned the value 3. Alternately, you can use the ARG built-in function to determine how many args are passed, and to fetch each arg.

When the RETURN instruction is reached, the expression specified after RETURN is evaluated and used as the return value of the Function. The expression can be a variable's value, mathematical expression, or even the return from another Function.

You can have more than one RETURN instruction in a Function, each returning a different value. But, REXX always jumps out of a Function immediately when it encounters a RETURN, and returns to the instruction that called the Function. Here we have two ways out of the Function answer(), plus two different possible return values:

answer:/* here's a Function that returns 1 if the user answers "YES", or 0 if he answers anything else */
   SAY "Do you want to learn REXX programming?"
   PARSE PULL ans
   IF ans == "YES" THEN RETURN 1
   RETURN 0

A Function can take multiple arguments, which are each separated with a comma, as so:

/* Call a Function with 3 arguments */
SAY "The results are:" query(5,"Yes","No") query(10,"X","Y")
EXIT

query:/* If the first argument is less than 10, return the second, else return the third. */
   PARSE ARG c,x,y .
   IF c<10 THEN RETURN x
   ELSE RETURN y

A Subroutine is similar to a Function, except that it need not return a value. (ie, It need not supply a value after the RETURN keyword). It is called with the CALL instruction. You do not place a ( and ) after the Subroutine name. Any args passed to the Subroutine are listed after the Subroutine name, and may be separated by commas. In order to access the args, you have to use the ARG() built-in function, or PARSE ARG.

/* Call a Subroutine named box to print a string in a box */
CALL box "This is a sentence in a box"
CALL box "Is this a question in a box?"
EXIT

box: /* Print the argument in a box */
   PARSE ARG text
   SAY "+--------------------------------+"
   SAY "|"CENTER(text,32)"|"  /* center the text in the box */
   SAY "+--------------------------------+"
   RETURN

Here's another example where we use commas to separate the args.

/* Call a Subroutine named print to print args passed to it */
CALL print "This is arg 1", arg 2, TIME()
EXIT

print: /* Print the args */
   count = ARG()
   DO i = 1 to count
      SAY ARG(i)
   END
   RETURN

Note that "arg 2" is printed out as "ARG 2" because it is not enclosed in quotes.

If you do choose to return a value from a subroutine (ie, put some expression after the RETURN keyword), REXX stores this value in the special variable named RESULT. You can't consider a Subroutine itself to directly return a value like a Function does. For example, consider the following call to Subroutine box, and assume that box's RETURN instruction returns a value string of "done":

SAY box "an argument"

This will not print "done". Rather, it will simply print "BOX an argument". First of all, REXX doesn't recognize box as a subroutine name because the CALL keyword has been omitted, so box is never even called. REXX thinks that box is a variable name, and since it hasn't been assigned a value, it defaults to its name uppercased. Even if you put the CALL keyword before box, that wouldn't result in box being called. REXX would misinterpret CALL as the name of another variable, as the CALL keyword can't be part of a SAY instruction, and "CALL BOX an argument" would be printed.

It is possible to call a Function, even a built-in Function, as if it were a Subroutine (ie, no parentheses around args, and it doesn't directly return a value). You need to use the CALL instruction to actually call the Function. The value returned by the Function is placed into the special variable named RESULT, just like with a Subroutine. (Optionally, with Reginald, you can still use parentheses with the CALL keyword, but the return value of the function is not stored in the RESULT variable -- it is discarded).

/* Print the time, using the CALL instruction */
CALL TIME "CIVIL"
SAY RESULT