Comment by megameter
5 years ago
If I had to put my finger on why Forth is hard for most programmers, it's like this: the structured program theorem suggests using sequence, selection, and iteration to control program logic. Assembly code on hardware architectures will assign all meaning sequence-relative, late-binding the selection and iteration. Forth doubles down on this sequence-first approach through a more versatile assignment mode(the stack) while only minimally accommodating the other two. That makes it easy to implement, while not explicitly addressing expressability.
Forth written "flat" with shallow data stack usage is assembly by another name, a wrapper for load-and-store; Forth that does everything with intricate stack manipulation is a source of endless puzzles since it quickly goes write-only.
But, like any good language with meta expression capabilities, you can work your way up towards complex constructs in Forth, and write words that enforce whatever conceptual boundaries are needed and thus check your work and use the system as a compiler. That's what breaks Forth away from being a simple macro-assembler. But you have to write it in that direction, and design the system that makes sense for the task from the very beginning. That falls into an unacceptable trade-off really easily in our current world, where the majority of developers are relatively inexperienced consumers of innumerable dependencies.
For me, the main problem with forth is a lack of names -- most languages (functional or imperative or even declarative) assign names to things -- things like function parameters, temporary values and so on.
Even Prolog, which is as far from traditional structural program as one can go, usually has descriptive names for unbound variables.
Compared to this, Forth is very name-terse. You get "function names" at best, and nothing else. This really makes programs much harder to understand, as it requires one to remember much more things while reading the code.
The ANS Forth standard supports named local variables. Unfortunately Forth dialects vary quite a bit in their implementation and prefered use of local variables, and the semantics of local variables are a bit hairy.
Cf. https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/ANS...
Note that Forth also supports locals. These will consume and remove N members from the stack so you can summon them as needed prior to calling the words.
But as someone that really got into Forth this year, I can assure that it does get better once you get more familiar with the language. I used to write commenting the stack effects on each line and now I barely need them as I write words in one sitting without that much effort.
Other developers are doing tacit programming in J or Haskell, pipe forward operators in F# or OCaml and threading macros on Lisp dialects and they seem to do fine.
It's been a long time since I did anything substantive with Forth, but, as I recall, the big problem here is that most Forth guides get so excited to show you how much rope the language gives you that they forget to teach you how not to hang yourself with it. So you're kind of left to figure out all the little idioms and best practices for stack management all on your own.
1 reply →
What does a local variable mean in the context of Forth? Data guaranteed to be in registers, like the in-CPU stack of 8008?
The term you are looking for is "tacit" or "point-free" programming. Array languages are another example.
You're right in the sense that it's not in style, but there are both named "locals" and "arguments" in ANS Forth IIRC.
> But, like any good language with meta expression capabilities, you can work your way up towards complex constructs in Forth, and write words that enforce whatever conceptual boundaries are needed and thus check your work and use the system as a compiler. That's what breaks Forth away from being a simple macro-assembler. But you have to write it in that direction, and design the system that makes sense for the task from the very beginning. That falls into an unacceptable trade-off really easily in our current world, where the majority of developers are relatively inexperienced consumers of innumerable dependencies.
Well expressed, I often think of the stack as the syntax of the language, not the runtime implementation, and it is quite difficult to hire for this skill without spending a lot of money.
Interesting perspective. For anyone else who wasn't familiar with this usage of "selection": https://en.wikipedia.org/wiki/Structured_program_theorem
> Forth is hard for most programmers
It's pretty hard to make that judgment. I'd guess at least 99% of programmers have never used Forth.
> That falls into an unacceptable trade-off really easily in our current world, where the majority of developers are relatively inexperienced consumers of innumerable dependencies.
aka, this is hard to do, and a difficult mental model to learn. It's the same kind of thing with LISP'y languages and functional languages (not the same model, but the same level of difficulty).
That's just about right. To put it more concisely: Forth only works well when used properly: as a very easy to extend DSL.