So, I was trying to figure out how to manage global vs. local state, and made the dumbest program possible:
/** array.rexx */ a. = 0 a.0 = 10 DO i = 1 TO a.0; a.i = i; END SAY array_string("a.") -- prints 1 to 10 SAY alen -- prints "ALEN" because it doesn't exist in global scope EXIT 0 /* Returns string representation of an array, stem. passed as first arg. */ array_string: PARSE ARG _arrayvar . RETURN _array_string() _array_string: PROCEDURE EXPOSE (_arrayvar) alen = VALUE(_arrayvar || 0) str = "" DO i = 1 TO alen IF i > 1 THEN str = str || ", " str = str || VALUE(_arrayvar || i) END RETURN str
So… I’ve made a global variable “a.” full of numbers. PROCEDURE makes a local variable context until you hit RETURN; you should never work at global scope if you can avoid it. So to pass a. in, I have to bounce through a global function array_string(), set a global var _arrayvar to whatever arg was given, which calls a local function _array_string and the paren in
EXPOSE (_arrayvar) expands that into “a.”, and then use VALUE() to dynamically read the variable.
Well, it works. I remember now how crazy complex REXX programs got, with giant global databases being exposed in every function. I bet this is the origin of my “World object” pattern in so many later languages.
This and another dumb example or two ate a couple hours of my brain, but it kinda makes sense again, you know? Interesting for a language I haven’t written in anger in 20 years. I went fully back to SHOUTING KEYWORDS, it just makes sense.
The Python version of this is:
#!/usr/bin/env python3 def array_string(arrayvar): return ", ".join(map(str, arrayvar)) a =  for i in range(1, 11): a.append(i) print(array_string(a))
Which I’d argue is just as stupid, because Python thinks ranges end 1 before the last number, doesn’t know how to join numbers with strings, on a large array that map will consume all memory, and is a single-pass interpreter so I have to put the function above the script code; but it is much, much shorter.