Hacker News new | past | comments | ask | show | jobs | submit login
What the hell is Forth? (2019) (information-superhighway.net)
273 points by harryvederci on Jan 13, 2023 | hide | past | favorite | 123 comments



If you want to build a Forth check out R. G. Loeliger's "Threaded Interpretive Languages Their Design And Implementation" https://archive.org/details/R.G.LoeligerThreadedInterpretive...

(Jonesforth has already been mentioned.)

Read "Starting Forth" and "Thinking Forth" too, even if you don't want to write a Forth or program in Forth. It'll still expand your mind in useful and fun ways.


BYTE magazine dedicated an entire issue to Forth in 1980 (vol 5, no 8). Interestingly, they used the exact same cover image as the Loeliger book, lol:

https://archive.org/details/byte-magazine-1980-08


You can also read the following "tutorial" on implementing the basic facilities of a forth right here:

https://news.ycombinator.com/item?id=13082825

I used that as a starting point to implement a trivial forth in golang.


these are all great recommendations, particularly the TIL book, which taught me so much about Z80 assembly language, though you really only needed a little bit to implement a forth back then - i went a bit bonkers in my implementation. i also used a a forth-like language implemented in C++ for an "adventure" writing system that taught me a lot about C++. you can't go wrong with implementing a forth if you want to learn.


I started using Forth because I wanted a Reverse Polish Notation calculator at the command line. It turned out to be very practical and extensible.

For example, I created many words to perform unit conversion, such as temperature:

    : 2fahrenheit 9 * 5 / 32 + ;
    : 2celsius    32 - 5 * 9 / ;
Furthermore, I can even pull in live currency conversion rates from Yahoo Finance to go between USD and CAD.

Since my underlying Forth interpreter runs on Python[0], I get the full large integer and floating-point support that Python has.

[0] http://openbookproject.net/py4fun/forth/forth.html



People who are interested in low-level language implementation might wish to learn a little dc, because its ability to easily produce arbitrary binary output may come in handy when boostrapping.


There was that old RSA in a sig file...

    #!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
    $/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
    lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
You'll note on that last line a |dc` as all of that stuff after the `echo` gets packed into something for dc to run.

http://www.cypherspace.org/adam/rsa/rsa-details.html


Thank you for linking this! Went down a 2-hour rabbit hole and it's really scratching some sort of itch.


It is exceedingly terse. Every command is a single character and the only required formatting is a single space to separate numbers. Just this side of line noise...


bc is built on dc and uses infix notation.

bc -l supports arbitrary-precision arithmetic, IIRC.


`k` in dc sets the fractional digits after the dot.

I am not sure there is a limit but 99 works ...


Good to know, can be useful.


Something I like about Forth is, that one can use almost anything in identifier names ant any position, because the language does not have arbitrary limitations in that like mainstream langs have. I also like that in Scheme. Very useful for making shorter and meaningful names.


Of all those what is forth articles I've read, this has been my favourite read. Forth is an interesting language, but as a web dev, I've never realised its potential to be a useable language. However, I recently got a RP Pico, and was looking for a language to control it. Browsing the available ones, I saw a demo of a forth and the way it was used kind of blew my mind as it kind of connected the understanding of the machine architecture with the language directly. It kind of felt like I was one with the machine even though I was just turning an led on and off. Since then, I haven't done anything with the board, but I want to get into simple EV making and I feel forth is the domain language for this kind of endeavour.


I think Forth reinforces that even more than machine assembly language does. It’s all just numbers and some ops, also encoded as numbers.


In my career of building programming languages, two of them arr Forth-based (stack-based)[0][1] and one is a Lisp[2].

I sometimes can't grasped how my Forth-based languages work when processing larger code, but it could have been easily because I never invested thst much into learning Forth anyways, which is why my third one is a Lisp.

Still, Forth is a very simple and incredible language. It is simple to understand, but harder to process on larger code. It is incredibly easy to implement, and easily extendable. It is also very predictable with only a few exceptions, which makes it a favorite for first-time esolangers.

The only shortcomings from Forth's design is getting used to stack-based operators, but I feel like it's something that can be adapted over time.

[0]: https://github.com/HoangTuan110/Nooklang

[1]: https://github.com/HoangTuan110/mil

[2]: https://github.com/HoangTuan110/owu


What a great read! I have to admit that I’m biased towards FORTH, I’m not a programar, more of a maker, so when I need to build an embedded project, Forth is my go to solution form my application. One of the benefits I have found in Forth “in my opinion” for embedded is factoring your code so that you only leave on the stack what you need, this makes for very compact machine code, great memory economics, and a relative fast system, even compared to C native code.

Working interactively with the HW is on of the most rewording parts of FORTH for me, to see the actual value of the bitfield you are using is great to trouble shoot new HW, and figure out just what you are doing.

One of the things I wish the FORTH community would do a better job of is, while keeping the interactiveness of Forth for development on the HW, it would be great to have a portable “true Forth VM” that you can take to a new platform and deploy a precompiled virtual Firmware or ROM. This IMO is beneficial for two reasons, you gain portability as the combined Froth adheres to the VM, and you can just take what you needed to the platform you are targeting, no need to have all the parts of a FORTH REPL or compiler. Just burn the App FW (VM + App) and you are done.

