Forth: The programming language that writes itself

119 pointsposted 6 hours ago
by suioir

38 Comments

rpcope1

3 hours ago

If you like Forth, but find it challenging to build real stuff with, Factor (https://factorcode.org/) is most or all of the good stuff about Forth designed in a way that's much easier to do things with. It was designed by Slava Pestov (who I think had a big hand in Swift), and honestly it's a lot of fun to build webapps and other programs with, and much less brutal to read than Forth can be.

sriku

an hour ago

I've had a soft spot for Forth and am toying with a silly Forth-like interpreter for web programming ... if not for actual use, at least for some fun time. One concept it adds is the notion of a "current selection" which can define the available vocabulary to use and is used to select and work with DOM elements. Just experimenting.

https://github.com/srikumarks/pjs

Edit: As a kid, I disliked BASIC as a language though it let me do fun stuff. So I made an interpreter in BASIC for a language I'd like and it turned out Forth-like (and I didn't know about Forth at that time). I guess I'm still that kid some 35 years later.

js8

32 minutes ago

I used to be a fan of these languages like Lisp and Forth and Joy (and Factor and Haskell), but then I found that what I a really long for is just (untyped) lambda calculus (as a universal language). (Combinatory logic is just a similar representation of lambda calculus, but the differences go away quickly once you start abstracting stuff.)

I think expressing semantics of all (common) programming languages in lambda calculus would give us a solid foundation for automated program translation. And we should aim for that, the babel tower of languages doesn't really help anyone.

The current issue I have is with type theory. So I am trying to embed notion of types directly into the lambda terms, so they would sort of "automatically typecheck" when composed. The crucial in this, in my opinion, are lambda terms that do not use lambda abstraction in their body, because you can think of these terms as a kind of mini-DSLs that have yet to be interpreted.

Anyway, once we can translate calculus of constructions (and other common formal logics) into untyped lambda calculus, it will also help us doing automated theorem proving. It must be theoretically possible, but to my knowledge nobody has really done this sort of hardcore formalization.

procaryote

21 minutes ago

Why specifically untyped?

js8

a minute ago

Because it is the simplest thing we have, and has a pretty straightforward self-interpreter.

It feels like you need a lot more metamathematics to deal with typed lambda calculus than with untyped one, and types are something vague that comes without a justification.

Anyway, the idea is, if you have a language, you can think of its source code as a giant lambda term, where you have all lambdas upfront and only composition in the body. A tree of symbols to be composed, essentially. And then to interpret this source code in a language, you supply definitions of the language's primitives as arguments to the source code term.

Now if your language is typed, the primitives need to be chosen in such a way, so that the interpreted term (the source code applied to language primitives) fails to normalize if the program is not typed correctly.

You can then have a correspondence between the primitives of the typed language that typecheck and simpler set of primitives of the same language used purely for computation, used under the assumption that the program typechecks. This correspondence "defines" the typing mechanism of your language (in untyped lambda terms).

nikolay

4 hours ago

Many people glorify the simplicity of Lisp as an interpreter, but Forth is similar and underappreciated. Sadly, the only code I've written in Forth is... PostScript. Yeah, PostScript is a dialect of Forth. As a child, I really was amused by the demo of GraFORTH on Apple ][, which included 3D wireframe animations, which at the time were magical.

lutusp

an hour ago

