Forth Flames


Well, truth be told, Forth isn't that readable.

At all.

Now there's a reasonable, well-supported statement.

If you really mean to say "Most examples of Forth one finds on the web are difficult to read", then I'd agree. But I'd also say that C, C++, and Java are not readable either, as most examples of those languages wouldn't meet your criteria of readability as presented below. If you are going to critcize a particular language as being unreadable, you should be able to identify other languages that are readable.


Some call it a WORN (WriteOnceReadNever?) language. But then, that's how you sort out boys from real men. Contrast ForthIsDead

It is possible that only InterCal could qualify as a serious contender.

Some reasoned argument, examples, and attention to the distinction between lets-you-write-unreadable-code and makes-you-write-unreadable-code would probably help the anti-readability case.

How true! But as I say elsewhere, the problem of Forth is the kind of people it attracts. They are usually bright, vocal, and don't give a sh*t about readability.

It takes an average programmer to get the machine to understand. It requires an outstanding programmer to get other human beings to understand. Forthers, though clever, rarely belong to the latter category.

If it is true that BadCodeCanBeWrittenInAnyLanguage, and the obfuscated C contest is the proof that one can do worse, the (Forth history induced) game of fitting everything inside a 16 x 64 matrix -- the early Forth Home Machines -- has resulted in people trying to cram everything in an as short as possible space -- throwing away everything not strictly necessary (e.g. no convenience routine, no comment) -- and no, so-called "shadow-blocks" while a neat trick, are an insult to the maintainer. -- verec


It is possible to write any stack-based parser in Forth, whether LL or LR. Then you can make it parse the words the way you want them parsed. Because you can define any word you like and redefine any word that's already defined, illegibility in Forth code is the fault of the code's author. BadCodeCanBeWrittenInAnyLanguage.

Of course, it is not always productive to make programs easy to read at the expense of efficiency. Let the high-level code be easy to read, but make the low-level code fast. It is always possible to dissect Forth code if you cannot "read" it. Some C expressions aren't readable either.

Here's an example of a readable Forth program that says "Hello World:"

 : hello  ." Hello, World!" ;
 hello

Here's an example of a readable Forth program that sings NinetyNineBottlesOfBeerOnTheWall:

 : #bottles ( i -- i ) dup . ;

: bottle ( i -- i-1 ) #bottles ." bottle(s) of beer on the wall." cr #bottles ." bottle(s) of beer." cr ." Take one down, pass it around." cr 1- #bottles ." bottle(s) of beer on the wall." cr ;

: bottles ( n -- ) begin dup -1 > while bottle repeat drop ;

99 bottles

For a more artistic (and less readable) rendition, check out http://www.99-bottles-of-beer.net/language-froth-273.html

A well-factored version which better handles plurality:

 :noname   dup . ." bottles" ;
 :noname       ." 1 bottle"  ;
 :noname ." no more bottles" ;
 create bottles , , ,

: .bottles dup 2 min cells bottles + @ execute ; : .beer .bottles ." of beer" ; : .wall .beer ." on the wall" ; : .take ." Take one down and pass it around" ; : .verse .wall ." , " .beer ." ." cr 1- .take ." , " .wall ." ." cr ; : verses begin cr .verse dup 0= until drop ;

99 verses


Here's an example from StartingForth (modified slightly for readability purposes):

 : FILL           FAUCETS OPEN  WAIT-UNTIL-FULL  FAUCETS CLOSE ;
 : RINSE          FILL AGITATE DRAIN ;
 : DO-WASH-CYCLE  WASH SPIN RINSE SPIN ;

I would say this is more "readable" than the C or Java equivalents:

 void fill() {          void rinse() {        void do_wash_cycle() {
   open(faucets) ;        fill() ;              wash() ; 
   wait-until-full() ;    agitate() ;           spin() ;
   close(faucets) ;       drain() ;             rinse() ;
 }                      }                       spin() ;
                                              }

[I restored the above, since the meaning of the next paragraph seems to depend on it.--GP]

See how Forth has less "noise" (punctuation) than other languages. However, the lack of punctuation and standarized conventions for indentation and whitespace is one of the things that makes it easy to write hard-to-read programs in Forth.

