Lisp has a lot in common with Forth in that people often reduce it to a trick and miss the lesson it has to teach; people implement their six words from the bare metal and use those six words to implement Forth but never seem to make the leap, realize they can take it one step further and implement the language they need for the task at hand just as easily as they implemented Forth with those six or however many words they decided to start with. Sure it may not be the most efficient solution but in a time when most people walk around with half a dozen cores in their pocket, counting clock cycles is generally not a concern and it can probably be more efficient than the batteries included solution that comes with eight D cells when it only requires a single coin cell. But there is something about the weight of those eight D cells, they are substantial and we can feel it.
Lisp appeals to a hierarchical approach, in essence. It constrains some of the principal stuff that "keeps the machine in mind" by automating it away, so that all that's left is your abstraction and how it's coupled to the rest of the stack. It's great for academic purpose since it can add a lot of features that isolate well. Everyone likes grabbing hierarchy as a way to scale their code to their problems, even though its proliferation is tied to current software crises. Hierarchical scaling provides an immediate benefit(automation everywhere) and a consequent downside(automation everywhere, defined and enforced by the voting preferences of the market).
Forth, on the other hand, is a heavily complected thing that doesn't convert into a bag of discrete "runtime features" - in the elementary bootstrapped Forth, every word collaborates with the others to build the system. The features it does have are implementation details elevated into something the user may exploit, so they aren't engineered to be "first class", polished, easy to debug. It remains concerned about the machine, and its ability to support hierarchy is less smoothly paved since you can modify the runtime at such a deep level. That makes it look flawed or irrelevant(from a Lisp-ish perspective).
But that doesn't mean it can't scale, exactly. It means that the typical enabled abstraction is to build additional machines that handle larger chunks of your problem, but the overall program structure remains flat and "aware" of each machine you're building, where its memory is located, the runtime performance envelope, and so on. It doesn't provide the bulldozers that let you relocate everything in memory, build a deep callstack, call into third-party modules, and so on. You can build those, but you have to decide that that's actually necessary instead of grabbing it in anger because the runtime already does it. This makes it a good language for "purposeful machines", where everything is really tightly specified. It has appealing aspects for real-time code, artistic integrity, verification and long-term operation. Those are things that the market largely doesn't care about, but there is a hint of the complected nature of Forth in every system that aims for those things.
The Youtube auto-dub stuff is pretty bad and the subtitles are quite good but hard to follow with all the vim motions on top of it!
Your writing is in English and your code comments too... English was not my native language but I'm fluent now. So unless you are targeting specifically the Italian viewers, you would reach many more people in English. Your content is worth being international I feel.
Sure, gForth still doesn't have a decent way to make HTTP requests or match a regular expression, but writing libraries like that doesn't seem to be fun for the average FORTH developer, who would rather reimplement a very barebones language environment to address the gap left by the other 1200 FORTHs.
It's not that these projects aren't cool, but if you actually want the language to become popular why not look at things every other popular language has?
In most languages, building a compiler or interpreter is a major project. With FORTH, if you’re the only user, you can have something working in minutes.
I’ve lost count of how many times I’ve thrown together a simple stack-based interpreter. Whenever I need to encode non-trivial behavior in an app, I know I can spin up a quick FORTH and get it done.
> So, the question is, how to encourage today's world of C programmers to take a look at Forth. How do we convince them that Forth can be 10 times more productive?
So they are clearly interested in getting people to view FORTH as a productive choice.
Because that is completely missing the point of what Forth is.
It's meant to be a simple high-level language that stays quite close to the underlying machine and can be implemented in a few dozen lines of assembler to solve a specific problem you have.
It doesn't need to be some massive bloated ball of mud and straw like ultra-high level languages such as C, where every aspect of the underlying machine is abstracted away in library after library.
The number of C programmers whose use case is "I need to bring up this CPU with a never-before-seen instruction set" is a rounding error. The number who need to fit their complex logic into 1K of memory is small and dwindling every year. I can buy an ESP32 for less than a dollar.
Moreover, there's no technical reason why FORTH programmers can't write, share, and use libraries (except maybe the aforesaid plethora of incompatible language implementations). FORTH is great for creating neat little DSLs that solve a specific problem. Stacking these can be powerful, but if you personally don't want to use them, or it doesn't fit your use case, that's fine.
They absolutely would not be more productive in Forth. If they're writing in an ultra-high-level language like C, they're unlikely to be targetting something where Forth would make sense.
You need ridiculously powerful processors to run a C compiler, and your code is likely targeting some massive processor with possibly hundreds of kilobytes of code space.
Forth and C inhabit entirely different conceptual spaces.
> Moreover, there's no technical reason why FORTH programmers can't write, share, and use libraries
None of the libraries you write will be of any use to me, and vice-versa.
LOL, thanks for the reminder that most of my career has been spent up in the stratosphere, towers upon towers of abstractions. Started re-learning C during pandemia for embedded systems and microcontrollers, feeling freer as I go deeper down the stack. Got into Lisp interpreter, then compiler and assembler. Had a chance to study eForth in this post, and it can get real close to the metal.
> need ridiculously powerful processors to run a C compiler
That's one thing I noticed while getting familiar with C, that it's a huge effort to write a compiler in itself. Whereas Lisp and Forth even more, creating a variant/subset of the language from scratch is an exercise for every student. These languages are hidden gems, even though they play such important roles in the history of computer science. They are relevant, perhaps now more than ever when people are losing touch with the ground, the basics of code and computation.
It's not 1982 anymore. I can compile C just fine on SoC that costs $5. Of course it's true that these things are ridiculously powerful, but that doesn't really matter. The amount of silicon used is roughly the same as an 8051 from 20 years ago.
I'm all about cool projects like building your own CPU out of 7400 logic gates or writing your own OS in assembler or whatever. But I personally feel that FORTH doesn't need to be limited to these kinds of toy projects where you're intentionally making things harder on yourself. However when I see discussions related to FORTH it seems like most projects fit into this category and there is little diversity.
It could also be that they wouldn’t be more productive (given the kinds of software the typical C programmer writes).
It could also be that that is the wrong question.
When you look at the Forth code of a beginner, yes it's full of stack juggling, of "@" and of "!". When you look at code from more experienced Forth programmers, there's much less of it.
The challenge is to build your way out. There's no fixed way to do this, because the best path to do so is generally dependent on the task at hand.
Needless to say, most programmers fail this challenge.
Sounds like a fun game maybe.
But its definitely not for everyone. I'd say that the status quo of Forth being an obscur niche is fine, just fine. If you need convincing, if you aren't spontaneously curious about Forth, then it's likely not for you.
But if even the proponents of the language say that ("needless to say"!) most programmers will be incapable of the challenge of writing good code in it... definitely doesn't sound like anything I'd want in anything I wanted to be maintainable or long-lasting. If this is the outcome you desire, then your, uh, anti-evangelism is working!
If I piqued your interest, might I interest you in the introductory series I wrote: https://tumbleforth.hardcoded.net/
How is that not what you are doing? Lay it all out and back up what you are claiming, some of us are willing to hear you out.
Chuck Moore is a genius. How many other people created a language, wrote their own semiconductor simulator and ECAD system, and used it to design their own CPU? But, Forth has a strong culture of NIH, and it started with him. Maybe you need a degree of arrogance and self-belief to do the things he's done. Sadly, most people are not such geniuses as to be able to get away with it.
What I tried, perhaps badly,to say; is that it's worth learning everything from Forth culture except for contempt for everything that's not Forth. There are a lot of things wrong with common-denominator programming languages, and common-denominator practices; and it can be exciting for a young programmer to join a community which openly expresses the problems and has an alternative view. (This was especially the case 15-20 years ago when C++ hegemony was at its height). But it can easily become parochial.
The lesson of Forth for me, is that you can really gain a lot of productivity by ruthlessly removing generalisations and focusing on the exact problem you want to solve; and not being afraid to re-implement stuff in order to do so - if you can do it in a simpler way. I don't think adopting concatenative syntax is necessary to do this; there are too many examples where it was achieved without.
Chuck Moore has argued that all programming should adopt this radical simplification approach; this seems to be the case put by the OP (although not explicitly). I don't think it works. Too many tasks require a degree of collaboration which is enabled by the abstractions. Rewriting everything simpler works for a lone programmer, but it means you have to understand everything, and sometimes you just have to interoperate with some system whose complexity can't be refactored away. Take Unicode- Chuck Moore's answer would be "throw away unicode" but most of us don't have that choice.
I have never seen that, most in the Forth world seem resigned to obscurity and content living in their own world. If you could point me to the people advocating Forth above all else, I would love to see it and I don't mean that in a "you're wrong, I'm right" way, I just want to see what their methods are.
That’s something you could prevent with an advanced compiler that inlines lots of code and carefully tries to put functions often called together in cache lines, but this code doesn’t do that, and if you did, why spend that effort on your compiler if a simple traditional language makes that inlining easier?
The trick is that you can regain 100% the speed of C (or machine code) by native-coding the critical parts. It's pretty much the same cheating method as JIT or calling native code with an FFI, just manual.
In this regard, a simple, naive subroutine threaded scheme makes it very trivial to do. Think Lua extensions but even more easy because you don't have dynamic types or GC memory. Seriously, when I look hear that language X is "easy to extend" and I look at it... No, it is not.
I have come to the same conclusions as eForth "independently" (I have looked at many Forth systems before making my own, so there could be some influences), except I wasn't interested in compatibility with the standard, so I ditched the counted strings for C's ASCIIZ strings. This makes interfacing with C/C++ libraries as straightforward as you can get.
I quite don't understand why eForth goes for C++; I do see its value to parse more complex languages but Forth? I also don't see the value of multithreading. Cooperative schemes usually work well enough and are easier to handle. If concurrency is needed, multiple programs with RPC, shared memory or pipelines are options usually available (some options are more portable than others, though).
> So, the question is, how to encourage today's world of C programmers to take a look at Forth.
This is a huge mistake. If you make a Forth for others instead of doing it for your own needs, you are doing it wrong. Doing it for yourself, and not being tied by backwards compatibility because you have published your Forth and you don't want to lose your audience, leads to vastly different answers.
The compiled code came out looking quite nice. I'm sure a decent C compiler would have done better, but it wasn't bad at all.
It meant all the stack noise was compiled as register move instructions leaving only calls to chunky words which were too big to inline.
[1] https://en.wikipedia.org/wiki/Barrel_processor
If you do your implementation on regular CPU, do a software pipelined [2] interpreter, which also can do several threads of execution simultaneously.
[2] https://en.wikipedia.org/wiki/Software_pipelining
Software pipelined stack machine interpreter was used to compress code for VLIW DSP.
People say that stack juggling is boring, but I actually find it to be a very natural way to think about computation. Forth's linear, concatenative style gives you SSA-like semantics for free, which makes it straightforward to lower into register-optimized bytecode or native code.
And once you're there, dynamic recompilation at runtime can do the rest. A naive, threaded implementation of Forth might not be performance-friendly on modern hardware, but there's nothing that prevents it from being high-performance. It just depends on how much effort you're willing to put into the implementation.
The usual implementation options are subroutine threading, indirect threading, and direct threading.
The problem is that every program is a DSL, so it’s hard to grep unless you built it. It’s a great personal hacking language though.
I often wonder, though, because of the mechanics of context with LLMs, if forth might not be the ideal language for LLMs to write simple tools for their own use?
Could we pawn off the “you should try forth” problem onto AI lol?
So in my opinion this is somewhat antithetical to the idea of FORTH
> 100% C/C++ with multi-platform support. Though classic implementation of primitives in assembly language and scripted high-level words gave the power to Forth, it also became the hurtle for newbies. Because they have to learn the assembly and Forth syntax before peeking into the internal beauty of Forth.
Fair enough to write a core of FORTH in C as a kind of portable assembler but most of the system should be written in FORTH in my opinion, then you can change it from FORTH. As fast as I can see eForth is written entirely in C.
Anyway FORTH is fun, writing your own is fun too and a great educational experience, but despite being a fan, I wouldn't write anything serious in it today. It is much too low level and it has even less memory safety than C!
The elegance of it continues to impress though with functional programming to get the job done and compile time programming to mold the language into that DSL which expresses the problem perfectly.
Tethered Forth programming on small devices is an underrated opportunity, IMO. There is also the opportunity to revise the OpenBoot project, I remember the days of automation for deployments at the Bios, it was an amazing tool for massive deployments of Sun T systems in telcos.
It has always fascinates me how Forth has been historically used for low level embedded programming, but also can be as high level as you’d like. I feel like this isn’t a concept that has really gone away.
IMO Forth is easiest language to implement from scratch, especially on stack based CPUs :)
- optimizing the code density (threaded interpretation)
- the dynamicism was said to allow for numerical optimization not possible in math libs / fortran long ago
(see J.V.Noble papers, I'm not knowledgeable enough to confirm his claims but i assume they hold some ground)
- the bare-metal repl feel is also special, as freeing as poking basic on old hardware but with the freedom of lisp in a way
forth sits in the thinking-altering languages land firmly imhoPhew - that is a terse language. I have heard it compared to assembly language and yeah I see that.
Prove that. Record some videos, show me some code and metrics that'll be evidence that I'm getting 10x more productive.
Look at the languages in the repository:
C 50.6%
C++ 47.6%
Forth 1.5% <-----
HTML 0.1%
Makefile 0.1%
JavaScript 0.1%
How does that build credibility?
Oh, please. I've written in Forth. It's useful when you have to do a cram job to fit in a really tiny machine. Otherwise, no.
The interesting question is why Forth lost out to BASIC on the home computers. There were a few that were Forth based, and there were RPL on calculators, so that whole programming paradigm could conceivably have caught on. I wonder how that would have affected other kinds of programming...
Thought for 1m 0s
Yes, it's possible to implement a Forth interpreter or compiler using a macro processor like M4 (and by extension, its evolutionary successor M5, which shares similar macro expansion and substitution principles). Macro processors excel at text transformation, making them ideal for generating low-level code (e.g., assembly) from high-level Forth definitions. While no public implementation specifically uses Alan Dain Samples' historical M5 (whose source and detailed examples are scarce), a robust example exists using GNU M4 to create a Forth-to-Z80 assembler cross-compiler. This targets the ZX Spectrum but demonstrates the technique: M4 macros define Forth primitives (e.g., stack ops, arithmetic) as Z80 instruction snippets, handling control flow with label counters for uniqueness.M5, as an M4 evolution, would adapt similarly—its enhanced features (e.g., better argument handling and streams) could streamline expansions, but the core approach (defining words as macro substitutions) translates directly. Below, I'll outline how it works, provide key macro definitions, and show a complete example. This generates human-readable, annotated assembly without peephole optimization but with inline efficiencies (e.g., DUP ADD → _2MUL).How It WorksCore Mechanism: Input Forth code (e.g., : FOO DUP ADD ;) is processed by M4. Macros like DUP expand to Z80 code preserving stack effects (data stack in HL/DE/SP; return stack in HL'/DE'/BC'). Labels use counters (e.g., if100) to avoid conflicts.
Stacks: 16-bit data stack; return address stack (RAS) for loops/recursion.
Compilation: m4 input.m4 > output.asm, then assemble (e.g., with Pasmo for Z80).
Adaptation to M5: Use M5's = for definitions (vs. M4's define) and => streams for output diversion. Argument parsing aligns closely.
Limitations: Uppercase words only; 16/32-bit ints; basic floats via ROM.
Key Macro DefinitionsMacros are modular (e.g., in stack.m4, arithmetic.m4). Here's a selection:Stack Manipulation (e.g., from stack.m4):
define({DUP},{ ; ( x1 -- x1 x1 )
ex DE, HL ; 1:4 dup
push HL ; 1:11 dup})dnl
define({SWAP},{ ; ( x2 x1 -- x1 x2 )
ex DE, HL ; 1:4 swap})dnl
define({DROP},{ ; ( x1 -- )
pop HL ; 1:10 drop
ex DE, HL ; 1:4 drop})dnl
define({PUSH($1)},{ ; ( -- n )
push HL ; 1:11 push($1)
ld HL, $1 ; 3:10 push($1)
ex DE, HL ; 1:4 push($1)})dnl
Optimization Example: DUP DUP → DUP_DUP for fewer instructions: define({DUP_DUP},{ ; ( x1 -- x1 x1 x1 )
exx ; 1:4 dup dup
push HL ; 1:11 dup dup
exx ; 1:4 dup dup
ex DE, HL ; 1:4 dup dup
push HL ; 1:11 dup dup})dnl
Arithmetic (e.g., from arithmetic.m4): define({ADD},{ ; ( x2 x1 -- x )
add HL, DE ; 1:11 +
ex DE, HL ; 1:4 +
pop HL ; 1:10 +})dnl
define({SUB},{ ; ( x2 x1 -- x )
or A ; 1:4 -
sbc HL, DE ; 2:15 -
ex DE, HL ; 1:4 -
pop HL ; 1:10 -})dnl
define({MUL},{ ; ( x2 x1 -- x ) [Binary long multiplication loop]
push BC ; 1:11 *
ld B, H ; 1:4 *
ld C, L ; 1:4 *
ld HL, 0x0000 ; 3:10 *
ld A, 0x10 ; 2:7 *
mul_loop101: ; *
add HL, HL ; 1:11 *
rl E ; 2:8 *
-- ETC ETC. Rest of assembly pørn censored.An interesting project chose it as its lang: https://collapseos.org/
When I’ve promoted LLM for Forth, I see words that I have to google, maybe they’re standard somewhere but… The silliest yet was 2LOOP where “2” seems to be a typo it scraped from the internet.
I’m gonna expand that suggestion!
2DO … 2LOOP — iterate using double integer
FORTH has been used to control deep space telescopes and planetariums --it's a great way to expose instrumentation for high-level access, but that access might not be human anymore, it could just as easily expose instrumentation to AI agents.
For example, a FORTH page could contain a prompt "Animate a galloping black and white zebra on the attached 64x32 RGB LED matrix, cache the code to do this on a FORTH page called ZEBRASHOW6432." Another could prompt "Run ZEBRASHOW6432 at the top of the hour during weekdays in the Pacific Time Zone." This might involve lifting C drivers from Arduino and CircuitPython for the 64x32 RGB LED matrix driver into FORTH (trivial) and building an MCP-to-FORTH server, but endless fun...
So I guess it's best to stop reading about FORTH and grab an rP0-2W and attach desired indicators, sensors, actuators and transceivers to see for yourself.