Forth is super cool for embedded work. The normal dev cycle of build, burn, not work, tweak, build, burn, repeat is quite slow and annoying. It was kind of revolutionary for me to discover Mecrisp[0], which demonstrates how can provide a (fast!) language that also provides a friggin' repl into your hardware.
The ##forth IRC channel on Libera is quite active. Would recommend popping in for anyone interested. The two projects that got me interested in Forth are
Explanation and motivation for the What and Why of Forth and its implementation. Well, actually, it's actually an implementation in x86 assembly, but the comments are a wonderful exposition and intro into Forth.
Implementation of Forth in x86-64 opcodes. It's a hand-written ELF that implements a Forth. It's simplicity is absolutely beautiful.
SmithForth is what pushed me over the edge to really start learning x86 assembly and Forth. I started by hand-decompiling the SmithForth binary, which was quite an adventure on its own.
you probably can't use amd64 in embedded work, or even i386 these days, but i think 'a friggin' repl into your hardware' is a good explanation of what's appealing about forth
I think I posted an almost identical reply to you just a few days ago, but I'm presuming they linked the x86 examples because most people can actually try them without needing said embedded hardware
Oh no sorry, I didn't mean it as a critique, haha! I just thought this was a funny deja vu. It was this little comment exchange in a post linking a free x86-64 assembly book:
k: it probably teaches more than everything i know about amd64 assembly, except the most important thing, which is that arm assembly is much better
vdZ: I'm sure many architectures are nicer than amd64, but that's what the CPU in my laptop uses, as well as my Steam Deck. If I want to get into low-level hacking it's easiest to start with the hardware I have, no?
k: yup, no use looking for your keys in the rose garden if you know you dropped them in the sewer
i guess it's worth mentioning with qemu-user that you can totally run arm code on amd64 hardware, though sometimes things work that shouldn't, so it's not an ideal testing environment. i did a demo of this last year in https://asciinema.org/a/622461
i think the particular thing i ran into was that supposedly actual arms require an instruction cache flush before executing newly jit-compiled instructions and qemu didn't, so not exactly opcodes
oh also i think qemu was supporting unaligned fetches (trapping on them on intel would be very expensive and not useful for running working programs), so i didn't notice that data in my data segment had gotten misaligned until i got a bus error on an actual arm. i don't think i saw an actual failure from the cache flushing thing
Not sure what you mean by this. There are Atom-like boards, and Core i7 boards with BSPs and everything in between. Bringing up a custom system isn't that hard either.
this is very different from 30 years ago when pc104 boards were all over the place. pc104 is not completely forgotten but pc104 and vmebus are pretty well eclipsed by raspberry pi, esp32, arduino, gumstix, and plain stm32 and avr8 designs, increasingly even in non-hobbyist designs. can and i2c have displaced isa/eisa and sometimes even rs422
so if you are doing embedded work you probably will not be able to use amd64 or i386 and thus jonesforth or smithforth or stoneknifeforth. but the principles do apply
Someone linked to me FreeForth, a Forth that doesn't have any compile / interpret distinction. Everything is compiled, and if run interactively, words are first compiled into anonymous "function" and then run, which has a lot of benefits; such as allowing compile-only words at the REPL.
I haven't heard anyone talk about or recreate this variant, which to me seems a very interesting evolution of the original Forth. Nor has anyone tried to recreate it in something more readable than a thick assembly implementation that's trying to be a little too smart for its own good.
sad to see he's running microsoft windows, which i am sure is not running on a ga144, and an iphone
but it's wonderful to see he's still alive and still living in the mountain cabin and still working on colorforth
this is dispiriting:
> forth is a lovely language, but you have to be able to interface with your hardware. i've been doing that for 50 years and i'm tired of it. they keep changing the rules faster than i can learn what they are
i really respect that the most important purpose for his clock app is to tell him when the sky will turn beautiful golden colors
i wonder if it would be more informative for him to stream some live coding rather than just present finished programs, because i feel that the essence of forth is the interactive experience of using it
a surprisingly hardcore tidbit is (53'40") that colorforth context switches between apps by recompiling the new app from source. otoh i guess that's what php and streamlit do too
I can understand, though. For instance, with new security rules like x^w page protection, it becomes much harder to write a self-modifying Forth on MacOS - I gave up a jonesforth port because of this. I'd continue if I had a way to turn off these protections, but this seems hard-baked into the new M123/OS versions now. It's maybe easier for JIT compilers that don't actually modify the core compiler itself (something FORTH definitely does, and which makes up a big part of its allure. It's the ultimate foot-gun).
As a side node, I think that since the FORTH community seems to so strongly advocating for small stand-alone systems that are bootstrapable, it's annoying that there don't seem to be forth based IP stacks out there. Most forths have a C-based layer for networking, which feels a bit like cheating to me. I think there should be an open source forth-based network stack out there. This kinda doesn't give weight to the argument that "Forth is all you need".
sorry to hear you gave up; how do things like luajit and node handle the x^w thing? also, i thought jonesforth was entirely interpretive; i didn't think it generated new machine code at runtime?
a standard approach for target-compiling forth applications onto small machines, as i understand it, is to put some dictionary fields in one memory area and some dictionary fields in another. things like the immediate bit and the name go in memory area a; things like the cfa and dfa go in memory area b. then you only put memory area b in the rom image, thus saving space
it seems like, if you want to generate new machine code at runtime in a forth system with x^w, you probably want to do a similar kind of segregation thing where code and (at least mutable) data go in different memory areas. data compiled with c, or , goes in the data area, and probably things like the immediate bit and the name; newly generated machine code goes in the code area. the header for the word points at the code, as usual, via a pointer (let's say a bare pointer, not a jump; doing this kind of separation with direct threading would be more challenging), the cfa
how do you handle switching the page between writable and executable? well, you could do it after every word you compile, just in case the next word calls it as immediate (say, inside of [ ]). but maybe that's too wasteful of pages, because it means each word gets its own page. (and you get terrible instruction cache contention if you put them all at the beginning of the page). probably the forth way would be to have a word you have to call explicitly to make all the previously defined words executable, but the automatic way that occurred to me is to initially point all the cfas at a trampoline routine. the trampoline, when invoked, moves the machine code for the currently-being-compiled word (if any) to a new page, updates the compilation state appropriately, and then changes the protection on all the previously compiled code that's trampolined out from writable to executable, and iterates over all the already-defined words in the dictionary, changing their cfa from pointers to itself to instead point at the new native code it's just made executable; when it reaches the point in the dictionary where it was previously invoked, it stops
you say 'actually modify the core compiler itself', but normally you don't modify existing definitions in a forth dictionary; you just add new ones to the end of it, which shadow the previous ones. i think in colorforth and some other nonstandard systems, the global namespace works more like in lisp or python, where, if you redefine an existing word, all the words that called the old definition start calling your new definition instead. this is useful for interactive experimentation because you don't have to forget (or, worse, marker). if you want to implement that, you still don't have to actually change the existing machine code; you can compile your new machine code onto a new page and point the cfa of the old definition to the new definition. this is normally what you'd want to do with a traditional forth dictionary structure anyway because the definitions are packed tightly one after the other, with no padding in between, so if you were to overwrite a definition in place with a new, longer definition, you would also be overwriting the beginning of the definition after it
as for tcp/ip, there are a pretty small number of implementations of tcp/ip in history. bsd unix's tcp/ip was copied into basically every unix and also microsoft windows and vax/vms wollongong tcp/ip (though the vax i used was on tgv multinet instead, whose provenance i don't know, though rumor has it 'tgv' was 'two guys and a vax' https://news.ycombinator.com/item?id=28190718). i don't know if cutcp (clarkson university tcp/ip) derived from the bsd code or not. plan9's i'm pretty sure didn't.
there have been a few independent reimplementations of tcp/ip, but really a surprisingly small number—not just in forth, in any language. two of them are lwip and uip from contiki; they are small and simple, though uip in particular is hardly rock-solid, and may be good information about the minimal amount you need to implement to have a usable tcp/ip stack
uip https://github.com/adamdunkels/uip is 2900 lines of c (uip/uip/ and uip/lib/); its example webclient is another 500. couple that with tweetnacl and you might have a worked example of how to get online
lwip is described by wikipedia as 'widely used', and the current version https://github.com/lwip-tcpip/lwip is 125000 lines of c. but if you only count lwip/src/core/, lwip/src/include/, and lwp/src/api/ it's 'only' 41000 lines. of that about 10% is ipv6 support
but if you git checkout 3551b2a2 you have version 1.2.0 from 02006 which is 'only' 26000 lines and already supports ip (v4 and v6), arp, tcp, udp, dhcp, snmp, slip, ppp, and ethernet. boehm's cocomo model estimates this as 6.2 person-years of work based on the number of lines of code (generated using david a. wheeler's 'sloccount'), so it's clearly not a career-long research project, and maybe it could be a lot faster if you're cloning an existing working system like this instead of designing something from scratch
plausibly in forth you could do a better job, because forth is better at embedded dsls, and as vpri showed, implementing tcp/ip really benefits a lot from embedded dsls
[Huge thanks for the detailed reply, esp. network implementations]
Yeah, I'm sorry, too, but I think it was the right choice to give up.
Yes, you can do all the things with JIT you say, but if you look at Jonesforth, and see how it implements the assembler and so forth, you can see just how simple it is, and how much more complex it would be to build a system to deal with r^x protection. That alone might more than double the complexity and code size, maybe even more than that - maybe I'm overly pessimistic. I think it's against the spirit of jonesforth to do so. I couldn't really call the result jonesforth anymore.
Re: network stack, you're probably right. There ARE 1-2 network stacks in FORTH, but they are not open source. One is from Taygeta (https://www.taygeta.com/networking/forthnet.html). Porting UIP might be fun.
He's still listed as chairman at Greenarrays, which makes chips for embedded systems (and a version of Forth is still the official development system for them)
Having used Forth professionally for about ten years, the language has always held a special place in my heart. I have had the experience (fun!) of implementing Forth from nothing in a couple of processors (6502 and 68K).
While I do think the language is useful in certain domains, the main problem everyone has with it will be finding qualified programmers. I’ve had to convert codebases to C for this reason and, back in the day, made a fair bit of money doing this as a gun for hire.
I think the opinions on the linked page are likely to be split across age lines. If you were active on the internet prior to 2004 sites like this one will spark nostalgia in many, however, if your primary experience with the internet starts with the iPhone, Facebook, etc then you will merely see poor design and ugly aesthetics. I'm sure this is somewhat reductive, but broadly I would suspect I'm correct.
It has nothing to do with that, it's just bad design to have pattern image backgrounds that make text hard to read and add nothing.
There's a reason even small web pages don't look like this any more. Pages made like this were people seeing features and thinking they should use them without thinking about what they were doing. Go back as far as you want, professional pages never looked like this.
Even in the days of geocities it was only people's first web pages that looked like this. You could excuse people for learning to put a .gif in the background and then showing it off in the mid 90s. 30 years later there isn't any excuse.
As a person that's closer to 40 then 30, i love the design of that webpage. It makes me feel young again. I understand that it's technically bad. I understand that there are many ways to make it feel more readable.
I don't care. I miss a time when nobody knew or cared about how to design a readable webpage.