It's too contrived, though.

Not really. A microprocessor-controlled washer could have code very much like this. Assuming memory-mapped I/O, the example could be fleshed out something like this:

 : FAUCETS    10000 ;         \ address of faucet-control port
 : LEVEL      10004 ;         \ address of water-level sensor port
 : DRAINVALVE 10008 ;         \ address of drain-control port
 : OPEN       255 SWAP ! ;    \ store 255 to port (causing faucets/drain to turn on)
 : CLOSE      0 SWAP ! ;      \ store 0 to port (causing faucets/drain to turn off)
 : NOT-FULL?  LEVEL @ 100 < ; \ return true if level less than 100%
 : NOT-EMPTY? LEVEL @ 0 > ;   \ return true if level greater than 100%
 : WAIT       1000 MS ;       \ do nothing for one second

: WAIT-UNTIL-FULL BEGIN NOT-FULL? WHILE WAIT REPEAT ; : WAIT-UNTIL-EMPTY BEGIN NOT-EMPTY? WHILE WAIT REPEAT ; : DRAIN DRAINVALVE OPEN WAIT-UNTIL-EMPTY DRAINVALVE CLOSE ;

Similar definitions for AGITATE, RINSE, WASH, SPIN, etc. would be simple, assuming memory-mapped I/O to turn on/off the various motors.

And if you think microprocessor-controlled washers are too far-fetched, here are the high-level definitions for my army of robots that will take over the world:

 : ROBOT  CRUSH! KILL! DESTROY! ;
 : DALEK  EXTERMINATE! EXTERMINATE! ;
 : R2D2   BEEP BEEP BRAAP BUZZ DOODLE-DEE-DOO ;
 : C3P0   WHINE COMPLAIN INSULT-R2D2 ;


verec supplies an example of unreadable Forth code (his comment is meant ironically):

So here's a readable example taken from ... ForthObjects

 : LIT, ( x) POSTPONE LITERAL ;
 : >SIZE ( ta - n) CELL+ @ ;
 0 VALUE SELF
 : SELF+ ( n - a) SELF + ;
 : SEND ( a xt) SELF >R  SWAP TO SELF EXECUTE  R> TO SELF ;
 VARIABLE CLS ( contains ta)
 : SIZE^ ( - aa) CLS @ ?DUP 0= ABORT" scope?" CELL+ ;
 : MFIND ( ta ca u - xt n) 2>R BEGIN DUP WHILE DUP @ 2R@ ROT
SEARCH-WORDLIST ?DUP IF ROT DROP 2R> 2DROP EXIT THEN
CELL+ CELL+ @ REPEAT -1 ABORT" can't?" ;
 : SEND' ( a ta "m ") BL WORD COUNT MFIND 0< STATE @ AND
IF SWAP LIT, LIT, POSTPONE SEND ELSE SEND THEN ;
 : SUPER ( "m ") SIZE^ CELL+ @ BL WORD COUNT MFIND 0>
IF EXECUTE ELSE COMPILE, THEN ; IMMEDIATE
 : DEFS ( n "f ") CREATE SIZE^ @ , SIZE^ +! IMMEDIATE
DOES> @ STATE @ IF LIT, POSTPONE SELF+ ELSE SELF+ THEN ;
 : METHODS ( ta) DUP CLS ! @ DUP SET-CURRENT
>R GET-ORDER R> SWAP 1+ SET-ORDER ; ( ALSO CONTEXT !)
 : CLASS ( "c ") CREATE HERE 0 , 0 , 0 ,
WORDLIST OVER ! METHODS ;
 : SUBCLASS ( ta "c ") CLASS SIZE^ OVER >SIZE OVER ! CELL+ ! ;
 : END ( ) SIZE^ DROP PREVIOUS DEFINITIONS 0 CLS ! ;
 : NEW ( ta "name ") CREATE DUP , >SIZE ALLOT IMMEDIATE
DOES> DUP CELL+ SWAP @ SEND' ;


This is not a fair example to use. This code is unusual, in that it (a) lacks any comments beyond the stack descriptions, (b) uses some relatively exotic language features (e.g. POSTPONE), and (c) is trying to do something that's inherently complicated to express: namely, extend Forth to be object-oriented.

