
Understanding What It's Like to Program in Forth (2008) - pcr910303
https://prog21.dadgum.com/33.html
======
dwheeler
Forth is truly amazing in terms of what you can do with very little RAM and
CPU power. It is quite possible to have a working interactive development
environment and production implementation in only 4-8 kibibytes of RAM. In the
world of small memory 8 bit computers it was amazing.

I think Forth can be useful to learn today, at least to stretch the mind to
realize that not all programming languages have to be variants of Algol. It
can also be a fun game as suggested by the article. I have enjoyed fiddling
with it, including re-implementation of the language, and I can recommend it
to others as a fun Bazaar toy. In addition, the book Starting Forth is amazing
and still worth reading, because it shows that complex topics can be explained
clearly and with humor.

However, for actual production use, I do not think the Forth programming
language is ever going to return to widespread actual use. Our computer
systems are far more capable, and if you have to program a tiny of computer,
you would use a larger computer for programming instead of trying to fit your
development environment within a few K of RAM. Nowadays the big constraint is
development time, including the time to develop the resort code the time to
read existing code to modify it. Forth doesn't do as well by those measures.
When something is trivial another languages, but it's a puzzle to solve in
Forth, that is not a good thing. That does not mean that Forth is a bad
programming language, it is a very good programming language, but it is
designed and optimized for a situation that is increasingly unlikely.

~~~
ddingus
I have known an embedded engineer for probably a decade now.

He uses Forth.

I watched him write a tiny forth kernel in a Kb of RAM or so, then run a
dictionary through it to get a brand new CPU bootstrapped in what could be as
little as a day.

Very impressive. That system got an assembler / disassembler used to make new
system words and other words fast.

Modifying a Forth system, and I say that due to how Forth is really an
environment that becomes capable of the application, depends lot on who made
it and what one can know of their thought process.

What I thought interesting about this guys approach us a fairly pure Forth is
used to bootstrap. Then one that is a lot more comfy gets made for the longer
get term.

Once that stage is reached, and there are good tools, assembler /
disassembler, monitor, word viewer, etc... Forth can be made less of a puzzle.

One can even add other syntax, an interpreter, if desired.

The product is more like a dev system, self hosted and capable.

I find it all compelling, but as you say, much different.

~~~
dwheeler
That's a plausible use case. Question is, if the engineer goes away, how long
would it take to replace him? Languages do not take too long to learn, but
Forth programs are often hard for others to read.

I think most people prefer cross-compilation on small systems for professional
use.

If you are doing it as a hobby, ignore everything I just daid. I see the fun
in it, and applaud it. Enjoy!

~~~
ddingus
Again, depends on how the Forth is done.

Counter question:

Given the obvious savings, why not invest some of that into a second person to
retain a clear advantage?

Do what most people prefer and get results that most people get.

There are other ways to success.

~~~
dwheeler
> There are other ways to success.

Absolutely. I've played with Forth many times, and enjoyed it. But when it
comes to building systems that people _pay_ to develop & maintain, I haven't
found any use cases recently. No doubt there are some, but I suspect they're
much less justifiable today.

~~~
ddingus
Let me expand a bit. Was tired when I wrote the snarky comment.

In a typical corporate environment, yes. Your thoughts ring true.

It is a big world outside that scene, and many playing there can benefit from
Forth. That is the utility. People who grok Forth flat out solve hard problems
like no other.

Tool for that toolbox, essentially.

------
robomartin
Sometimes I feel discussions on HN always go into the weeds with people going
back and forth while losing sight of reality.

I used Forth professionally for well over a decade. I made truckloads of money
with the end products. One of the companies I was involved with, which was
100% Forth, sold for just south of $20 million USD.

Customers don’t go to Home Depot to buy drill bits. They go there to buy
holes.

The world could not care less if solution A was coded in C, solution B in
Forth and solution C using a keypad to enter machine code. All they care about
is the best solution at the best price.

I have always felt that the distinction between experienced and less
experienced engineers is that those with experience focus on what matters
—delivering value to customers— while the less experienced folk needlessly
burn time on theory, languages, code editors and other stuff.