This would also allow for a single instance of FORTH, in the sense that your code will be portable across all systems, as the core compiler and interpreter are all targeting the VM and not the HW. Rather than build “ A Forth “ for each systems, you add the “HAL” that allows you to compile the VM for the HW. I use mostly ARM with Mecrisp, so I kind of have that now. Hint, it’s what make “arduino” so popular…

I highly recommend FORTH for Embedded applications, as I have build even a very BASI PID with little efforts… but it is a low level effort, and if you enjoy Bare-Metal development, you will be right a home in FORTH, if you are dependent on upstream libraries and HAL, you will, IMO struggle in FORTH regardless.


Not sure if this is useful for hardware, but there's UF [0] for Uxn [1], a tiny VM that can you can get to run on lots and lots of (old and new) devices.

[0]: http://www.call-with-current-continuation.org/uf/README (git repo link at the bottom of that page)

[1]: https://100r.co/site/uxn.html


A great introduction is the book Starting Forth [0].

It has the most charming illustrations I've ever seen in a text book.

[0] https://www.forth.com/starting-forth/


It is a grave error to introduce Forth without noting that it is universally recognized as the First Programming Religion.

Lately Lisp and Rust have begun to take on religious overtones, but Forth came first.

It is probably also a mistake to introduce it without mentioning that the first two (normally one-character) words defined are pronounced "builds" and "does".


Lately? Lisp has been a religion for decades.


Decades counts as lately. Are there any other programming religions?


Haskell, Julia, Rust, Lisp, and Forth are 'esoteric' enough to create an in-crowd, who are quite often deluded by imagined miraculous solutions to people's problems.

Please repeat after Fred Brooks: there ain't no silver bullet.

To a certain extent this goes on outside programming languages per se: OOP, Gang of Four, Agile match the pattern as well.


Feel APL similar in-crowd member too, though perhaps even more niche


Yup. Also HolyC (literally a religious undertaking), but the crowd had only one person, and he is no longer with us.


Went to a better place, one hopes. Maybe one where he is appreciated, and not considered mad.


The "in-crowd" vibe is very different from religion. We admire a language for its strengths, but worship it for its faults. APL is beginning to shade into theological territory.


I don't think the article mentions metacompilation, which is a further cute and mind-bending feature Forth is known for.

Metacompilation re-uses the live, running interpreter/compiler to compile a new system image of itself, from source code.


I've made a few meta-compilers before, there's nothing quite like bringing up a system from scratch and getting it to compile itself. It's one of the (few) things Forth is good at.


Incredible language. FORTH is like that unsung bluesman from the 30's that inspired rock superstars of the 60's & '70s. The OG, barely-above-assembly-language language.


Last year's Advent of Code I dived into Forth a bit (used GForth). Solved 5 puzzles in it, but then I got stuck, when I was reading in the input of a puzzle and the lines in the file were of varying length. I did not find a way to properly clear the previous line buffer and got wrong results because it still contained characters from an earlier longer line. I asked around for a solution but did not get anything helpful that always works. I think more time would be needed to truly get good at it. Learning some patterns that are typically used in the language to do things like reading a file line by line and processing it. Some string related stuff is supposed to become better in GForth soon, when 1.0 is released. Good to know!

That said, I did enjoy it sort of, until I got stuck. Sometimes definitions can be very succinct and it made me think about implicit arguments vs explicit arguments to functions. In Forth all is implicitly on the stack. It has to be there already, when you utter a word, otherwise you are making a mistake. That is of course harder to program correctly, but makes code very short. Also gets you naturally into the territory of higher order functions and point-free style.

What I think could be an issue with existing programs is, that one needs to build and memorize a mental model of all the implicit arguments words take. It adds one more lookup to the definition of a word. But perhaps this is a tradeoff for very readable code (if written very well, very well factored).

I also thought about "How could this ever do multicore?" and "How can any data structure be better than linear time, if everything is on a stack?". GForth seems to have stuff for making threads, but I have not gone that far on my journey.

Just try it. It is an interesting experience.


This is a great article! I love his description of Forth as "a weird backwards lisp with no parentheses".

Reading the source code of "WAForth" (Forth for WebAssembly) really helped me learn about how WebAssembly works deep down, from the ground up.

It demonstrates the first step of what the article says about bootstrapping a Forth system, and it has some beautiful hand written WebAssembly code implementing the primitives and even the compiler and JavaScript interop plumbing. We discussed the possibility of developing a metacompiler in the reddit discussion.

I posted this stuff about WAForth and a link to a reddit discussion with its author in the hn discussion of "Ten influential programming languages (2020)":

https://news.ycombinator.com/item?id=34056735

Yes, I agree FORTH should be probably be on the list, at least if the list was a few languages longer, for as influential as it's been.

WAForth for WebAssembly is beautiful and modern!

https://github.com/remko/waforth

It's a lovingly crafted and hand written in well commented WebAssembly code, using Racket as a WebAssembly macro pre-processor.

I learned so much about WebAssembly by reading this and the supporting JavaScript plumbing.

The amazing thing is that the FORTH compiler dynamically compiles FORTH words into WebAssembly byte codes, and creates lots of tiny little WebAssembly modules dynamically that can call each other, by calling back to JavaScript to dynamically create and link modules, which it links together in the same memory and symbol address space on the fly! A real eye opener to me that it was possible to do that kind of stuff with dynamically generated WebAssembly code! It has many exciting and useful applications in other languages than FORTH, too.

Lots more discussion and links in the reddit article.

But here's the beef, jump right in:

https://github.com/remko/waforth/blob/master/src/waforth.wat

Reddit /r/Forth discussion of WAForth:

https://www.reddit.com/r/Forth/comments/zmb4eb/waforth_wasmb...

remko:

Author here

If you can't be bothered to install VS Code, you can have a look at a standalone version of the example notebook (in a 26kB self-contained page).

And if you're planning to go to FOSDEM 2023, come say hi: I'll be giving a talk there on WebAssembly and Forth in the Declarative and Minimalistic Computing devroom.

DonHopkins:

I really love your tour-de-force design and implementation of WAForth, and I have learned a lot about WebAssembly by reading it. Never before have I seen such beautiful meticulously hand written and commented WebAssembly code.

Especially the compiler and runtime plumbing you've implemented that dynamically assembles bytecode and creates WebAssembly modules for every FORTH word definition, by calling back to JavaScript code that pulls the binary bytecode of compiled FORTH words out of memory and creates a new module with it pointing to the same function table and memory.

WebAssembly is a well designed open standard that's taking over the world in a good way, and it also runs efficiently not just in most browsers and mobile smartphones and pads, but also on the desktop, servers, cloud edge nodes, and embedded devices. And those are perfect target environments for FORTH!

What you've done with FORTH and WebAssembly is original, brilliant, audacious, and eye-opening!

I'd read the WebAssembly spec before, and used and studied the Unity3D WebAssembly runtime and compiler to integrate Unity3D with JavaScript, and I also studied the AssemblyScript subset of TypeScript targeting WebAssembly and its runtime, and also Aaron Turner's awesome wasmboy WebAssembly GameBoy emulator .

I first saw your project a few years ago and linked to it in this Hacker News discussion about Thoughts on Forth Programming because I thought it was cool, but it's come a long way in three years, and I'm glad I finally took the time to read some of your code, which was well worth the investment of time.

Until reading your code, I didn't grasp that it was possible to integrate WebAssembly with JavaScript like that, and use it to dynamically generate code the way you have!

Also, the way you used Racket as a macro assembler for WebAssembly was a practical and beautiful solution to the difficult problem of writing maintainable WebAssembly code by hand.

Even for people not planning on using FORTH, WAForth is an enlightening and useful example for learning about WebAssembly and its runtime, and a solid proof of concept that it's possible to dynamically generate and run WebAssembly code on the fly, and integrate a whole bunch of tiny little WebAssembly modules together.

Playing with and reading through your well commented code has really helped me understand WebAssembly and TypeScript and the surface between them at a much deeper level. Thank you for implementing and sharing it, and continuing to improve it too!

remco:

Wow, thanks a lot, I really appreciate that! It makes me very happy that I was able to get someone to learn something about WebAssembly by reading the source code, which is exactly what I was going for.

[More links and discussion of WAForth, WebAssembly, and Forth Metacompilers:]

https://www.reddit.com/r/Forth/comments/zmb4eb/waforth_wasmb...


Here's the author's blog post about WAForth:

A Dynamic Forth Compiler for WebAssembly

https://el-tramo.be/blog/waforth/


i had a room mate in the early 90's who was a forth programmer. At the time they wrote the code that did the airport displays. It was all forth. I wrote c back then and never really grasped it. Always seemed a little like a weird assembler.


It’s a meta-assembler. You can see every word you define as a new instruction you define. For example, if you want an instruction that multiplies by 17, you do

  : 17* 17 * ;


Indirect threaded code is quite a universal program representation.

We used to have our Forth-like system back in 1994, with a virtualized NEXT point, so we had execute, interpret, compile and two link stages behaviors for each word. This allowed produce making an optimizing linker, which produced very tiny .COM-files. I still have source code for it.

I think this idea can quite easily be taken to the extreme, and allow adding things like - type checking - debugging - SSA IR generation (say, for LLVM optimizer) - lots run-time checks (for tests)

So I believe a Forth system can be made quite safe.


For a more modern language that scratches the same minimalist syntax itch as Forth, try Red [1]. It's list-based rather than stack-based and includes the "killer app" of a really nice DSL for GUI layout. Even including the excellent PySimpleGUI, it's the fastest way to build up a custom GUI without a GUI builder tool.

[1] http://redprogramming.com/Getting%20Started.html


Lots of virtual machines are stack machines and lots of languages compile to bytecode for a virtual machine. I thought that bytecode being a language in its own right would be a good idea so tried using Forth for it. Had a rough plan of a toolchain resembling a ML implemented in a lisp compiled to a forth. There's an article (by Baker?) which showed recursion and iteration folding to the same code on a stack machine which is beautiful.

That project was an abject failure. I was not good at programming stack machines. I can't keep track of where things are on the stack. The Forth way seems to be using lots of short functions (uh, words) with predictable stack behaviour that compose to more complicated behaviour, and I struggle to keep track of many small functions too. Both combined is really tough. I essentially need to use a compiler to reliably target the stack VM.

It turns out I type while I think and that yields large, sprawling functions with dead paths and mistakes. That's then refined and factored as my thinking clears. A repl sort of works for this but there's a lot of reaching back to gather the pieces where the working ones are not clearly distinguished from the failed experiments. The large messy work in progress function strategy did not work at all in forth.

It's surely possible to retrain oneself to think the Forth way. Might be worthwhile, though it's hard to guess the value trade-off before doing so. People tell me it's worthwhile, and they were right about that with lisp, so I'm probably missing out.