Can you read C code when you don't know what it's supposed to do? And has had all the comments stripped out? And uses long_jmp() a lot? And is implementing ObjectiveC? Does that have any bearing on C's readability?

--GeorgePaci

I contend this is a fair example of what I have seen over the years. People should acknowledge that gems such as Anton Ertl's excellent http://www.complang.tuwien.ac.at/forth/objects/ is the exception rather than the norm. A quick browse over news://comp.lang.forth every single day of the month will rather confirm that Forthers actually enjoy writing terse and unreadable code on the grounds that they will seem so much more clever by being able to decipher such WORN constructs. The #1 problen of Forth is...Forthers!

[Referring to GP's second paragraph above:] That's off-topic. We know what this code was supposed to do -- implement an object system -- and that the author himself stripped whatever comments might have existed, if any. Finally the cryptic aspect is mostly due to the "challenge" of beating Bernd Paysan's 12 lines OOF. But no one ever asked the author to post his code, and I find it more than fair use to reuse Wiki postings on Forth to hilights my points. If the author wants to make a readable version, fine; it's just that that readable version wasn't the one shown in the first place, and that's what counts as far as readability goes: show your best example, not your worst! -- verec

I guess we should take the winner of the Obfuscated Perl contest to use as proof that Perl is not readable.


Note that these 24 lines of code add object-oriented capabilities to Forth. The conciseness is by design, to minimize the overhead. It compiles to about 2K of object code. Try adding object-oriented programming support to other procedural languages with only 24 lines of source code and 2K of additional object code. It's easy in Lua, but Lua is written in very much the same spirit as Forth, I think. (http://www.erix.it/progutil/gpeddler2/help/oo.html) -- ScottVokes

 If that same example had been 96 lines, including 72 lines of comment
 it would have still compiled to less than 2K additional object code
 and yet would have explained what is that was going on. Also, choosing
 less cryptic names (">SIZE" anyone ?) would go a long way improving the
 readability. Finally, some box-and-lines ASCII drawings or a literate
 explanation wouldn't hurt.

Finally, one of the most difficult to admit aspect of this snippet is that it claims to be some kind of "object model implementation" while it fails to address the issue of recycling (only the dictionary is used, no heap-allocation or freeing is provided.)

That's a double readability failure: failure to say what, failure to say how. -- verec

Had it been 96 lines, with 72 lines of comment, it would no longer fit into a single Forth source block, making it more difficult to use on some Forth systems. It would also take longer to load over a 1200 or 9600 baud serial link, which is another type of system where Forth is often useful.

 Whoever you are, you are tiring me. I will probably stop answering this thread.
 *Sigh*

You wrote: [...] with 72 lines of comment, it would no longer fit into a single Forth source block [...]

That's exactly my point: you are favoring easing up some terminal limitation (let's get rid of those comments so that the whole code shows on one screen) to the detriment of understandability (let's explain in plain English what's going on)

You wrote: [...] take longer to load over a 1200 or 9600 baud [...]

Again you are making another tradeoff, and again you trade readability for something else.

I would have no problems if you were saying "Readability sucks, and that's for morons anyway, 'cause real programmers can decipher anything". But that's not what you say. You try to imply that readability matters, yet you throw it out at every step along the way.

Define what your position is and stick to it.

-- verec

My position is that the author of this example decided that conciseness was more important than readability, and therefore intentionally ignored readability aspects of the Forth language. It is, therefore, not a fair example of readability. Your position seems to be that if any unreadable string can be written in a language, then that language is unreadable, which is an unreasonable position.

This is not my position. I never said or implied that if there is a single unreadable example in a given language then the whole language itself is unreadable.

What I did say is that: - given example is unreadable - given example is typical of Forth utterances I've seen over the years - therefore, collectively, those utterances define Forth as unreadable.

-- verec

And again, this is a red herring. The fact that this particular example is hard to read or lacking in commentary, or missing those oh-so-welcome box-and-line drawings has nothing whatsoever to do with the readability of Forth. I could easily find 24 unreadable lines of C, Perl, Smalltalk, Applescript, English, Lojban, or whatever you think is a more readable language. And the names aren't as cryptic if you know anything at all about Forth naming conventions.

 Definitely a problem here. I only pointed out an example inside ForthWiki
 of some code supposed to offer some value (in that case object support)
 and hilighted the fact that this code was unreadable, to which some distracted
 writer wannabe replies that if this code is unreadable that is not the
 problem. But what is the problem then? 

