Hacker News new | past | comments | ask | show | jobs | submit login
Lost at C? Forth May Be the Answer (forth.org)
93 points by gnosis on May 22, 2011 | hide | past | favorite | 47 comments



> I once needed a structure which was written to 30 named, one-dimensional arrays. It was read as a single, named, two-dimensional array. I’m told this is feasible in C, but I’ve never met anyone who wanted to try it.

It sounds to me like what's being described here is an array of pointers to arrays. Not only is that feasible in C, it is extremely simple and common. The second argument to main() is such an array, for example.

> In C, you’re more protected. But then, you also have to do things like type casting to circumvent a patronizing compiler constantly checking up on you.

I don't consider it "patronizing" when a compiler warns me that casting the first few bytes of a string literal into a memory address might not be what I want. I consider that "helpful".

> The biggest drawback of Forth is the Catch 22 that attends any nonconformist idea. Not many people know Forth, and people won’t usually learn something unless everyone else is already using it.

The author apparently does not think much of his audience. He's basically saying that if you don't learn Forth it's because you're a conformist.

> Industry experience has shown that a Forth programmer is up to ten times more productive than a C programmer.

Now this is just silly. If this were really "industry experience", nobody would still be using C for anything except legacy applications.


> Industry experience has shown that a Forth programmer is up to ten times more productive than a C programmer.

Anytime I see some kind of statement like this, I am reminded of the python paradox.


Forth has 20 years on Python, and the industry has gotten infinitely more conservative in those 20 years. When Forth came out, using computers was radical. When Python came out, using C++ was radical.


I learned a lot about Forth writing JONESFORTH[1]. It's brilliant that you can write a full system in a couple of 1000 LoC that one person can completely understand from top to bottom.

After writing it, I learned a lot more about the Forth community, and how they despise my (perhaps misguided but well-intentioned) attempts to teach people about the principles of writing a Forth interpreter. Search for "JONESFORTH" in the comp.lang.forth archives for some examples.

[1] http://git.annexia.org/?p=jonesforth.git;a=summary


"I learned a lot more about the Forth community, and how they despise my (perhaps misguided but well-intentioned) attempts to teach people about the principles of writing a Forth interpreter."

Could you elaborate on that? Why would they despise your attempt to help others?

Also, thank you for writing JONESFORTH. It's a very useful resource.


The nub of the problem (for them) is that JONESFORTH isn't an ANSI-standard Forth. The secondary problem is that because I wrote it from scratch on my own, I didn't follow a bunch of traditions about "my granddaddy wrote Forth this way and it was good enough for him", details that are really irrelevant if you're just trying to explain how Forth works.

Anyhow if you want to find out more, go to:

https://groups.google.com/group/comp.lang.forth/topics

and type "JONESFORTH" in the search box.


I think JONESFORTH is awesome, I really enjoyed reading it, and I really appreciate you writing it, but there are a couple of points that could possibly be described as above, but maybe will sound a little less insane if described in full.

• Your ROT originally was backwards. That is, rather than rotating the third element on the stack to the top, it pushed the top stack element down by two items, which is traditionally called -ROT. While obviously this is a purely arbitrary convention, and irrelevant to just trying to explain how Forth works, it did create unnecessary confusion; it means that anybody who actually learned Forth from JONESFORTH would constantly be struggling to remember which way ROT worked. I apologize for never properly reporting this to you. You fixed this in http://git.annexia.org/?p=jonesforth.git;a=commit;h=dccbff0e...

• The design of JONESFORTH (last time I read it) doesn't accommodate CREATE DOES>, which is the Forth way of creating functions that have state — closures, if you will, or objects with a single method. This, by contrast, I think really is relevant to trying to explain how Forth works. The techniques that support CREATE DOES> (ITC, DTC) are no more complex than JONESFORTH.