25 years ago I made over $500K with a small 6502 embedded system used to help
control lab equipment during cancer research lab tests. I made this box with a
6502, a couple of UARTS, a 2x16 LCD display and four pushbuttons. The box sold
for $2,000 each. Sold piles of them. The code was written in Forth. The buyers
could not care less. Neither did I frankly. I love Forth, but, at the end of
the day, it’s just another tool.

Customers want holes.

~~~
ggm
_Customers want holes._

At one level I entirely agree. But at another, when it comes to the holes they
drill in the bathroom to hold the toilet roll, and the holes they believe were
drilled in the pickle fork holding the wing onto the 737-max, they feel very
differently about the holes. The first one, They don't much WANT The toilet
paper falling off, but its kinda meh. The second one, being told uncle fester
was given a hand drill from the barn and told to ream 'em good and deep
doesn't fill anyone with joy.

Customers want _the right kind_ of holes.

~~~
robomartin
These kinds of analogies are not intended as precise engineering or business
definitions. They are simple thinking tools used to deliver a point.

If you are in the business of delivering holes for aerospace customers your
focus should be on delivering the kinds of holes they need. At the end of the
day, they still only care about holes. That’s what they are buying.

Most customers using a software-based product could not care less if it was
created using vim and python or toggle switches and machine language. They are
after the solution to a problem; that’s all they care about.

Our customers don’t buy language features, compiler flags, stacks, lists,
dictionaries, classes, variables or functions.

~~~
ggm
Aphorisms have to be tested. "Did you drill these holes to required tolerances
and was the material tested for overheating and delamination" is not that far
off "did you use llvm or gcc and what compile time options did you use"

~~~
robomartin
You missed the point. Forget about holes and think about what customers are
looking for. The answer is a solution to a problem. Nobody buys a car because
they are after one with body panels made with hydro-forming rather than a
sequential press. They are after a vehicle that addresses the transportation
needs they might have. They could not care less if it was designed using
SolidWorks, Fusion 360 or Siemens NX.

They are looking for a hole.

------
mark_l_watson
I experimented with Forth with my Apple II (I had serial number 71, one of the
early ones!). I liked the interactive bottom up REPL coding style, but I found
it difficult to read code that I had written the week before.

After playing with Forth, I bought Pegasus Lisp for the Apple II and for me
Lisp hits a sweet spot of concision, bottom up REPL development, and
readability.

That said, I can see why some people like Forth if they are very experienced
with it and can get things done quickly.

~~~
timbit42
Reading the book 'Thinking Forth' will help you write legible code.

~~~
carapace
I second this, IMO to a first approximation reading that book is the way to
understand programming in Forth.

[http://thinking-forth.sourceforge.net/](http://thinking-
forth.sourceforge.net/)

------
LessDmesg
The thing that's wrong with Forth is it promotes eschewing verbal
identification of variables for the sake of positional. This is promoted as
good mental exercise, but is just bad language design. As Rich Hickey said, we
humans prefer to identify things in terms of keywords, not positions. For any
method with more than a couple parameters, kwargs are more convenient than
positional arguments or, worse, implicit args on the stack. This is why
concatenative languages are doomed to be just a forgotten cul-de-sac off the
highway of the history of programming languages.

~~~
ken
I frequently see arguments of the form "X is good; Y doesn't have X; therefore
all typeof(Y) are doomed". I don't understand. Didn't you just give a
criterion for success? Why can't we make a new Y2 that has X?

In this case, it doesn't even seem difficult. I've seen multiple stack-based
systems that allow items labels. They don't use them for arg-passing (AFAIR),
but I don't see why they couldn't.

I'm not even convinced that positional arguments are fatal for language
design. _Most_ popular languages today lack named arguments. They're usually
only named on the callee side. I'm sure we've all run across a C function call
that looked like foo(a, b, c, d, e, f, g, h), and cursed the author under our
breath, and then counted out to the argument number we wanted to change.

Languages succeed or fail for many reasons, but I don't think I've ever seen
"calling convention" be the deciding factor (no pun intended).

In the more general sense of concatenative (not necessarily stack-based)
languages, Unix pipelines are a common example, and they don't seem to be
doomed.

------
ggm
When we did forth(like) languages in computer science kindy (back in the 70s
and 80s) the lecturers used to smirk because real languages like ADA took 20
passes and built huge models and were therefore more betterer and gooderer for
some value of complex. Having the thing function as a stack machine in
Reverse-Polish meant you didn't have to parse anything, it was basically
already there for you sitting on the top of the stack (dock of the bay)
watching the PC come in.