Forth people like to factor code into very short words, to help avoid confusion with the stack. Words should be properly commented so that their stack effects are clear.

https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/Fac...


wow!!! This bring me a lot of memories. Back in 1988, I wrote a Forth program to control a X-Y table to control a ultrasound probe to inspect metal parts. The program was running on a Radio Shack Color Computer 2 (TRS-80) with 16k of RAM. The program itself was running in OS-9 operating system. Remember, there was no hard drive on this, only one floppy drive! Amazing to see how far we come from!


Here are some great resources on Forth:

http://www.call-with-current-continuation.org/articles/forth...

https://git.sr.ht/~vdupras/duskos/tree/master/fs/doc/design/...

https://www.youtube.com/watch?v=9TJuOwy4aGA

Let me quote the first essay at length:

> Writing "good" Forth code is very hard, or at least what I consider good Forth code, which may be different from what others consider good. Forth has been called a "write only language", but only because it requires an additional effort to simplify your code to a point where everything becomes obvious. This is an art, it is a moment of transcendence, which I don't claim to have ever reached, but sometimes I get a glimpse of it, an inkling of the fact that if I would work very hard on this, it will become so simple, so heavily factored, using such obvious and clear names that everything just falls into place. It is this moment that programmers experience every once in a while, where a short, simple piece of code just does what it is supposed to do, without any extra baggage, easily understandable. To achieve it in Forth is much harder, it may require more time, many rewrites, but the results are even more satisfying, as the result is smaller, much simpler, fully self-contained and not burdened by code that you can not trust. When you forget about that urge of productivity, which has become the moloch we sacrifice our children to, you may be able to achieve that particular thing that is called quality, elegance, art. It may take a lifetime, you may never reach that far, but still you should strive for it.

> Or you remain a cog in the machine, developing on absurdly convoluted "software stacks", using inadequate and brittle languages, connect barely matching interfaces to only small parts of too many bloated libraries, using insanely sophisticated tools of incomprehensble complexity and trot on, asking yourself why everything sucks and why the last time you actually enjoyed programming and were you could be genuinely and deservedly proud on what you accomplished, was when you were a kid...

It seems to me that a lot of ideas in mainstream computing are pointing towards dead ends, and the practice of software engineering is either stagnating or in decay. Maybe it's time for a more radical reconsideration of how we build software, and time to give Forth (or something like it) a more serious look.


I would not hold my breath for it to revive software engineering, if the end result is purportedly to make a pretty program. No doubt quality is severely lacking in modern programming, but programming is a means to ends other than autoeroticism.

And Forth is nothing new as a low-level, bending-over-to-the-machine language [1], except that its users to have constant urges to decry everything else as bloat (first link), civilisation-threatening, training wheels (third link), and all those wonderful things. Just don't do anything [0], and hoorah, you can write nothing too.

[0] https://news.ycombinator.com/item?id=28771886 is a classic on that topic.

[1] Bemusingly this does not make it necessarily fast; some Forthen are too simple and too low-level for compilers to get much done, c.f. https://applied-langua.ge/posts/i-dont-want-to-go-to-chel-c.... for the video described in the third link.


Wow, I haven't seen anything regarding Forth since the last time I was using an old PowerMac as a daily driver. The openboot firmware for those old macs was a forth interpreter.


Seems you can start with way less than 30 instructions.

A 3-INSTRUCTION FORTH FOR EMBEDDED SYSTEMS WORK Illustrated on the Motorola MC68HC11 by Frank Sergeant

https://pages.cs.wisc.edu/~bolo/shipyard/3ins4th.html#:~:tex....


