Every programmer should learn three kinds of languages MINIMUM: Forth, Lisp, and most any Algol-derived language, including C, and most definitely Oberon in my opinion. Every time you learn a new language, you get new tools in your coding toolbox that can be used to help you solve a problem. This is true even if you never end up using two of the three languages again. But one thing that can rub off on you isn't the specific mechanics of the language, but rather, a specific
philosophy. One of the fundamental questions to ask, especially in the case of Forth, is,
why was Forth developed?
Forth's conceptual model is the way it is because it is what the hardware speaks. You don't write infix operations, or even prefix operations, on CPU architectures. You write them postfix. Sometimes with a lot of boilerplate (e.g., CLC before ADC), but nonetheless, the operands must be available
prior to the addition. Since this is the natural way for most creatures to perform arithmetic (and it is! The "infix" excuse is just that), and is the natural way for computers to do arithmetic, why hide it? Forth decides to make this explicit.
Chuck Moore invented Forth because he was:
1) Sick of learning different application-level languages -- also known as "the user interface" today.
2) Sick of learning different HLLs.
3) Sick of learning different shell languages.
4) Sick of learning different linker languages (e.g., executable file formats).
That's a stack of four different langauges, where a language is defined as some means of communicating with the next lower layer in the stack. For example linkers are used to take binary executable files and link them together on disk or in memory, preparing them for execution. Shells are used to actually get the linker to do its job. HLLs are used to create the binary images for the benefit of the shell, and once the program is written and linked, the user interface is used to talk to the program written in the HLL.
It is rediculous when you think about it. It's just plain not needed.
Forth reduces this language stack to only two layers: Forth to Machine, and User to Forth.
For instance, let's consider the use of a hypothetical e-mail client. In today's world, you would need to learn the mail client's user interface. I challenge most people here to learn "mutt"'s interface, for example. It's daunting! But, for the sake of brevity, I'll constrain my examples to just two commands: composing new mail, and quitting the program.
To compose a new message, you press M on the keyboard, and it'll ask for the relavent parameters, and send off a message. To quit the program, press Q. Note that the main program must sit in what basically boils down to an event loop, blocking on either the user's keystrokes or on the arrival of new mail (so that it can say "New Mail" or something like that). As such, it is
interpreting keystrokes and other events, and therefore, constitutes a kind of language.
In Forth, this kind of e-mail client would be different. For starters, you'd load the e-mail client into memory, and it'll drop right back to the Forth's "OK" prompt. To compose a new message, you might type "M<enter>", where M is defined something like:
Code:
: M From: To: Subj: Body: send-it ;
where From:, To:, Subj:, and Body: are words that either ask the relavent information or grabs them from some kind of environment setting, etc. send-it does the actual busy-work of sending the message.
Actually, this isn't really a Forth-way to do the above. The above example more or less mimicks how Mutt works. More realistically, you might do this:
Code:
From: kc5tja@send.spam.to.microsoft.com
To: 6502forum@send.spam.to.microsoft.com
Subj: Z-80s are blasphemy!
Body Send
Note that From:, To:, and Subj: are commands actually typed by the user! Body would presumably invoke the user's editor of choice, assuming one wasn't written directly in Forth itself. Send is rather self-explanatory, I think.
But, you get the idea -- the email client doesn't implement "yet another" event loop -- it already has a perfectly good one built in. The only thing the software does is hook into that event loop by defining new Forth functions -- err -- words.
A good Forth application would have a help program written too -- in this case, something like
help-mail or whatever. It'd list the mail-related words and a brief synopsis of what they do.
As far as listing messages and reading them and relying to them, well, that's all pretty much handled in a very similar way. To check for new mail for the first time, I'd probably have to do this:
Code:
login
check
where login would securely ask for user-name and password. Of course, if you're already logged in, you wouldn't have to do that again. check then checks for new mail.
A command "list" would be used to list your current messages, and "read" to read one. Note that using this kind of interface seems like a drudgery at first, but really, it's not! All the ham radio BBSes use a very similar interface, actually, thanks in large part to AX.25-protocol BBSes being inherently
line oriented instead of character-oriented. Thus, to save time, plus the fact that you're basically running on a 1200bps LAN connection (yes, that's 1200bps), as much information needs to be provided as possible all at once. In a ham radio BBS, you typically would do this:
Code:
r 15360
In Forth:
Code:
15360 read
Not that big a difference. It's not hard to use either. I now prefer it (mostly) versus using something like Mutt, which used to be my all-time favorite mail reader program.
And the all-time best thing about Forth applications: every single application is scriptable. If your mail program does not provide a "read through" functionality, write one!
Code:
: read-thru ( from to -- )
begin 2dup xor while over read swap 1+ swap repeat 2drop ;
Can't do that with any other mail client, except Emacs. But then, Emacs is written in Lisp, and follows *precisely* the same philosophy, only with the addition of a (thin) user interface layer.
Another great example of this was the GEOS operating system for the Commodore 64. Here is a system that, in less than 64K of memory, provided an amazingly capable GUI for an architecture previously thought to be incapable of supporting such a concept. What does it have in common with Forth? It has a
single event loop inside the OS, and applications merely hook into it, by providing a set of data structures to describe what's on the screen, and a set of call-backs for managing them. Literally everything else is handled by the kernel.
The observant reader will note that I didn't address "quitting" a program yet. This is because there is no concept of "quitting" a program in Forth. Since the mail client is a fundamental feature of the Forth environment when loaded, it follows that to quit the mail client would mean to quit the Forth session.
So how does one use another application? There are two answers. One is to load another application co-resident in memory with the mail client. Another is to release the memory used by the mail software and then load the new application. Forth *favors* the latter, but *enables* the former.
For example, PygmyForth for DOS pretty much supports the former approach, where numerous applications are co-resident in memory. Meanwhile, Chuck's ColorForth (and my own Forths) basically relies on an overlaying technique to ensure the Forth dictionary size (a) doesn't become gargantuan, and (b) the newly loaded application doesn't inadvertently obscure useful commands of any earlier application. Since Forth programs are incredibly small, this is not a burden: the compilation process of going directly from raw source to raw binary occurs
so fast that changing between applications in this manner occurs before my finger lifts off the ENTER key. I find it fascinating that GForth under Linux can load Forth applications faster than Linux itself can load
pre-compiled and pre-linked binaries. Much of this has to do with how infinitesmally smaller Forth applications are compared to traditionally written applications in other languages.
So there you have it in a nutshell -- Forth's overarching philosophy is none other than ease of use, convenience, but more importantly,
user interface consistency (which, by the way, is the holy grail of all "HCI experts" today!). But it's like driving a car, folks -- you can't get anywhere unless you learn the relationship between the gas pedal, the brake, the steering wheel, and the gear selector. Likewise with Forth -- you won't get anywhere unless you learn the reverse polish nature of Forth. But once you do, look out -- it's not a pickup truck you're driving, it's a SVT-10-equipped Dodge Viper, with twin sequential turbochargers bolted on for extra measure. You'll find your programming productivity increases substantially.