I think the smirk was misplaced. What they needed to do was talk about this in
comparative language classes and about why people drive to small(er)
languages, and fitness for purpose, and what kind(s) of things happen when you
force people to think this way, vs why you drive to COBOL and what you force
people to think and do, when you go there. They're all turing-complete.
They're all capable of expressing the same things, at some differing level of
complexity and cost, in some variant of machinery.

~~~
OneWingedShark
If it were up to me to design curricula for CS, I'd do the entire thing in
Ada, with the exceptions of "Data-Structures & Algorithms" being in Lisp and
"Machine Architecture" in Forth — both of these classes would have a
"Compilers & Interpreters" prerequisite where they would be provided the
specification-files for Forth and Lisp interpreters/compilers which the
students would implement, and _that_ is what they would use in the
aforementioned classes — not only would having the curriculum in these less-
popular languages help emphasize that the important part is the underlying-
theory (rather than hyped-up language-of-the-month), but making its
prerequisites actually matter and introducing an element of software-
maintenance would do a lot to produce good graduates.

------
co_dh
That is an unfair comparison. Forth is designed to run on metal, with no os,
no stdlibc, no vector. Can any of other language do that?

In fact, by just adding first class function, retro forth makes the code way
easier to read.

~~~
davidgay
> That is an unfair comparison. Forth is designed to run on metal, with no os,
> no stdlibc, no vector. Can any of other language do that?

Not much of a stretch with C, really - there's a reason its used to write
operating systems ;) (the standard library is mostly about OS interaction
which is irrelevant in the bare metal/no OS context)

On some systems, C requires a minimal library for compiler-emitted intrinsics
(e.g., for 16/32-bit multiplies on 8-bit systems, for floating point, etc).

~~~
madhadron
I think you misunderstand. When the parent says "designed to run on metal"
they don't mean "designed to be cross compiled to produce binaries that run on
metal", they mean "the compiler, editor, etc. are all running on metal."

~~~
mikekchar
One of the very first things I thought of when I heard about WASM is, "Oh.. It
would be _so_ fun to build FORTH on that". I never got around to it (yet) and
from a quick search, there are already a ton of implementations. But I think
this is one of the things about FORTH: it's not just that you can run it on
the metal. It's that you can _easily_ build a FORTH environment for pretty
much any metal you can think of. Bootstrapping from absolutely nothing to a
very productive environment is really an empowering feeling. I always thought
it was a shame that there are so many people who have made a Lisp, but so few
that have made a FORTH. I kind of feel like both of these tasks should be
required material in school... Though I only have nebulous feelings about why
it is valuable... Not sure I could explain it to someone who hasn't done it
already.

~~~
colomon
I haven't done any serious Forth programming in 30+ years, but every time I
see a limited resources programming environment, I immediately get the urge to
implement Forth on it. "This new game is going to include a DCPU-16 virtual
computer you have to program? Great, all I need to do is implement Forth on
it..."

Luckily for my already very limited spare time, so far I've managed to resist
this urge.

------
lebuffon
It's an assembly language for a 2-stack VM. It's never going to be easy but it
is hella-fun to play with.