Forth is nice and very handy to have on something like and Arduino Uno (and similarly spec MCU's) etc. It allows rapid experimentation without compiling/uploading.


Wait! Is core Forth smaller than core Scheme?


Scheme is deceptive. I think R5RS was all of 50 pages or so. But try implementing quasiquotes, closures, lexical scoping, tail call optimization. Not to mention the trickier things of call/cc, dynamic-wind, hygienic macros. There is a surprising amount of complexity involved. Even if you do go with the simplest of GCs, which is probably stop-and-copy.


Much smaller in terms of code size and memory used, yes. A small Forth running in 2 kilobytes RAM is easily done.


You can write a Forth-like in a few lines of a modern language and then keep expanding it. There are Forths for the smallest systems and challenges of minimal instruction set Forth, like [0].

The article [0] explains what people (and myself) are really happy about having this around:

> Let's pretend I've wired the 68HC11 so that port A pin 01 controls an LED. I can't remember whether a 0 or a 1 turns it on and I'm not sure whether it works. I look in the data book and find that address zero is the port A data address. Although the LED only uses a single bit of port A I don't have anything else connected so I'll just set the whole byte on or off and see what happens.

Without that, embedded work is far more annoying. And I do like the way it works; every so many years, I start implementing my own to figure out if it's really not possible to make something modern [1] (written to play around with Xamarin apps and ASP.NET servers without having to wait 9 hours for the compile & deploy to finish, so in the spirit of Forth indeed) with it which always falls over on stack manipulation, which gets incredibly annoying when programs grow; you waste so many instructions just to line up the stack correctly to execute a some more complicated word. We currently have a hybrid language (hopefully released this year) with datatypes, stack, (reactive) variables etc, but that is getting rather huge (for a Forth) and, because of other features we have, it's more like a Frankenlanguage, marrying Forth & Lisp... That works well but not anything usable in embedded or in the spirit of the original Forth, besides spelonking/scripting systems.

[0] https://pages.cs.wisc.edu/~bolo/shipyard/3ins4th.html [1] https://gist.github.com/tluyben/16ee2645c4c8aed813005d51488d...


Forth semantics work nicely as unstructured glue, I've found. As you start getting into the weeds of algorithm design it becomes more of a puzzle. But that also makes sense, in a Forther context. The most Forth-like thing to do is not to start abstracting and imposing structure so that you can have a configurable algorithm, but to define down the problem to a table of static results, and thus complete the circle of "code is data". I believe Chuck Moore said something to the effect of Forth being in the workflow and mindset: once you have a problem defined to need that much complexity of automation, it's not a problem solved by Forth-the-language.

Of course, Moore also has done some algorithmically complex things with Forth-the-language, so I might be off-base in that assessment.


If you think about garbage collection alone, you might guess...


I first ran across Forth here https://jeelabs.org/article/1651c/ early in my career. Fascinating language.


I didn't really understand forth till I tried implementing eforth in c.

https://github.com/tehologist/forthkit

Managed to write a compiler/interpreter that could understand enough forth to implement the entire system. Less than 500 lines and only uses stdio.h and compiles using TCC

https://bellard.org/tcc/

That was so much fun I built a second one in under 300 lines of javascript for experimenting with canvas api in web browser. Single file doesn't require a server, you can drag and drop code onto text window.

https://github.com/tehologist/ecma6-forth

Runs standalone, I want to get back to it again.


Along similar lines, i once watched this guy on YouTube implement a Python-based Forth _compiler_ (not interpreter) and optimize the crap out of it. It was a great video, if anyone’s interested it was called “Porth” and i think his GitHub page has a link to the video.


Found the video you referenced.

https://www.youtube.com/watch?v=8QP2fDBIxjM&list=PLpM-Dvs8t0...

I met the creator Charles Moore a few times. When I lived in the bay area and used to go to the svfig (silicon valley forth interest group) meeting. He would often talk about forth was like solving a puzzle, likened it to sudoku. It is a good exercise for the brain and I highly recommend it.

https://www.forth.com/starting-forth/


Back in the eighties I went to a presentation by Moore on VLSI design featuring a GUI design tool he wrote in Forth. The physical user interface was via contacts taped to his fingers and thumb, he would touch them together to navigate the UI. We were very impressed.

I still have a tshirt that reads “Be Moore Like Chuck”…


I know it's a lot of fun writing Forths and that's how most people tend to experience Forth, but I like to urge people to actually build applications on Forth. Understanding Forth by writing applications is probably the best way to get a feel for Forth.


Is there any "battery-included" ANS Forth (more or less like Python/Go) which provides access to concurrency, networking, database, GUI, etc?

Not an embedded device programmer, but mostly deals with frontend apps, and occasionally backend, so those are very relevant to me.

Or perhaps use "non-traditional" Forths like 8th (https://8th-dev.com) or Factor (https://factorcode.org)?


gForth is probably the closest you'll get to a batteries-included ANS Forth. It has a lot of libraries and does have some GUI libraries. It definitely has networking and some amount of db words, I'm not sure what it's concurrency situation is like.

8th is a great not-Forth. Highly recommended because of how practical is.


I still use it when exploring a microcontroller, lately with Mecrisp-Stellaris Forth on an STM32 device. It's a joy to use.


I've been wanting to evaluate forth as a personal computing language, does anyone know any games written in pure forth?


Blog author here, in 2020 I released a DOS game built completely in my own Forth system. Fully open source and hackable. https://spindleyq.itch.io/neut-tower

The coolest application of the Forth philosophy in that project was actually building tools that integrate directly with the engine, imo. I built a map and tile editor directly into the game for quickly iterating on art and level design, and at one point even added a slide presentation engine for giving talks with that had live demos integrated directly into slides. The eureka moment was when I added map editing and realized that I didn't need to write a fancy GUI just for saving and loading maps, because I had a live Forth console running over the serial port. As soon as I'd written the save/load routines they were immediately, directly usable.

Death Road to Canada is another game I'm aware of that is written in Forth, for more modern platforms.


I really enjoyed reading your Forth related blog posts, that's why I shared this one on HN. Thanks for writing them!

I also liked these:

- https://blog.information-superhighway.net/data-is-code

- https://blog.information-superhighway.net/retrocomputing


There was a bit of discussion over on Reddit of a game called "Cosmic Conquest", printed in an edition of Byte magazine, that is supposed to be the first space RTS. That was entirely written in Forth on the Apple II.

A few of us managed to resurrect the code, and I've managed to get it more-or-less working as intended. Once I get time I'll tidy up the bits I wrote so they're fit to show in public.

Here's a video of it:

https://gjcp.net/conquest.mp4


Like this language itself this article seems to give a good overview in a concise format. Thanks!


As Clutch said, "All the best locations are located on the margins".

It's a shame that the term "Red Pill" has been co-opted by the right-wing crazies like QAnon, because it tarnishes what would otherwise be an excellent term.

Forth, located on the margins between assembly language and high-level languages, is the Red Pill of compilers.

You go from a kilobyte or so of assembly to a fully-working operating system, mostly written in Forth. You've jumped the gap from a system that doesn't even boot to something you can type commands into and get expected results, and write useful code, and do real work on. It fits onto a couple of tracks worth of a floppy disk, and - more importantly - it all fits into your brain in one go.

So, do you take Forth, stay in low-level land, and see how deep the rabbit-hole goes?


The author complains about not having local variables, but most decent Forth environments have them. It is not difficult to have local variables in Forth, just use a library or compiler that provides them.


The language has, perhaps, a bit too much Chuck Moore: Don't reuse code, don't make code reusable, and don't try to anticipate anything. The knob is turned all the way over to the "simplicity of implementation" end of things, and all else be damned.

http://www.cs.uni.edu/~wallingf/blog/archives/monthly/2017-1...


With regard to local variables, although standard Forth has them or considers them as an extension, Moore is correct in the sense that they are a crutch for when you did something wrong - often they allow to sweep under the carpet a "stack juggling" issue, which is usually a sign that you should reconsider your approach to the problem.

FYI Moore also designed processors; one of his designs was apparently viable enough to be part of the Rosetta mission. At some point he wrote his own CAD program to design his processors, which are at the very least functional.

It's not "simplicity of implementation" for the sake of it. It's about finding the simplest solution to a problem. But people too often confuse "simple" with "easy" if not "lazy" or "simplistic" - like your depiction of his approach.


Yeah, but it goes to 11!


Author here. I didn't have a decent Forth environment, I had a weird mess that I built myself from scratch. I ended up implementing a lot of "sophisticated" features - coroutines, cooperative multitasking, an interactive debugger - but I was never annoyed enough by the lack of locals to seriously contemplate spending the effort to build them, so I just didn't.


I believe that any programmer should at least know a little about Forth. It's like Lisp. Just knowing about them is extremely enlightening, even if you don't use them in your daily life.

Obligatory link: https://github.com/nornagon/jonesforth/blob/master/jonesfort...

This well-written tutorial will have you implement a Forth in 500 lines of assembly and another 500 lines of Forth.

You will feel like a different person after having done this. People will like you more. Food will taste better. You'll never be alone again, always knowing that you can re-create a fully-functional programming language from assembly within half an hour, if you needed to. It is said that people who know Forth die happy.


Agree with the parent, it's a language worth knowing like LISP is worth knowing, but (unlike LISP) it is not a good language choice for almost all use cases in 2023 (almost all use cases are not that memory constrained any more, even embedded systems), for the same reason you shouldn't use Perl (it is very hard to read code).

I was going to say "its main disadvantage is that the only way to find out what a piece of code does is to execute it mentally" (non-declarative) but one may say that of every language to an extent. Instead I will say it feels like using a macro-assembler for a stack VM.

Clifford Stoll, author of "The Cuckoo's Egg", in which he described how he chased a hacker, allegedly used FORTH to control a radio telescope (https://www.amazon.co.uk/gp/product/1416507787) back in the days (not sure, I might have got this nugget from the book).


  > for the same reason you shouldn't use Perl (it is very hard to read code)
I slightly disagree with this take on Perl. Agreed that it is easy to write code which is hard for others to read, and agreed that it is often not a good idea in a large-team setting, for that reason.

But there is a lot of code that doesn't fall in that category, and Perl, by its nature (and by CPAN), can be remarkably good at just "getting stuff done" for oneself. All the wild syntax can really help in expressing a concept succinctly.

I wouldn't say the same about Forth, though.


Not trying to disparage Perl, which has some utility, like most languages, notably fast regex engine and presence on many systems.

BUT: I've been writing Perl for much longer than Python, but despite wanting to write readable/maintainable code, Perl has a tendency to get you to a stage where your code looks cryptic (part of it is by design - Larry Wall, a linguist, values implicitness as "context" - I think explicitness, by contrast, should be aspired to, in order to avoid confusion). I've never written cryptic Python code (and I am not a particular Python fan, as I prefer statically typed compiled languages), but it should be said that clarity is one of Python's advantages.

I agree with you that it is easier to write readable Perl than readable FORTH, which could be due to the similarity of Perl with other non-stack imperative languages.


Well, in Forth there isn't much "wild syntax" to begin with, so naturally you couldn't claim the same about Forth.


Someone told me once that Perl was write-only.


I don’t really feel I can judge whether it’s good or not to use generally, but it’s difficult to obtain a similar degree of DSL-ness even on pretty powerful (e.g. Micropython-grade) constrained platforms. Forth, along with Lisp, is one of the original DSL substrates (Thinking Forth spends like half its pages on preaching EDSLs), and I don’t think it’s really been supplanted in that niche by anything that doesn’t require a beefy GC.

(The extremely easy bootstrapping from any point down to an ISA manual and a ROM programmer—or a monitor that accepts peek/poke/goto from a UART—I also don’t think has really been replicated anywhere else.)


DSL just a library that exports a lot of functions that work together any language that allows naming functions does that?


If you don’t care about syntactic convenience, yes. In practice, a(n idiomatic) Forth “library” can have an API like, for example,

  1000 ,bp) ax mov,
for laying down assembly code in memory (might look a bit unusual, but think “postfix assembler” and it’ll become natural soon enough). If you want this to compile down to byte writes and arithmetic without requiring an assembler library at runtime (DynASM-style), you can do that as well.

Custom control structures[1], object systems, perfect hashing, parser generators, all that fun stuff that’s possible with flexible syntax and arbitrary compile-time code execution, people have done it. You never have to think whether an X-macro is sufficiently ugly yet to warrant a custom preprocessor. (If you want to say “web templating”, you can say “web templating”, except it’s not that pleasant with manual memory management, and most of what I’m thinking about was written in the 80s.)

There’s nothing impossible about this in any language (the absence of a competent C REPL continues to amaze me), but not all languages are good at everything they can technically do, and Forth is good at these.

(Forth is also bad at some things. If you want code that transparently works on floats and doubles, or 32- and 64-bit addresses, on the same system depending on a compile-time setting, it’s going to be painful. Passing abstract types by value is impossible to do elegantly as far as I know. Omitting unnecessary code from the executable, trivial with static libraries and a linker, requires adapting half your implementation and is a serious selling point for commercial Forth systems. And so on.)

[1] I know we’re all alleged adults and are not supposed to get excited about these, but does LuaJIT’s FOLD tree peephole optimizer, for example, qualify as a legitimate custom control structure? (It’s implemented with a combination of macro magic and a custom preprocessor.)


The original use for FORTH was to control radio telescopes.


I was delighted (and saddened) when I discovered a Forth manual written by W. Richard Stevens for Kitt Peak observatory. A great writer lost far too young.


> it is not a good language choice for almost all use cases in 2023

I think I agree with this. But it’s fun to think about wild scenarios where it would make sense.

Like some dystopian future where people are trying to cobble found hardware together to make something.


> Like some dystopian future where people are trying to cobble found hardware together to make something.

https://git.sr.ht/~vdupras/duskos

http://collapseos.org/


Thank you!


I don't know, I think it can be a pretty solid language depending on what variant you use. There are few pieces of code in Forth that make me think "man, this seems repetitive, but I don't know how to actually generalize this" because abstraction is little more than structured copy+paste.


> abstraction is little more than structured copy+paste

Which perhaps is logical, since Forth is a concatenative language. Roughly, one can split a program in half at any point and get two subprograms which can be called one after the other - in the same order - to get the same result.

Like, to calculate 2 + 3 * 4 one would write 2 3 4 * + in Forth, this sequence can be split in two 6 different ways, and we can even meaningfully interpret those two parts each time. E.g. part 4 * + is a two-argument function which multiplies first (closest to the top in the stack) by 4 and sums the result with the other argument - in JavaScript it would be function(x, y) { return 4*x+y; }.


Perl doesn't seem like it should necessarily be hard to read (I'm not a perl programmer) but agree that most perl that I've seen is pretty opaque. I guess if you really get to know the idioms maybe it's easier.


I guess if you really get to know the idioms maybe it's easier.

It is, as long as you stay away from things like selfgol* or memowe's keywords only JAPH** (which is technically very readable, it's just very hard to comprehend).