The problem is that you deliberately chose a less-than-readable example, rather than a readable example, and then presented it as a typical example of Forth code. You are implying "This typical Forth example is unreadable, therefore Forth is unreadable." I won't bother trying to explain how fallacious this is.

 That writer acknowledges that said example is unreadable, and carries
 on saying this has nothing to do with the readability of Forth.

Verec acknowledges that this example was stripped of comments, and condensed as much as possible, and then claims that it is fair to use it to judge the general readability of Forth.

 Wake-up-time folks!

The readability of a language is defined by the set of sentences that can be meaningfully parsed by a native reader of that language. A language is nothing but a dead language if there is no crowd/mob to utter some sentences in said language. The set of uttered sentences is what defines the language. Unfortunately, the set of uttered Forth sentences that you can collect all over the net and in the few remaining books tend to be closer to the above example in their lack of clarity of intent, thus tainting Forth with a strong UNREADABLE label.

-- verec

While it is tempting to absolve a language of the abuses committed in its name, the fact remains that (for the project leader at least) buying into a language means buying into its culture as well. If you choose language X for a project, you will get coders are members of the X community and who most likely will crank out code that looks like all the X examples you've seen. Warts and all. --djbr

Okay, you've finally made a good point. I disagree, but at least it's really about the readability of the Forth language as a whole rather than about some strawman example. I suggest you put this statement up at the top of the page (rather than the ridiculous "Forth isn't readable. At all. ... Only INTERCAL could qualify as a serious contender.") Then maybe someone can refactor this topic into a coherent exposition of the (un)readability of Forth, rather than a bunch of silliness about nouns vs. verbs and arguments about your choice of examples. --KrisJohnson


Anyone is welcome to make this page look "more positive", but whoever tackles this should resist fooling himself by hand-picking nice examples and throwing away bad examples, under the pretext of educating people on how to write with good Forth style.

-- verec

Rather than "more positive", how about "balanced"? Readable Forth can be written, and unreadable Forth can be written. Examples of each would be helpful to someone who actually wants to know something about the readability of Forth (rather than someone looking for ammunition in the ForthIsDead vendetta). --KrisJohnson

This thing is getting personal now: you have no idea how far you are from the truth.

One of my goals, in writing those pages in the first place, was to make people react and show me (and the world at large) so many counter-examples of the thesis at hand (being ForthReadability, ForthReusability, ForthPortability or ForthIsDead) that my stances would be annihilited by an overwelming evidence.

How naive of me!

Yet I did leave a hint or two (ForthIsAliveAndKicking) that absolutely nobody bothered to fill.

Those pages should stay as a testament of the flat brain waves of the ForthCommunity, (whatever ForthCommunity means, including the empty set).

I'm certainly more sorry about this state of affairs than most, yet I don't find the auto-congratulating ways usually employed to hilight Forth features very conclusive. The result is the opposite. I thought that by being a bit provocative I would unleash some creativity; I find apathy and nit-picking. I had great plans, but I'll stay with a damaging image of that humanity subset whose blinds are so strong that they can't perceive straight...

So long, and Thank you for the F...

-- verec


I had great plans, but I'll stay with a damaging image of that humanity subset whose blinds are so strong that they can't perceive straight...

Well, truth be told, English isn't that readable.

At all. --GeorgePaci

"Obviously, no one would dare to comment on the excellent choice of words." --KrisJohnson


Here's some more code from the same page. Looks pretty readable to me. I don't speak Forth but I can grasp what it does.

 CLASS BUTTON
VAR TEXT
VAR LEN
VAR X
VAR Y
 : DRAW ( )
X @ Y @ AT-XY\ Get X and Y, and position cursor on screen
TEXT @ LEN @ TYPE ;\ Get TEXT and LENgth, and type it
 : INIT ( ca u)0 X ! 0 Y ! LEN ! TEXT ! ;
 END

