What kind of programs would one naturally reach for Forth as the optimal solution? It has always struck me as a very low level language but I rarely hear this caveat from its advocates.
I highly doubt it's useful these days on general purpose computers, where even the very smallest ones can easily implement C (or better) or even run a whole operating system like Zephyr or Yocto.
However if you're creating your own computer from scratch or have other artificial constraints (like it needs to fit into a boot sector[1]), and if you want to really understand precisely how your language works down to the lowest level detail while still having high-ish level constructs, then Forth is the ideal small language for that.
It made more sense in the 8 bit home computer era, where you could do a more high level coding with more performance than a BASIC interpreter, without having to mess with hexdumps for DATA segments, or Assembly opcodes.
1. Assembly coding within a REPL. Forth supports "load-and-store" without the additional bookkeeping steps of assembly. Once the program works, it can be incrementally rewritten into the assembly if needed, or used to bootstrap something else. Historically this is probably the single biggest usage, because the language works as a blunt instrument for that within the standard wordsets. Lots of programs on the early micros shipped with code that was developed with Forth, but with the Forth interpreter discarded at the last step; and where there is novel hardware and novel applications, Forth tends to come up as the bootstrap.
2. Minimal-dependencies coding. For the same reason that it's a good bootstrapping tool, Forth ends up being portable by assuming nothing. While different Forth systems are all subtly incompatible, the runtime model is small enough to wrangle into doing what you want. Stack machine VMs basically are "Forth with more sandbox and less human-readability".
3. "Big ideas" coding. The "human-readable stack machine" aspect means it's a useful substrate for language design - being programmable, you can shift the imperative interpreter model in the direction of new syntax and new general-purpose data structures, while still retaining a way to drop all the way down to assembly - the biggest downside is that this doesn't let you easily introduce existing library code, so bootstrapping from within Forth would take a long time and you would most likely get stuck on trivial string processing. But Forth as the second of a two-step process where you "compile to Forth" using something more batteries-included is actually pretty reasonable as an alternative to generating a binary or designing an original VM.
I have yet to use Forth for anything serious, but it's worth pointing at an example for how expressive you can be dealing with hardware. From https://www.forth.com/embedded/#Embedded_Programming_Example the top level control for a washing machine could be:
: WASHER ( -- ) WASH SPIN RINSE SPIN ;
I won't repeat all the rest, even though it's short, but let's look at a few other definitions that build up to that:
: RINSE ( -- ) FILL-TUB AGITATE DRAIN ;
: DRAIN ( -- ) PUMP ON 3 MINUTES ;
: ON ( mask -- ) PORT C@ OR PORT C! ;
4 CONSTANT PUMP
01 CONSTANT PORT
All very high level and fairly straightforward to understand word-by-word until you get to the bottom, that being the last 3 lines I pasted. (Though in a file this would be written the other way around with WASHER being the final line.) The PORT is a memory mapped hardware address, PORTB on a 68HC12 chip, and various other constants like PUMP are defined as bitmasks to get at individual bits on the port. The ON word takes the current value at the PORT address, ORs it with the stack-passed mask, and sets it back.
In C this might look like (again in reverse order):
That is, if you program the C in a similar procedural style that closely follows the physical function of the device. It's maybe more common to express similar C code in a state machine style, in which case it'd look a lot different.
Is the Forth version actually worth it? To me the C is "good enough", and more explicit or at least clearer as I'm familiar with C. Where Forth could win me over is in its ease of having a truly interactive environment to iteratively develop the software via a REPL, much like Lisp. (But then I'd rather just use Lisp.) My embedded systems hobby work for the last 10+ years has all been really simple, though, so interactivity isn't a big enough advantage to just using C. (When working with hardware, it's somewhat exciting to stick a pin in a breadboard and move it between power and ground to toggle a motor. It'd be even more exciting to do this interactively via REPL commands poking at memory.)
A lot of the power of Forth comes from its metaprogramming capabilities and having the compiler available at runtime, all wrapped in a tiny footprint. Similarly to Lisp, it empowers one to explore a problem domain without getting in the way. These concepts are alien to C which is downright hostile to exploratory programming.
If you really want to understand the genius of Forth and its creator, I suggest reading everything that Chuck Moore put down in writing starting with "Programming a problem-oriented language".
A lot of us today, being bogged down in the sort of tedium-inducing programming that pays the bills, tend to forget that programming languages are (or should be!) primarily about expressing ideas. Forth is still one of the best languages to do that in.
Yeah. Pretty much agree with everything here. I'd rather encourage starting with the book Thinking Forth, though. It's not written by Moore but has some commentary from him included in it.
I'd even suggest learning a little Forth to people even if it didn't have its interactive nature (which again I don't actually find useful in my own limited embedded work, there's really no "explore" phase as the problems are all straightforward -- contrary to software I write in CL or even Java). I had a friend in college who for a project made his own language and got it working on an embedded system (I think via compiling to C, but I don't recall exactly), but it was just a boring Algol-like somewhat inspired by Ruby. That pattern has shown up again and again around the world though. Forth is one of the handful of languages that shows what expressive options there are that aren't just transparently Algol-like.
It's used in a number of EFI implementations. Its good when you have no environment at all, hence bootloaders. Factor is a more general purpose forth-like language.
However if you're creating your own computer from scratch or have other artificial constraints (like it needs to fit into a boot sector[1]), and if you want to really understand precisely how your language works down to the lowest level detail while still having high-ish level constructs, then Forth is the ideal small language for that.
[1] https://github.com/cesarblum/sectorforth