Variables and Types in REXX
Learn about variables, typeless values, decimal arithmetic, and stem variables in REXX with practical Docker-ready examples
REXX takes a radically different approach to variables and types than most modern languages. There are no type declarations, no reserved keywords for allocating memory, and no “int” vs “string” vs “float” distinctions to memorize. In REXX, every value is a character string, and the language decides how to interpret that string based on the surrounding context.
This design choice, championed by Mike Cowlishaw at IBM in 1979, makes REXX remarkably beginner-friendly while still supporting serious numerical work through arbitrary-precision decimal arithmetic. The same variable can hold a product code one moment, a monetary amount the next, and a customer name after that — no casting, no conversion calls, no compile errors.
REXX is an imperative, procedural, structured language, so the flow of assignment and reassignment will look familiar to anyone coming from Python, Ruby, or Perl. What will surprise you is how the typeless model and the decimal numeric system interact. This tutorial shows how variables come into existence, how REXX decides whether a value is “numeric”, how NUMERIC DIGITS controls precision, how strict (==) and non-strict (=) comparisons differ, and how REXX’s unique stem variables provide associative-array-like storage without ever leaving the typeless model.
Declaring and Using Variables
Variables in REXX spring into existence the moment you assign to them. There is no var, let, dim, or type keyword — just a name, an equals sign, and a value. Every value is stored internally as a character string; REXX converts it to a number only when an arithmetic operator or numeric built-in demands it.
The example below mixes assignments with different apparent types, then interrogates the values using the DATATYPE() built-in, exercises REXX’s arbitrary-precision arithmetic, and contrasts the two flavours of comparison operator.
Create a file named variables.rexx:
| |
A few points worth noting in this example:
x = 100andy = "100"produce identical internal storage. The quotes are a source-code convenience, not a type annotation.DATATYPE(v)with no second argument returnsNUMif the value could be treated as a number andCHARotherwise. A one-letter option (N,W,A, and so on) narrows the check and returns1or0.NUMERIC DIGITSadjusts the global precision used for arithmetic results. REXX performs decimal math, not binary floating-point, so1/3is a genuine repeating-decimal approximation rather than a misleading0.3333333333333333.- The plain
=operator pads shorter strings with blanks and does numeric comparison when both operands look like numbers. The strict==operator demands exact character-for-character equality, including length.
Stem Variables — REXX’s Built-in Associative Arrays
REXX has no array, list, map, or hash keyword. Instead, every variable whose name contains a period behaves as a compound variable, and the part before the first period is the stem. A bare stem followed by a period (e.g. score.) sets the default value for every tail that is not explicitly assigned — including tails you haven’t thought of yet. Integer tails give you array-like behaviour; symbol tails give you dictionaries. The convention for “array length” is to store the count in the .0 tail.
Create a file named stems.rexx:
| |
Notice three things here:
- The
DO i = 1 TO fruit.0loop uses the stored count. Nothing stops you from overrunning a stem — it just returns the default value (or the uppercased tail name, if no default was set). - Assigning to the bare stem
score.does not create a single “array” object; it sets a fallback for every possible tail. This is how REXX programmers emulate sparse arrays and initialised-to-zero counters. - In
capital.usa, the symbolusais uninitialised, so REXX uses the uppercased literalUSAas the internal tail. Reading back viacapital.usaperforms the same lookup, so the round-trip works transparently.
Running with Docker
| |
Expected Output
Running variables.rexx:
=== Basic Variables ===
message: Hello, REXX!
count: 42
pi: 3.14159
flag: 1
=== Typeless Data ===
x + 5 = 105
y + 5 = 105
x || 'abc' = 100abc
=== DATATYPE Checks ===
datatype(42): NUM
datatype(hello): CHAR
datatype(3.14): NUM
datatype(2.5e3): NUM
datatype(42,'W'): 1
datatype(3.14,'W'): 0
=== Decimal Arithmetic ===
1/3 (9 digits): 0.333333333
1/3 (30 digits): 0.333333333333333333333333333333
2**100 (50 digits): 1267650600228229401496703205376
=== Comparison Types ===
(5 = '5.0'): 1
(5 == '5.0'): 0
('abc' = 'abc '): 1
('abc' == 'abc '): 0
Running stems.rexx:
=== Integer-tail Stem ===
fruit.1: apple
fruit.2: banana
fruit.3: cherry
=== Default Tail Value ===
score.1: 95
score.2: 87
score.99 (never assigned): 0
=== Symbol Tails ===
capital.usa: Washington
capital.france: Paris
capital.japan: Tokyo
Key Concepts
- Typeless by design. Every REXX value is a character string; numeric, boolean, and textual interpretations are decided by the surrounding operators and built-ins, never by a type declaration.
- Assignment creates variables. There is no
declare, novar, and no initialiser syntax. The first assignment is the declaration, and subsequent assignments may store values that look like entirely different “types”. - Variable and keyword names are case-insensitive.
Count,COUNT, andcountall refer to the same variable;SAYandsayare the same instruction. DATATYPE()is your type inspector. UseDATATYPE(v)for a quickNUM/CHARanswer, orDATATYPE(v, 'W'),DATATYPE(v, 'N'),DATATYPE(v, 'A'), etc., for specific categorical checks.- Arithmetic is decimal and arbitrary-precision.
NUMERIC DIGITS nsets the number of significant digits used in results — perfect for financial calculations, awkward for nanosecond-sensitive floating-point work. =and==are different operators. Plain=does numeric comparison when both sides look numeric and otherwise pads strings with blanks;==demands exact, byte-for-byte string equality.- Stem variables replace arrays and dictionaries. Any variable name containing a period is a compound variable; a bare stem assignment (
stem. = value) sets a default for every tail, giving you sparse arrays and initialised dictionaries in one construct. - REXX has no true constants. The convention is to assign once and treat the variable as read-only by discipline — or use
NUMERIC DIGITS/OPTIONSfor settings that behave constant-like across a scope.
Running Today
All examples can be run using Docker:
docker pull rzuckerm/rexx:3.6-5.00-1
Comments
Loading comments...
Leave a Comment