* https://libarynth.org/selfgol ** https://www.perlmonks.org/?node_id=594266


If a Forthlike language was to be made today, what features would it require to not be a hard-to-read mess? I can see some type of typesystem being useful, I dont know what else can make it better.


Typing would make things more verbose, but not any more readable than just writing words for each type of data you're dealing with, which accomplishes the same thing. Forth can dictionary mask and forget words, so typed-lang-style overloading is trivial, but unnecessary.

Many short word names could be expanded from symbols and abbreviations suited for 4-character names into more verbose versions, but the underlying RPN stackiness would still prove an impediment to broad understanding.

Native vectorization like APL or Lisp would increase the base complexity of the language machinery and make implementation more complex, but would allow the language to be simpler by getting rid of the need for most stack reordering.


> It's like Lisp. Just knowing about them is extremely enlightening . . .

I agree. My introduction to Lisp was Seibold's Practical Common Lisp -- a very hot book back in the mid-to-late aughties, that I suspect introduced a lot of people to Lisp.

Forth feels like it's having a similar moment (by which I simply mean: a lot of people are talking about it in terms of enlightenment, not that it's going to replace JavaScript!). So I wonder. Think someone will write a Practical Forth?


A million errr 40 odd (my back is dim etc) years ago the end of year stuff (open day etc) was fast approaching. Our science teacher asked a few chaps (all boys prep school - Devon, UK) to have a go at showing off this computing thing or something, oh and I have this Forth thing on tape and this: ZX Spectrum. We'd graduated from ZX80s and 81s. We had 20 brand new Speccies newly bought. The Promised Land beckoned.