> As a child, I really was amused by the demo of GraFORTH on Apple ][, which included 3D wireframe animations, which at the time were magical.

I originally wrote GraFORTH (https://archive.org/details/a2_GraFORTH_1981_Lutus_Paul) to escape the slow world of integer BASIC on my first computer (an Apple II). Because it relied on large blocks of assembly code to produce nice graphics, it perhaps misled people about what Forth could do on its own.

Later I wrote a variation I called TransFORTH (https://mirrors.apple2.org.za/ftp.apple.asimov.net/documenta...) that supported floating-point. I intended to combine GraFORTH and TransFORTH, but my computer didn't have enough RAM.

Innocent times, different world, before the personal computing tail began wagging the dog.

behnamoh

4 hours ago

Why is it that languages like this don't scale? It's not the first time I see a powerful language that got forgotten. Other examples include SmallTalk and Common Lisp (tiny community).

It is because some languages are "too powerful"? What does that say about our industry? That we're still not that advanced of a specie to be able to handle the full power of such languages?

I say that because it seems languages that are "dumbed down" seem to absolutely dominate our world (Python, Ruby, JS, etc.)

procaryote

10 minutes ago

Powerful languages invites people to do needlessly complex things. Needlessly complex things are harder to understand. Harder to understand is worse.

Code that matters is usually read and extended many more times than it is written, over time by different people, so being straightforward beats most other things in practice

tarkin2

4 hours ago

One simpler explanation: in forth you are forced to keep the stack, and modifications to the stack, in your short term memory, albeit only really three numbers in most cases. Whereas with C et al you simply look down the page at the variables, far less taxing on your short term memory.

Well-written and designed high-level forth words often transcend that and tend to be, quite literally, readable however, in a way that is incredibly rare to see in C et al. Of course the argument is that other programmers shouldn't be expected to see the problem in the way the original problem solver did.

rpcope1

3 hours ago

This is probably why you see things like locals get used a lot as modern Forth programs grow. It doesn't have to be brutal early days Chuck Moore genius programs, but I guess you start getting away from the original ethos.

zovirl

39 minutes ago

I was lucky, early in my career, to work at a place which used a lot of Perl and to read Damian Conway’s book, Object Oriented Perl. It was an amazing, mind-expanding book for me. It was filled with examples of different approaches to object-oriented programming, more than I ever dreamt existed, and it showed how to implement them all in Perl.

So much power! And right in line with Perl’s mantra, “there’s more than one way to do it.”

Unfortunately, our codebase contained more than one way of doing it. Different parts of the code used different, incompatible object systems. It was a lot of extra work to learn them all and make them work with each other.

It was a relief to later move to a language which only supported a single flavor of object-oriented programming.

rpcope1

3 hours ago

I worked at a place that had a big Forth codebase that was doing something mission critical. It was really neat and cool once you finally got it, and probably hundreds or maybe thousands of people had touched it, worked on it and learned it, but the ramp was pretty brutal for your average developer and thus someone decided it would be better to build the same thing over with a shitty almost-C-but-not-quite interpreted language. It certainly made it easier for more people to understand and build, even if the solution was less elegant.

kragen

3 hours ago

That sounds interesting! Do you have any tips for us on how to use Forth effectively? What was the codebase?

saghm

3 hours ago

I don't think "power" is really that helpful a metric in determining how useful a programming language is. If you think of programming from the standpoint of trying to specify the program you want out of all of the possibly programs you could write, one of the most helpful things a programming language can do is eliminate programs that you don't want by making them impossible to write. From that standpoint, constraints are a feature, not a drawback.

zovirl

an hour ago

And at the extremes, too much power makes a tool less useful. I don’t drive an F1 car to work, I don’t plant tulips with an excavator, I don’t use a sledgehammer when hanging a picture. Those tools are all too powerful for the job.

pjmlp

42 minutes ago

Sadly our industry carries mostly about brick layers and usually tries to go into technologies that make it easier to deal with employees like replaceable servants at low wage prices.

The large scale salaries SV style isn't something that you will find all over the globe, in many countries the pay is similar across all office workers, regardless if they are working with Git, or Office.

vlovich123

27 minutes ago

That argument implies that you would actually see these languages in communities with large SV style salaries which isn’t the case.

It turns out that “brick layer” languages are also easier to understand not just for the next person taking over but yourself after a few months. That’s valuable even to yourself unless you value your time at 0.

pjmlp

10 minutes ago

Why? The less the VCs have to spend with employees the better.

See the famous quote about Go's target audience, or 2000's Java being a blue colour job language.

Not only do languages like Lisp, Forth, Smalltalk require a people to actually get them, a bit like the meme with burritos in Haskell, they suffered from bad decisions from companies pushing them.

Lisp suffered with Xerox PARC, Symbolics and TI losing against UNIX workstations, followed by the first AI Winter, which also took Japan's 5th project with Prolog alongside with it.

Smalltalk was getting alright outside Xerox PARC, with big name backers like IBM, where it had a major role on OS/2, similar to .NET on Windows, until Java came out, and IBM decided to pivot all their Smalltalk efforts into Java, Eclipse has roots on Visual Age for Smalltalk.

socalgal2

an hour ago

I'm not entirely sure this is different from other languages but I believe a common complaint about lisp is every solution ends up writing a DSL for that solution, making it hard to understand for anyone else. So it's a super power if you're a small team and especially if you're a team of 1. But if you're a large team it doesn't scale.

mcdonje

4 hours ago

It kinda happened with markup languages. HTML, SVG, and some other domain specific markup languages are all XML, which is a subset of SGML.

The thing there is those DSLs have their own specs.

Coding is a social activity. Reading code is hard. When there are multiple ways of doing things, it's extra hard. People want to have relatively standardized ways of doing things so they can share code and reason about it easier.

If there's a lisp or racket or a forth that's defined as a DSL, it might take off if it's standardized and it's the best solution for the domain.

gldrk

3 hours ago

HTML uses a ton of SGML features not part of XML (sometimes erroneously though to be non-standard ‘tag soup’, not to mention self-closing tags). You need either a specialized parser or an SGML processor + DTD.

shawn_w

an hour ago

Wasn't HTML4 the last one defined as a SGML DTD? 5 and on is its own beast.

(rip XHTML)

lukan

4 hours ago

What I heard is with Forth, basically no 2 environments are alike, but highly customized, meaning every forth programmer creates his own language in the end for his custom needs.

So collaborating is a bit hard like this. The only serious forth programmer that I know, lives alone in the woods doing his things.

So from a aesthetic point of view, I really like the language, but for getting things done, especially in a collaborative way?

But who knows, maybe someone will write the right tools for that to change?

coliveira

an hour ago

This is not a real issue, because the same thing can be said about C. No two C projects are the same, each has its own set of libraries, macros, types, etc.

I think the main problem is that Forth systems don't have a standard way of creating interfaces like C and other languages have. So the diversity of environments becomes a big issue because it's difficult to combine libraries from different sources.

kragen

3 hours ago

I think those other languages have real advantages you aren't seeing.

—·—

The other day akkartik wrote an implementation of the program Knuth used to introduce literate programming to the CACM readers: https://basiclang.solarpunk.au/d/7-don-knuths-original-liter...

It just tells you the top N words by frequency in its input (default N=100) with words of the same frequency ordered alphabetically and all words converted to lowercase. Knuth's version was about 7 pages of Pascal, maybe 3 pages without comments. It took akkartik 50 lines of idiomatic, simple Lua. I tried doing it in Perl; it was 6 lines, or 13 without relying on any of the questionable Perl shorthands. Idiomatic and readable Perl would be somewhere in between.

    #!/usr/bin/perl -w
    use strict;

    my $n = @ARGV > 1 ? pop @ARGV : 100;
    my %freq;

    while (my $line = <>) {
      for my $w ($line =~ /(\w+)/g) {
        $freq{(lc $w)}++;
      }
    }

    for my $w (sort { $freq{$b} <=> $freq{$a} || $a cmp $b } keys %freq) {
      print "$w\t$freq{$w}\n";
      last unless --$n;
    }
I think Python, Ruby, or JS would be about the same.

Then I tried writing a Common Lisp version. Opening a file, iterating over lines, hashing words and getting 0 as default, and sorting are all reasonably easy in CL, but splitting a line into words is a whole project on its own. And getting a command-line argument requires implementation-specific facilities that aren't standardized by CL! At least string-downcase exists. It was a lark, so I didn't finish.

(In Forth you'd almost have to write something equivalent to Knuth's Pascal, because it doesn't come with even hash tables and case conversion.)

My experience with Smalltalk is more limited but similar. You can do anything you want in it, it's super flexible, the tooling is great, but almost everything requires you to just write quite a bit more code than you would in Perl, Python, Ruby, JS, etc. And that means you have more bugs, so it takes you longer. And it doesn't really want to talk to the rest of the world—you can forget about calling a Squeak method from the Unix command line.

Smalltalk and CL have native code compilers available, which ought to be a performance advantage over things like Perl. Often enough, though, it's not. Part of the problem is that their compilers don't produce highly performant code, but they certainly ought to beat a dumb bytecode interpreter, right? Well, maybe not if the program's hot loop is inside a regular expression match or Numpy array operation.

And a decent native code compiler (GCC, HotSpot, LuaJIT, the Golang compilers, even ocamlopt) will beat any CL or Smalltalk compiler I have tried by a large margin. This is a shame because a lot of the extra hassle in Smalltalk and CL seems to be aimed at efficiency.

(Scheme might actually deliver the hoped-for efficiency in the form of Chez, but not Chicken. But Chicken can build executables and easily call C. Still, you'd need more code to solve this problem in Scheme than in Lua, much less Ruby.)

—·—

One of the key design principles of the WWW was the "principle of least power", which says that you should do each job with the least expressive language that you can. So the URL is a very stupid language, just some literal character strings glued together with delimiters. HTML is slightly less stupid, but you still can't program in it; you can only mark up documents. HTTP messages are similarly unexpressive. As much as possible of the Web is built out of these very limited languages, with only small parts being written in programming languages, where these limited DSLs can't do the job.

Lisp, Smalltalk, and Forth people tend to think this is a bad thing, because it makes some things—important things—unnecessarily hard to write. Alan Kay has frequently deplored the WWW being built this way. He would have made it out of mobile code, not dead text files with markup.

But the limited expressivity of these formats makes them easier to read and to edit.

I have two speech synthesis programs, eSpeak and Festival. Festival is written in Scheme, a wonderful, liberating, highly expressive language. eSpeak is in C++, which is a terrible language, so as much as possible of its functionality is in dumb data files that list pronunciations for particular letter sequences or entire words and whatnot. Festival does all of this configuration in Scheme files, and consequently I have no idea where to start. Fixing problems in eSpeak is easy, as long as they aren't in the C++ core; fixing problems in Festival is, so far, beyond my abilities.

(I'm not an expert in Scheme, but I don't think that's the problem—I mean, my Scheme is good enough that I wrote a compiler in it that implements enough of Scheme to compile itself.)

—·—

SQL is, or until recently was, non-Turing-complete, but expressive enough that 6 lines of SQL can often replace a page or three of straightforward procedural code—much like Perl in the example above, but more readable rather than less.

Similarly, HTML (or JSX) is often many times smaller than the code to produce the same layout with, say, GTK. And when it goes wrong, you can inspect the CSS rules applying to your DOM elements in a way that relies on them being sort of dumb, passive data. It makes them much more tractable in practice than Turing-complete layout systems like LaTeX and Qt3.

—·—

Perl and Forth both have some readability problems, but I think their main difficulty is that they are too error-prone. Forth, aside from being as typeless as conventional assembly, is one of the few languages where you can accidentally pass a parameter to the wrong call.

This sort of rhymes with what I was saying in 02001 in https://paulgraham.com/redund.html, that often we intentionally include redundancy in our expressions of programs to make them less error-prone, or to make the errors easily detectable.

codys

2 hours ago

The article in CACM that presents Knuth's solution [1] also includes some criticism of Knuth's approach, and provides an alternate that uses a shell pipeline:

    tr -cs A-Za-z $'\n' |
    tr A-Z a-z |
    sort |
    uniq -c |
    sort -rn |
    sed ${1}q
(I converted a newline to `$'\n'` for readability, but the original pipeline from the article works fine on a current MacOS system)

1: https://dl.acm.org/doi/pdf/10.1145/5948.315654

mek6800d2

an hour ago

With great respect to Doug McIlroy (in the CACM article), the shell pipeline has a serious problem that Knuth's Pascal program doesn't have. (I'm assuming Knuth's program is written in standard Pascal.) You could have compiled and run Knuth's program on an IBM PC XT running MS-DOS; indeed on any computer having a standard Pascal compiler. Not so the shell pipeline, where you must be running under an operating system with pipes and 4 additional programs: tr, sort, uniq, and sed.

McIlroy also discusses how a program "built for the ages" should have "a large factor of safety". McIlroy was worried about how Knuth's program would scale up to larger bodies of text. Also, Bentley's/McIlroy's critique was published in 1986, which I think was well before there was a major look into Unix tools and their susceptibility to buffer overruns, etc. In 1986, could people have determined the limits of tr, sort, uniq, sed, and pipes--both individually and collectively--when handling large bodies of text? With a lot of effort, yes, but if there was a problem, Knuth at least only had one program to look at. With the shell pipeline, one would have to examine the 4 programs plus the shell's implementation of pipes.

(I'm not defending Pascal and Knuth, Bentley, and McIlroy are always worth reading on any topic -- thanks for posting the link!)

Bringing this back to Forth, Bernd Paysan, who needs no introduction to the people in the Forth community, wrote "A Web-Server in Forth", https://bernd-paysan.de/httpd-en.html . It only took him a few hours, but in fairness to us mortals, it's an HTTP request processor that reads a single HTTP request from stdin, processes it, and writes it output to stdout. In other words, it's not really a full web server because it depends on an operating system with an inetd daemon for all the networking. As with McIlroy's shell pipeline, there is a lot of heavy lifting done by operating system tools. (Paysan's article is highly recommended for people learning Forth, like me when I read it back in the 2000s.)

JonChesterfield

4 hours ago

They scale extremely effectively to large problems solved by a team size of one, maybe two.

The story goes that changing the language to fit how you're thinking about the problem is obstructive the rest of the people thinking about the same problem.

I'm pretty sure this story is nonsense. Popular though.

elitepleb

3 hours ago

frankly it's a miracle any of them scaled at all, such popularity mostly comes down to an arbitrary choice made decades ago by a lucky vendor instead of some grand overarching design

shevy-java

2 hours ago

Back in 2004 or so - ancient days now - I remember an elderly programmer on #gobolinux (freenode IRC back in the days) who kept on praising Forth. I never understood why, but he liked Forth a lot.

Now - that in itself doesn't mean a whole lot, as it is just anecdotal, but people who are very passionate about programming languages are quite rare. I've not seen something like that happen with any other language (excluding also another guy on #gobolinux who liked Haskell). I did not see anyone praise, say, PHP, perl, JavaScript etc....

Some languages people don't like to talk about much. Forth though was different in that regard. I never got into it; I feel it has outlived the modern era like many other languages, but that guy who kept on talking about it I still remember. His website also was built in Forth and it was oddly enough kind of an "interactive" website (perhaps he also used JavaScript, I forgot, but I seem to remember he said most or all of it was implemented in Forth - turtles all down the way).

tombert

3 hours ago

Forth has been a peripheral fascination of mine for about a decade, just because it seems to do well at nearly every level of the software stack. Like a part of me wants to build a kernel with it, or make a web server, or anything in between.

I've never actually done any Forth, though, just because it's a bit arcane compared to the C-inspired stuff that took over.

kragen

4 hours ago

This is, I think, the best overview of Forth, and computing as a whole, that I've ever seen.

rtpg

an hour ago

it mentions sometimes not naming things as great, but... what does naming intermediate values in forth look like? Is there even a naming scope that would allow for me to give values names in case I don't want to get entirely lost in the sauce?

fennec-posix

2 hours ago

A long read but one that's quite incredible. Has definitely helped my understanding of computing get closer to the metal so to speak.

dlcarrier

3 hours ago

That is assuming that you, with German grammar, write.

DavidSJ

3 hours ago

I believe, that you that sumes as mean.

nakamoto_damacy

2 hours ago

I wish "Simple Made Easy," by Rich Hickey, could be applied here. Forth is simple but not easy. If there is something as simple as Forth but also accessible to mere mortals (aka easy) then I'd like to know what it is (I don't consider Clojure itself as a language to be simple in this sense).