------
samatman
Ran across this post years before I started playing with Forth (recommend the
whole blog, he's a great writer).

Later I was going through a Forth phase and came back to it to tackle the
puzzle it poses, here's my take on it:

[https://mnemnion.github.io/blog/2014/01/12/those-dadgum-
adde...](https://mnemnion.github.io/blog/2014/01/12/those-dadgum-adders/)

I hope this illustrates the raw power of the Forth paradigm a bit better than
the OP.

------
imglorp
I was following along until the author stopped explaining new syntax.

"over", according to forth.com, copies second item to top... ( n1 n2 — n1 n2
n1 )

But I get lost with >r, r>, r@, and !

~~~
loa_in_
They move top cell from stack to return stack or vice versa. r@ and r! are
effectively equivalent to r> @ and r> ! ... or was it r> @ >r and r> ! >r

------
kragen
James Hague has a lot more Forth experience than I do. But I would initially
write this function something like this:

    
    
        variable v1  variable v2  variable v3
        : vadd v3 ! v2 ! v1 !
          3 0 do  v1 @ i cells + @  v2 @ i cells + @  +  v3 @ i cells + !  loop ;
    

Or, alternatively:

    
    
        0 value v1  0 value v2  0 value v3
        : vvadd to v3 to v2 to v1
          3 0 do  v1 i cells + @  v2 i cells + @  +  v3 i cells + !  loop ;
    

I mean, yes, you _can_ make it a puzzle. But you don't _have_ to. These
versions will be slower than Hague's first working version and probably the
second too, but all of Hague's versions are slower (with any Forth compiler
I've used) than what GCC will give you for the C version. And what GCC will
give you for the C version, even if it improbably manages to vectorize, is
also a lot slower than what you'll get if you do your vec3 math on your GPU.
So maybe when it comes time to rewrite the naïve Forth version above, because
it _is_ slow, you should just code an SSE assembly routine and skip the manual
loop unrolling at the Forth level, or restructure the whole system to do the
vector math on the GPU.

Or maybe not. James Hague is a smart guy and he's shipped a lot of code, in
assembly, C, and Forth. But I'd like to understand where my reasoning is going
wrong, because I can't see it.

My perspective on Forth is that it's the thinnest possible layer on top of raw
machine code that gives you all the fundamental mechanisms for improving your
leverage. You need structured control flow, so it has IF ELSE THEN, DO LOOP,
BEGIN WHILE REPEAT, and a couple of others. You need expressions, so it has an
operand stack. You need procedural abstraction, so it has a return stack,
which also serves to store loop counters. You need labels both to make your
code readable and so that you can patch your code without overwriting parts of
it with JMP instructions to wherever you have free space to put the patch
code, so it has words. You need metaprogramming, so it has IMMEDIATE. You need
run-time polymorphic procedure dispatch, so it has ', EXECUTE, DEFER, IS, and
CREATE DOES>. You need namespace management, so new definitions hide old
definitions with the same name, and you also have wordlists.

The problem with all these wonderful mechanisms is that they can become an
attractive nuisance, as you futz around trying to find the perfect way to
express your intent in the smallest, clearest amount of code, navigating the
tradeoffs imposed by the sparse toolset. But you don't have to do it that way.
You can just write simple, straightforward code that gets the job done with no
fuss, and move on to the next problem. Forth lets you do that, too.

That said, I find it easier to get my code working in assembly language than
in Forth, and I don't know if that's because I don't know Forth well enough,
because Forth is inherently less practical than assembly language, or just
because Forth somehow fails to fit my brain. My guess is that I fall for the
attractive nuisances too often and waste my time with unproductive futzing.
And that's what this blog post looks like to me.

~~~
dwheeler
The problem with using global variables (like this) is that it's not thread-
safe. Many Forth systems supported multi-threading (each thread gets its own
pair of stacks), even on resource-constrained systems. If you're going to have
names like this, named parameters AKA local variables are a better solution.

~~~
kragen
Those aren't global variables; they're just variables. They _are_ statically
allocated, which you would think would lead to the problems you describe. But
multithreaded Forth systems traditionally use cooperative rather than
preemptive multithreading, and since VADD doesn't invoke any words that can
yield to another thread, it can be assured that no other instances of VADD
will mess with its variables while it's running. So that problem doesn't
actually exist unless you're using something like GForth's experimental
pthreads interface. In that case you could define the variables as "user
variables" (TLS, in more widespread terminology) as well as the possibility of
making them stack-allocated variables as you suggest.

I like stack-allocated variables, and they'd be the obviously correct solution
in a language like C; but ANS Forth doesn't have them (oh, I see they've been
added in Forth-2012; thank you!), they make it harder to factor words, and
some of the other problems they solve in Algol-family and Lisp-family
languages have other solutions in Forth, so the case for them is not as
strong.

Also, traditionally, multithreaded Forth systems were multiuser; each task had
its own dictionary. So a fourth way to avoid the problem (in addition to
procedure-local variables, cooperative multitasking, and user variables) is to
load the definitions above after spawning the potentially interfering task
rather than before.

------
stewbrew
"Better than Sudoku? Yes."

I would have went with riding a 5 EUR motorized kids skateboard without any
protection and never looking back. But that's a good analogy too.