We cobbled together text whizzing smoothly across the screen and changing colours within about 20 mins of loading the thing. Loading from tape took a good five minutes. Unlike the C64 and Vic20 the Speccy used consumer tape units.

I have absolutely no idea what you are on about with your big boy modern programming terms but I managed to convince quite a few parents that their sprogs were at the cutting edge or at least wasting time well, back in the day!


I couldn't get jonesforth to compile correctly. Not sure why. I found a python and a javascript implementation, not sure if I like them. Any recommendations?


Do you maybe want to tell us how exactly "not compile correctly" manifested?


I made tons of typos in both the assembly and Forth part when I did mine, but it did end up compiling correctly. Hunting the typos down was hard though because you get literally 0 feedback.


I've also heard it cures cancer. Any truth to this?


The percentage of people with cancer who are Forth users is very low. Take that as you wish...


It can alleviate the symptoms of javadenomas


Results not in yet but it looks promising, yes.


Did you mean:

THIS TRUTH ANY TO?


CHECK FACTH FIRTH YOUR


Downvoter prolly doesn't know Forth, and fifth, has no sense of humor :)


I got downvoted. Humor is bad on Hacker News.


Humor involves a point of view, and that's not allowed. Just ask ChatGPT.


> A single person should be able to understand a computing system in its entirety, so that they can change it to fit their needs

