I fairly frequently see people who are taking an interest in Forth struggle with the idea of programming without local variables. I struggled with it when I started writing Forth! I feel like there's an unspoken assumption for people coming to Forth from other languages, and if I were to speak it aloud, it would sound something like “temporary data should go on the stack”.
Because... functions should be re-entrant by default! They should clean up after themselves! Global variables are bad and must be avoided at all costs! Functions should be “pure” and take all of their inputs as parameters, avoiding hidden dependencies!
All of these ideas of what “good code” looks like are wrong in Forth.
It is actually extremely common for Forth words to rely on implicit context, which is globally accessible through other Forth words. This is often how you build DSLs!
I wrote this analysis of Return to Monkey Island's ending on October 4th, a couple of weeks after finishing it, in a kind of manic fugue state, writing well past the time I should have been in bed. After I'd written it, I decided it probably needed an editing pass before I posted it, but life immediately got in the way and I never looked at it again. Today I picked it up and read through it and decided not a word needed to be changed. So, without further ado, here it is.
On Feb 9, I made the following comment on my Mastodon:
still can't believe the shithead behind Pupkin managed to get his webcomic turned into a movie with Jennifer Lopez
Nobody responded to this in any way, because, quite frankly, nobody who wasn't an absolute fanatical follower of webcomics discourse 20 years ago has any idea what the fuck this means. Hell, I barely understand my feelings about this. But to do them justice, we are going to have to unpack 25 years of webcomics history.
The process of researching and writing this has rearranged my view of the formative years of webcomics. I've done my best to cite my sources, but primary sources are not always readily available anymore. I ended up using the Wayback Machine so much that it locked me out for a few hours. Support the Internet Archive.
So I should probably have a blog post that I can point to about this whole retrocomputing project that I've been up to the past year and a half.
I wrote a game on an MS-DOS 286 PC, using only tools I built myself or tools that were available during the era where they were still selling 286 PCs. It's called Neut Tower and you can play it on your MS-DOS PC, in DOSBox, or in your browser. As part of this project, I implemented a Forth system, and built most of my game and its tools using it.
My motivation at the start of the project was this: I was enjoying using my 286. I liked the single-tasking workflow; there were no distractions. I was downloading games and apps and it was fun! So I figured I'd take the next step and write a little game or something.
I've been seriously writing Forth, with my homebrew Forth dialect, for about a year now, off and on, and I've noticed something interesting with how things end up structured.
Forth and Lisp are often spoken of as though they are similar in some deep way. In Lisp circles, you often hear “code is data.” This is generally held to mean “Lisp has macros”, more or less – a Lisp program's source code is a syntax tree made of Lisp lists, that your Lisp program can introspect into and transform into new syntax trees and execute. Your program is literally a data structure.
My Forth code has very few things I would refer to as “data structures”. There is no significant language for defining them – I write one-off words that do pointer arithmetic. I only have a handful, so I haven't felt the need to generalize. It does zero transformation of them – they have been carefully chosen to be directly useful for everything the program needs them for, in-place, as-is.
Instead, the common pattern is that everything is code, which, thanks to Forth's flexible non-syntax, can be made to look a lot like data. Often data is compiled directly into the code that uses it – instead of naming a constant that's passed into a function to do a particular thing, you name a function that takes no arguments that just does the thing. (There are lots of flexible ways to make this sort of thing easy and inexpensive in Forth.) Forth is hyper-imperative to a degree that, as modern programmers, we've largely forgotten is even possible. Even, say, the number 4 is arguably a word executed for its side effects (push the value 4 onto the current stack). Of course, this is how CPUs work, too – you don't have a concept of “4” on its own in assembly, you have the concept of moving “4” into a register, or into memory. The only thing you can tell a CPU is to do things. Forth is the same.
Forth is perhaps the tiniest possible useful interactive programming language. It is tiny along a number of dimensions:
The amount of code required to implement it
The size of the code that is generated
The amount of memory used
The number of features it considers necessary for useful work
It is a language that makes complexity painful, but which reveals that a surprising amount can be accomplished without introducing any. Forth is the opposite of “bloat”. If you've ever been like “Oh my God this Electron-based chat app is taking up 10% of my CPU at idle, what the HELL is it DOING, modern computing has gone MAD”, Forth is there to tell you that computing went mad decades ago, and that programs could be doing SO MUCH MORE with SO MUCH LESS.
WHAT DO YOU MEAN, “FORTH”
There is an expression about Forth: “If you've seen one Forth, you've seen one Forth.” Forth isn't a strictly-defined language, though there is a standardized dialect; it's more a set of ideas that tend to work well together.
In the past month, I wrote a tiny Forth system on a 286 running MS-DOS using Turbo C++ 1.01. It is my first time using Forth in anger, though I read a lot about it 15 years ago. When I refer to my Forth, I am referring to a system literally thrown together in two weeks, written by someone who does not really know Forth that well. It is slow and wildly nonstandard and it doesn't do very much, but I have enjoyed the process of writing it very much. If you are a grizzled old Forth grognard, please let me know if I have misrepresented anything.