I think comp.lang.forth people were slamming JONESFORTH not because of anything about JONESFORTH but because they are mentally insane. (Although I can't really find the flames you were alluding to. The worst I found is complaints about minor incompatibilities like the above.)


"The nub of the problem (for them) is that JONESFORTH isn't an ANSI-standard Forth."

You might find this quote interesting:

"The ANS Forth standard is at least one, maybe two orders of magnitude more complex than Mr. Moore's approach to Forth. He says that code should be so simple that most type of errors simply can't happen. In the late eighties and early nineties Chuck quit writing code in Forth and experimented with sourceless programming. His first versions of his VLSI CAD software, OKAD, were constructed without source using his tools in his OK operating system. Later he return to Forth programming and rewrote OKAD II under his new colorForth. [Moore, 2000] In the chat session Chuck was asked, 'How did you come to the conclusion that Forth was too complex, and that sourceless programming was your next move?'

His reply was, 'Maybe by reading the Forth Standard.'"

From: http://www.ultratechnology.com/levels.htm


Am I reading this right? Chuck Moore decided that all programming could be done with sourceless coding and his demonstration of this was a graphical application? This is so common, yet so totally wrong. It's akin to the "revelation" that algebra is not necessary in mathematics because all mathematics can be "visualised". Which is equally stupid. However, I may just be misinterpreting what is being said in that quote. After all, I don't know why he then switched back to Forth, which is not sourceless, I am guessing.


"Am I reading this right? Chuck Moore decided that all programming could be done with sourceless coding and his demonstration of this was a graphical application? This is so common, yet so totally wrong."

He later recanted:

"I'm back.

OKAD was a mistake. I have added Forth to OKAD. ...

A few years ago I gave up on Forth, it was too complicated. It was about the time of the work of the standard committee and I wanted something simple. I abandoned source and used a decompiler to view the object code. It did not really work. I also wanted to get away from the keyboard."

More here:

http://www.ultratechnology.com/color4th.html


No, Forth is not sourceless. Though I was startled to read about how some implementations give you a souped-up disk editor for coding, to avoid the overhead of a self-hosted filesystem. I guess it beats toggling bits into the front panel....


You're in good company, since Chuck Moore despises ANSI Forth, and has written several newer, simplified Forths.


For years I've been railing about how lousy the language FORTH is. I have a confession to make, I actually think it has some charm. Despite the horribly coupled and low-level thinking that needs to go into writing a program of even moderate length in FORTH, I believe that there is hope for the language, and that it is even quite appropriate for use today, in modern systems, because in some circumstances it is better than the alternatives.

But first, we need to agree on the problem space.

FORTH was originally used for non-critical real time control of telescope hardware. The computation requirements were quite modest, there was limited storage available, and the audience was pretty technical. The programs did not have much dynamic state.

Generally, FORTH has been a failure outside of this envelope. While there are very whizzy specialized implementations of FORTH that are very close to equally specialized hardware, and that are capable of exceptional performance and turning really neat tricks, the usual result of bringing FORTH to bear on problems that have a large amount of state or very hard real-time requirements are: Slipped schedules, eventual cancellation of projects, and the labeling of anything dealing with the language as unhealthy fanatacism.

In the hands of a moderately skilled programmer, FORTH is good at:

- near-real-time operations involving modest amounts of computation

- rapid prototyping of same

- stuff whose consumers are very technical and can Deal With support along the lines of "comment out that line, stick this code in and try it again"

In my experience FORTH has not demonstrated success at projects that involve more than three or four engineers, projects that have extensive or complex data structures, or that require high performance (i.e., when microseconds count). This counts out video games (I've seen a lot of these attempts fail), operating systems (ditto), and commercial applications like word processors (shudder).

But if you've got a telescope to control, or a mass spectrometer, or you're doing new hardware bringup, FORTH is great stuff, and I've seen it shine.


"One of the most pervasive unknown Forth successes has been FedEx's handheld package tracking devices. They were all Forth powered, under-time and budget, and worked remarkably well. The new generation of FedEx package trackers (the ones that look like scan guns) use Forth as well."

Much more here:

http://pages.cs.wisc.edu/~bolo/forth/#projects


IIRC the "new" Denver airport luggage handling system was a disaster, and it was written in FORTH.

[I tried to find references, but couldn't. I do remember finding this out, and saying "That explains /everything/!"]

You can code a train-wreck in anything, I guess.


On the other hand, the FreeBSD bootloader is written in Forth. Per installation, the Denver Airport luggage handling system was massively much more complex, but that doesn't make one terrible implementation representative of the entire language. Good things can still be well written in languages that aren't C.

http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/boot/forth/

And for some sources for the Denver Airport claim:

http://developers.slashdot.org/story/05/08/27/1634255/Denver...

http://www.44342.com/forth-f381-t4059-p1.htm

Edit: it should be noted that the mechanical side of the baggage handling system was extremely complex, and at the beginning was prone to breaking.


I'll add: FORTH is incredibly easy to bring up. It was the first compiler I ever implemented, after getting started with Z-80 assembly and BASIC. I recommend building a FORTH implementation as a project that everyone should do; it'll take you about a weekend.


I wouldn't call it a failure outside the telescope market. IIRC the first Mac apps were written in forth. There is a forth interpreter for every platform. Quite a few smaller apps for older computers or handheld devices were written in forth. AFAIK it's still used for embedded systems programming.

But the language is rather old. The standard was never updated to turn forth into a "modern" language. And then there is the community. Even things like named "function" arguments are scowled at.


I used MacFORTH back in 1985 because I wanted to get a leg up on Mac programming, and it was one of the few environments that worked on a 128K Mac with two floppy drives. It was awful; I'll note that MacFORTH sank pretty rapidly once even halfway decent IDEs became available.

http://www.dadhacker.com/blog/?p=1468

One of the reasons there is a FORTH interpreter for every platform is that it's so easy to port or bring up that it's /always/ an early arrival.

It's sure not modern. Unextendeded FORTH has nothing like a heap (just stack-like allocation). I could go on.

And yeah, you get yelled at by FORTH purists who see nothing wrong with the language. They can be an interesting crowd to deal with; the most incompetent ones seem to be the loudest and most arrogant about FORTH's universal applicability to everything (and if you can't see this, you're a moran). See earlier comment about projects running late, then killed.

[Back in the day, when I was working on database engines at a largish computer company, a manager of mine said, "I've got to go over to building 123 and evaluate a proposal by some people who want to sell us an O(N) sorting algorithm."

"Don't they know that's impossible?"

"No. They claim they've done it. They got some people in Marketing all excited. They think it could be really big."

"Huh."

"They've written it in FORTH."

(pause)

"They're stark raving loonies," I said.

Oh, and it was about as miserable and as confused and misguided and very nearly fraudulent as you can imagine. Go figure.]


Forth doesn't interest me as a language any more. I thoroughly recommend learning it as a pathway into various other languages. And indeed, I consider JONESFORTH to be one of the highlights of the coding world. But these days I don't find a use for the language per se.

I have to say, however, I would love to see an interpreter for FORTH which does not actually maintain a secondary stack at runtime, but compiles the code down to something equivalent, e.g. uses the LLVM Jit.

Much of what is done with the second stack is simply reordering bits of data or duplicating bits of data. This could all be done at "compile time". Each stack location would only exist at compile time. At runtime the values would be stored in ordinary variables and references. There'd be no need to duplicate data or reorder it at runtime. Instead it would just pull the data from the correct variable or memory location.

Naturally this defeats all the principals of FORTH compilers, etc, blah, blah, blah. But it would still be a fun (and easy) thing to do.


One Forth I've seen, FreeForth, compiles subroutine threaded machine code rather than traditional direct/indirect threaded code, and it does register renaming at compile time to hide SWAPs, generating as necessary a real SWAP at the end. You do need a stack though, there are only so many registers. Even C has a stack - it just mixes up data and returns on the same one, which means it needs two extra allocation mechanisms (function return value and malloc) for data that must outlive the function's lexical extent.


Around 5% of the instructions in a C program are register reordering code introduced by the register allocator (assuming x86 and an optimizing compiler). I do not know the percentage of the register spilling code, which comes on top of this. Effectively, an LLVM JIT also produces shuffle code, but the programmer can use variable names instead of stack reorder operations.


>Much of what is done with the second stack is simply reordering bits of data or duplicating bits of data.

Actually, stack machine with one stack isn't Turing-complete. You need two stacks for this.

http://en.wikipedia.org/wiki/Turing_machine_equivalents#Two-...


You might want to consider a language based on combinatorics such as Fexl (see http://fexl.com). It enables you to write functions with or without intermediate symbols to the extent you see fit. In other words, you can go "point-free" or "point-full" as you like.


I believe Factor's optimizing compiler doesn't actually implement a stack, but just uses the stack structure as a handy shortcut to data-flow analysis.


Here's a detailed write-up of some of the advantages and disadvantages of Forth and the philosophy that surrounds it:

http://www.yosefk.com/blog/my-history-with-forth-stack-machi...


My first introduction to FORTH was GraFORTH on the Apple ][ (which has all but disappeared from the internets).

It was memorable because it was fast as blazes, essentially compiling routines to a sequence of JSRs, and it featured built-in wireframe 3D graphics primitives. This was exciting at a time where naively clearing the screen with line() routines took several seconds.


Honestly, that page pretty well convinced me that I have no interest in learning Forth. Possibly it was the "Since Forth needs few registers, a chip with many is just a lot of wasted silicon" bit.


If I were flung back in time to the 1970s, the two languages I think I could stand to work in would be Lisp and Forth. (C is not on the list because C has still come a long way since then; 2011-C is better in a lot of little ways than 1970-C, and the sum total is quite large.) But in 2011, I'd be more interested in their sequels, like Clojure or Factor [1].

But I do think it's important to look at Forth and see its place in history as a viable alternative to C, on pretty much any level C cared to compete in. It's important to understand that C is not the only way. (I don't mean this as a criticism of C.)

[1]: http://factorcode.org/


Thats fair enough. And that sentence I quoted would be much less horrifying in the 1970s given all the changes in computers since then.


Presumably there's no reason why an optimising compiler couldn't make use of extra registers.


At the end of procedure you have to have a Forth ABI compliant stack state. If your stack state is in registers, more than one, you have to insert special code to reassign them (or schedule registers with that constraint in mind).

Registers aren't good at compressing code the Forth way.

Register code for z = x - y (assume all are in registers or stack) could be sub r1,r2,r3, or sub r127,r124,r11, or anything. Register indices depends on context. On Forth it always will be just sub instruction. If y operand is in memory, the Forth code will be @ sub, and always will be. We could abstract that : @sub @ sub ; if we feel that calling @sub will save us little code memory. It is just not possible with registers, because of the context: the sequence ld ri,(rj); sub rk,rl,ri could use any proper i, j, k and l as register indices.

As a side note I should say that Java stack machine byte code isn't compressed as Forth code should be, so it lose to register code in Dalvik.

As a rule, Forth code is 2-3 times less than CISC code (VAX, x86) and CISC code is 2-3 times less that RISC code (which itself is smaller that VLIW code).


Internal evidence says this was written after 1994 but probably not very long after.


While it's cool how little plumbing Forth needs to be extensible via new control structures, I do make mistakes as does everyone I've ever worked with, and life is too short for yet another platform on which every program blows up randomly because it isn't 100.0% flawless. C at least tries to help a little with typed pointers, so I don't see how Forth could help but be more brittle.


"C at least tries to help a little with typed pointers, so I don't see how Forth could help but be more brittle."

You might be interested in StrongForth, a strong statically typed variant of Forth:

http://home.vrweb.de/stephan.becher/forth/


Too bad StrongForth only works on the Windows command line.

There is however StrongForth.f which runs on top of an ANS Forth system:

http://home.vrweb.de/stephan.becher/strongforth.f/index.htm


Update the EEPROM PIC program used to drive a jittering oscillator?

When is this article from?


At risk of sounding like an old git...

I built my own machine AND half-arsed Forth implementation for Z80 back in '92 from a couple of library books, a dismantled broken RM380Z and a PC with DOS 3 and TASM on it. It sort of worked but was a little unreliable (it was all on stripboard, most of the bus timing was guessed and the XTAL was way too fast). I think the entire Forth impl assembled down to about 4K.

That sort of thing is just impossible with today's equipment. It's depressing. To much abstraction these days. Ironically Forth was probably the first language that supported writing DSLs :)

I'll dig it out and document it one day.


Lisp is probably the first language that supports writing DSLs.


...within the syntax constraints of s-expressions. Forth allows you to define your own syntax as long as it's whitespace delimited.


... and as long as every sequence of words is a valid program.


I think that applies to all programming languages :)


No, many languages have a grammar in order to reject malformed programs, so that not every sequence of words is a program.

AFAIK, you can define your own FOR loops in FORTH, but you can't enforce statically that each FOR has a matching LOOP; the mismatched program will happily run and corrupt the return stack (if you use the return stack top to store the loop index so that it will be available using the magic word I).


That is true - i'll give you that. TBH I have fallen down that hole.


I don't see how that refutes my point?


Impossible? I don't know, micro-controllers can be used that way too if you wish so.


A fair whack of the microcontroller market uses harvard architecture (separate program/data) which makes it very hard for self-modifying programs to exist (such as Forth at a low level). Not only that, the programs are stored in Flash which has a limited lifetime so if you do go and modify it regularly, it will die.

90% of embedded ARM, PIC, AVR, MSP430, eZ80, 68HC11 etc fit that description in one way or another.

This is of course all IMHO.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: