Random REXX mention on Fediverse reminded me of good times with it. REXX was originally a scripting language for the IBM /360 series, later OS/2 where I encountered it. There's three main branches: REXX (original, simple procedural language), ooRexx (strict superset adding OOP tools to REXX), and NetRexx (almost-REXX implemented in Java, so it can interact with the entire Java API).
The things it does well are: Simple notation, like BASIC, but it's structured and dynamic: Variables have their NAME as default value, and it's trivial to evaluate strings as code. Variables can also be "stems", either indexed or associative arrays depending on key. a.=0; a.0=10
and you have an 10-element array of 0's (using .0
as length is common). Any command it doesn't recognize is passed to the outside environment, which might be a command-line shell, another program you're scripting, whatever, no special syntax needed. REXX is preposterously fast for a scripting language, and has perfect decimal math (Cowlishaw's main academic area of interest), though it's still not compiled language fast.
OS/2 made great use of it. The E and E/PM editors written in REXX are all about scripting; like Emacs but far more so, there's almost no program except the E script.
Back in the '90s, I wrote a ton of programs for clients (all dreadfully dull line-of-business stuff) which were thousands of lines of REXX with VT100 UI or a little teeny GUI shell in C it controlled and got messages from; my turnaround on a business change could be hours instead of days or weeks for a C-only program. There's somewhere on FTP sites or in my old code archive my QUEST game, which was just a random D&D wilderness crawl hack-and-slash, written the same way, and a huge script for writing a nice config file to generate the impossibly fussy bit-twiddling world files for DikuMUD and CircleMUD.
Down side, by the late '90s OS/2 was shut down, Mike Cowlishaw started doing everything in NetRexx, so the core language languished, and there weren't good ports to Linux or Mac (either System 9 or early OS X). The open-source "Regina" interpreter was almost but not quite compatible, and was very frustrating to debug around. I completely gave up on it around 1999, when Python got usable.
Seems in the last decade they've somewhat recovered, REXX Language Association, aka ooRexx.org, and NetRexx all have maintained sites, the old RexxInfo site is as hideous as it was in the '90s, and unmaintained now, but does have a free copy of the REXX Programmer's Reference book which is nicely complete.
The RexxLA symposium is going on as we speak. No livestreams, sadly, but last year's presentation decks are up. You might want to start with Rexx Tutorial for Beginners part 1, part 2, and ooRexx Tutorial.
I'd really like to hear "Rexx from OS/2 to macOS - a travel in time & space"!
% sudo port install oorexx
…
% cat hello.rexx
/** hello.rexx */
name = input("What is your name? ")
say "Hello," reverse(name) || "!"
exit
input: procedure
parse arg prompt
call charout ,prompt
return linein()
% rexx hello.rexx
What is your name? Mark
Hello, kraM!
Works fine. The default I/O commands are a little weird so I rewrote that input function almost from muscle memory. PULL var
and PUSH x
operate on a stack and get uppercased, PARSE PULL var
is very powerful and lets you interpolate strings for parsing input (you can also use it on function args, as seen here), but here all I want is a complete line as a function. SAY is a cutesy form of CALL LINEOUT ,whatever
, (the missing first arg to CHAROUT or LINEOUT is the output file name/handle). Note the two ways to call a function: y=f(x)
or CALL f x
depending on if it has a return value. I write everything lowercase, modern REXX is case-insensitive, but historically it was an uppercase-only language, so I always SHOUT THE KEYWORDS when talking about them.
I didn't get far into ooRexx back in the day; I don't think most of its "enhancements" are needed to a nice simple language, but there's places where stems aren't a sufficient abstract data structure and the like.
This looks like fun to play with again, though I wouldn't expect to ship anything useful in it. The one problem is there's no REPL. You can actually make a simple REPL with just DO FOREVER; PARSE PULL line; INTERPRET line; END
but there's a lot of error-handling and structured stuff that won't work in that. I think I have a real REPL in my code? I'll go looking in a bit.