This idea combined with the notion that software written by someone else necessarily serves their purposes rather than yours has me gradually working in that direction. Really all I need to do is write (or run) a forth on some bare metal. It's fun to build your own hardware as well which is what I'm during learning by doing right now too. Once I realized it was possible after reading jonesforth, I've been interested in (obsessed with) the idea.

To quote jonesforth:

> You really can write a complete FORTH in, say, 2000 lines of code. I don't just mean a FORTH program, I mean a complete FORTH operating system, environment and language. You could boot such a FORTH on a bare PC and it would come up with a prompt where you could start doing useful work. The FORTH you have here isn't minimal and uses a Linux process as its 'base PC' (both for the purposes of making it a good tutorial). It's possible to completely understand the system. Who can say they completely understand how Linux works, or gcc?

> Secondly FORTH has a peculiar bootstrapping property. By that I mean that after writing a little bit of assembly to talk to the hardware and implement a few primitives, all the rest of the language and compiler is written in FORTH itself.


The part about the language being a little bootstrap and then mostly implemented in its own language...

Are there other languages like this? At least any mainstream ones?


Lisps, can be, and sometimes are, implemented in a similar way. Trying to figure out the exact number of Lisp primitives required to write the rest of Lisp in Lisp is seemingly a hobby for some. A compiler for a functional language usually transforms the program into another functional language, an intermediate representation, one much more friendly to machine-implementation. (The classic model has four pointers to four lists and has simple operations for the items in those lists, and that's about it.)

It's a relatively small leap to writing the language in that subset, and implementing a small virtual machine for that subset, and then executing the language. Many toy Scheme implementations have been written in this way. But most major implementations, while often written in Lisp (or Scheme), generally do not do that. They use the full language and are not able to bootstrap like that. Though the 1980s Lisp machines kind of did do it that way. The garbage collector and parts of the OS and runtime were written in a Lisp-like assembly language.


https://github.com/udem-dlteam/ribbit

And https://piumarta.com/software/maru/

Are two good examples. Maru is interesting in that it can implement a full-fat language/os/vm/compiler in under 2kloc

Bluebottle is another barbecues and up OS: https://github.com/btreut/a2


Well, Norvig's (et. al.) JScheme - http://norvig.com/jscheme.html - is implemented in Java - partially, and then a bunch of core functions are written in JScheme itself.

Or, if you look at implementations of J... like this - https://code.jsoftware.com/wiki/Essays/Incunabulum - it's basically creates something closer to J in C and then writes the rest of the interpreter. If you squint hard enough...


I remember and learned a little forth because of that console you could get with PowerPC Macs back in the day. I think I remember there was a key combination to boot in that embedded forth interpreter. It was pretty cool


https://en.wikipedia.org/wiki/Open_Firmware

(Hence the key combination cmd-opt-O-F)


It's an interesting decision to write an article like this without actually showing any Forth code.

I think I like it?

Either way, I am compelled to build a Forth interpreter this weekend. Sounds rad as hell!


Here we go again :)

I've written a ton of Forths over the years in different languages, and every time I run into an article about it I get the itch to do another one.


> get the itch to do another one.

If you really want to satisfy that itch you should try building a Forth computer from scratch. Back in the 80s a friend showed me how to build a Forth CPU from PLAs (might have been some earlier cheaper form of programmable logic, heheh) and SRAM plus a little random logic. By the end of the weekend we were running floppy drives and a crt with it.


I used Forth for a while in the early 80's, but I don't miss it. It took a while to get used to it, but since everything I had done before that had been assembly language or interpreted Basic, it wasn't a steep curve. I remember doing things like writing code to take a string that was to be printed on a small dot matrix printer, like what you would find in a cash register, and flipping it upside down because the printer was physically mounted upside down in the final product but they wanted the print to be right side up when the tape exited the machine.


> A system does not have to be complex to be flexible, extensible, and customizable

An important lesson that many teams and orgs still haven't internalized. Maybe one day it'll be more commonly understood.


Complexity frequently doesn't come from the logical requirements of the system, instead it comes from the need to integrate the system to the VERY COMPLEX environment where it resides. Any simple web system nowadays needs to integrate with a complex web environment, with dozens (if not hundreds) of protocols, OS layers, databases, just to begin with. This is why you need hundreds of thousands of lines (or equivalent libraries) to create the simplest funcional application these days.

The secret of Forth is to avoid the environmental complexity by creating a language that is so simple that it barely needs any support and any integration with other systems. This is also its major weakness for commercial use.


I didn't even see a mention of the old bumper sticker:

"Forth love if honk then"


  フォースが好きなら、クラクションを鳴らしてよ
  [forth][love][if]  [honk]              [eh]


In Factor:

    "Factor" love? [ honk ] when
Not nearly as lyrical, but perhaps easier to understand.


Loved the article. I played around a but with Forth in the mid 80’s and my experience was very similar to the authors, eg astonishment that one could have a language/computing environment that was simple enough to understand in its entirety yet trivially extensible. Forth also makes complexity ridiculously hard, so you end up breaking down complex problems into simpler ones.

I never tried to build my own Forth, though.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: