Functions in REXX
Learn how to define and call functions and subroutines in REXX, including arguments, return values, variable scope with PROCEDURE, recursion, and built-in functions
Functions let you package a piece of logic under a name, give it inputs, and reuse it anywhere in your program. As an imperative, procedural language, REXX organizes reusable code into routines—blocks of code marked by a label. A single routine can be used two ways: as a function that returns a value into an expression, or as a subroutine invoked with the CALL instruction. There is no separate syntax for declaring the two; the difference is only in how you call them.
REXX routines reflect the language’s human-oriented design. There are no type declarations on parameters, no return-type annotations, and no forward declarations—a routine is simply a label followed by instructions and a RETURN. Arguments arrive as strings (because in REXX everything is a string) and you pull them apart with PARSE ARG or read them with the ARG() built-in function.
In this tutorial you’ll learn how to define and call your own routines, pass multiple arguments, return values, control variable scope with the PROCEDURE keyword, write recursive functions, and tap into REXX’s large library of built-in functions.
Defining and Calling Functions
A REXX function is a label (a name followed by a colon) that ends with a RETURN instruction carrying a value. You call it like a function in most languages—name(arguments)—and the returned value is substituted right into the surrounding expression. Note the EXIT instruction: it stops the main program before execution falls into the routine definitions below it.
Create a file named functions.rexx:
| |
PARSE ARG name assigns the first argument to name. With multiple arguments, PARSE ARG width, height splits them on the commas used at the call site. The RETURN instruction hands a value back to the caller, where it replaces the function call in the expression.
Subroutines and the CALL Instruction
The same routine can be invoked as a subroutine with the CALL instruction. After a CALL, the returned value (if any) is placed in the special variable RESULT. This style is handy when a routine performs an action and you want to check its result separately, or when it takes a variable number of arguments that you read with the ARG() built-in.
Create a file named subroutines.rexx:
| |
The // operator is REXX’s remainder operator, so n // 2 is 0 for even numbers. Because sum_all loops from 1 to arg(), it works no matter how many values you pass—a flexible alternative to fixed parameter lists.
Variable Scope with PROCEDURE
By default, a REXX routine shares all variables with the rest of the program—there is no automatic local scope. Adding the PROCEDURE keyword after the label changes that: the routine gets its own private set of variables, protecting the caller’s data. When a routine still needs to see specific caller variables, PROCEDURE EXPOSE names exactly which ones to share.
Create a file named scope.rexx:
| |
The counter assigned inside try_to_change is local, so the caller’s counter stays 100. show_config can read config because it was exposed. And add_to_total, which omits PROCEDURE entirely, freely modifies the caller’s total. Using PROCEDURE is the recommended practice—it prevents subtle bugs from accidentally clobbered variables.
Recursion
Because each PROCEDURE invocation has its own local variables, REXX functions can safely call themselves. Recursion is a natural fit for problems defined in terms of smaller versions of themselves, like the factorial and Fibonacci sequences.
Create a file named recursion.rexx:
| |
Each recursive call to factorial multiplies n by the factorial of n - 1 until it hits the base case of 1. The fib function adds the two previous values. strip trims the leading space left by the concatenation so the output is clean.
Built-in Functions
REXX comes with a generous library of built-in functions, especially for string handling—the language’s specialty. You call them with the same name(args) syntax as your own functions, and you can freely mix built-ins with custom routines.
Create a file named builtins.rexx:
| |
translate with a single argument uppercases a string, word and words work on whitespace-separated words, and format rounds a number to a given number of decimal places. The initials routine shows how built-ins like words, word, and left combine to build new behavior.
Running with Docker
The examples run unchanged under Regina REXX in Docker. Pull the image once, then run each file.
| |
Expected Output
Running functions.rexx:
Hello, World!
Hello, REXX programmer!
Area of 4 x 5 rectangle: 20
Double the area: 40
Running subroutines.rexx:
7 is odd
42 is even
Sum is 60
Running scope.rexx:
Before call, counter = 100
Inside routine, local counter = 999
After call, counter = 100
Config from caller: production
Shared total = 15
Running recursion.rexx:
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
---
0 1 1 2 3 5 8 13 21 34
Running builtins.rexx:
Length: 16
Upper: REXX PROGRAMMING
Word 2: Programming
Word count: 2
Substring: REXX
Reversed: gnimmargorP XXER
Max: 42
Min: 3
Absolute: 15
Rounded: 3.14
Initials: ACL
Key Concepts
- Routines are labels — A function or subroutine is a label (
name:) followed by instructions and aRETURN. There is no separate declaration syntax for the two; the call style decides how it’s used. - Two calling styles — Use
name(args)to call a routine as a function and use its return value inline; useCALL name argsto invoke it as a subroutine, then read its return value from the special variableRESULT. - Arguments are strings — Read arguments with
PARSE ARG(splitting on commas for multiple parameters) or with theARG()andARG(i)built-ins when the count varies. REXX puts no type constraints on parameters. - PROCEDURE controls scope — Without
PROCEDURE, a routine shares every variable with its caller. AddPROCEDUREto get private local variables, andPROCEDURE EXPOSE nameto selectively share specific ones. - Recursion needs PROCEDURE — Local scope from
PROCEDUREis what makes recursive functions like factorial and Fibonacci work correctly, since each call keeps its own copy of variables. - EXIT separates code from routines — Place
EXITbefore your routine definitions so the main program doesn’t accidentally fall through into them. - Rich built-in library — REXX provides many built-in functions, with particularly strong string handling (
length,substr,word,reverse,translate,left) that you call with the same syntax as your own routines.
Running Today
All examples can be run using Docker:
docker pull rzuckerm/rexx:3.6-5.00-1
Comments
Loading comments...
Leave a Comment