: BOLD27 EMIT ." [1m" ;\ Emit code to turn on BOLD TEXT : NORMAL 27 EMIT ." [0m" ;\ Emit code to return to normal text

BUTTON SUBCLASS BOLD-BUTTON : DRAW ( )BOLD SUPER DRAW NORMAL ; END


I must point out two issues when it comes to Forth legibility.

First, Chinese is utterly intractible to an English reader. Chinese has very different styles of writing than English. This should not be used as an argument against Chinese. Thus, Forth code which is perfectly readable to someone knowledgable in Forth may still appear as baud-barf to someone who isn't. Be aware that readability depends implicitly on your knowledge of the language itself.

That being said, neither AntonErtl?'s nor BerndPaysan?'s examples can be taken as representative of legible code. Quite the contrary, they're usually just the opposite. I don't know why, they really ought to know better. But, following ChuckMoore's coding styles would yield a substantially more legible program. They often argue that doing so would, as Anton once complained to me, "over-factor" the code. I should note, as documented elsewhere on this wiki, that ChuckMoore's coding conventions and the conventions of ExtremeProgramming are quite similar. The difference is that Chuck chooses terse names, but his names always follow a convention. As XP teaches, learning the coding conventions is as important as anything else too.

So, I openly acknowledge the 24-lines of OO goodness above is, in a word, unreadable. Here is how I would write it, were I so inclined to use it:

 0 VALUE SELF

: SELF+ ( n - a) SELF + ; : SEND ( a xt) SELF >R SWAP TO SELF EXECUTE R> TO SELF ;

\ Classes contain the following overall structure: \ +0 wordlist \ +1 size \ +2 ... unknown ...

VARIABLE lastDefinedClass ( contains ta )

: >SIZE ( ta - n) CELL+ @ ; : SIZE^ ( - aa) lastDefinedClass @ ?DUP 0= ABORT" scope?" CELL+ ;

: scanMethods rot search-wordlist ?dup ; : nextClass cell+ cell+ @ ; : MFIND ( ta ca u - xt n) 2>R BEGIN DUP WHILE DUP @ 2R@ scanMethods IF ROT DROP 2R> 2DROP EXIT THEN nextClass REPEAT -1 ABORT" can't?" ;

: LIT, ( x) POSTPONE LITERAL ; : methodFound? bl word count mfind 0< ; : compiling? state @ ; : (send') swap lit, lit, postpone send ; : SEND' ( a ta "m ") methodFound? compiling? AND IF (send') ELSE SEND THEN ;

: SUPER ( "m ") SIZE^ >SIZE BL WORD COUNT MFIND 0> IF EXECUTE ELSE COMPILE, THEN ; IMMEDIATE

: DEFS ( n "f ") CREATE SIZE^ @ , SIZE^ +! IMMEDIATE DOES> @ compiling? IF LIT, POSTPONE SELF+ ELSE SELF+ THEN ;

: METHODS ( ta) DUP lastDefinedClass ! @ DUP SET-CURRENT >R GET-ORDER R> SWAP 1+ SET-ORDER ; ( ALSO CONTEXT!)

: CLASS ( "c ") CREATE HERE 0 , 0 , 0 , WORDLIST OVER ! METHODS ;

: SUBCLASS ( ta "c ") CLASS SIZE^ OVER >SIZE OVER ! CELL+ ! ;

: END ( ) SIZE^ DROP PREVIOUS DEFINITIONS 0 CLS ! ;

: NEW ( ta "name ") CREATE DUP , >SIZE ALLOT IMMEDIATE DOES> DUP CELL+ SWAP @ SEND' ;

This "refactoring" was done in a few minutes. I recognize that there are other unknowns in the code, which I've had to let be. Much of the code, however, relates to banging dictionary structures together, and dealing with what is the horror of ANSI Forth specifications. Since the code represents an extension to the language itself, combining some macro-like functionality, the casual reader may still not fully understand how it works. It also exploits "state-smart" semantics, which even in the Forth community at large, is considered Really Bad Idea today.

--Samuel A. Falvo II


ForthReadability, ForthReusability, ForthIsDead, ForthPessimism


CategoryForth


EditText of this page (last edited October 13, 2008) or FindPage with title or text search