dwight wrote:
I find statements that Forth is not maintainable to be clearly without merit.
Ok.
Quote:
I once had to figure out some code by a person that wrote Forth code
and was obviously a Basic programmer.
Most variables were things like A1 and B2 and such. Still, even with some of
the worst coding I'd seen since looking at poorly written BASIC, I was able to
not only understand what the code did but make the needed modification
to solve the problem ( it was related to intertia and not code ).
All depends on the size of the code base, and the scope of the change.
Quote:
Well written code in any language is a pleasure to read.
But this implies a high level of familiarity with the language. There are many languages that are unreadable to even a skilled computerist with little background in the language itself. The attraction of the Algol-ish languages is simply the familiarity: from Algol to Pascal to C to Java, C#, JavaScript and even Python. Structurally, at a higher level, all of these languages are identical. As evidence of both their longevity and popularity as a family of languages, they obviously did "something right". Meanwhile, Forth, Smalltalk, the Lisps, and modern functional languages remain niche, despite their benefits.
Quote:
Well written Forth is like reading a a well indexed book. I've never seen any language that compares.
Everything is clearly in sequence. Levels of complexity of task are well organized
so that one can quickly go to any depth to understand the intricateness needed
to solve a particular problem.
Well, most of the Forth I've looked has been Forth implementations. Perhaps, historically, they are not well written, although they are clearly sophisticated.
The example from the video posted above is very nice, I watched that, and it was easy to follow and easy to read. Of course, it's a very small program, and seeing it developed keeps the context of the individual words in mind. However, the presenter mentions how there's little need for a stack diagram. Not surprising in this case, since most of the work is done through global variables.
Consider, from the F83 source code.
Code:
Block 63
\ Interactive Layer Parsing 02Apr84map
: /STRING (S addr len n -- addr' len' )
OVER MIN ROT OVER + -ROT - ;
: PLACE (S str-addr len to -- )
3DUP 1+ SWAP MOVE C! DROP ;
: (SOURCE) (S -- addr len )
BLK @ ?DUP IF BLOCK B/BUF ELSE TIB #TIB @ THEN ;
DEFER SOURCE
: PARSE-WORD (S char -- addr len )
>R SOURCE TUCK >IN @ /STRING R@ SKIP OVER SWAP R> SCAN
>R OVER - ROT R> DUP 0<> + - >IN ! ;
: PARSE (S char -- addr len )
>R SOURCE >IN @ /STRING OVER SWAP R> SCAN
>R OVER - DUP R> 0<> - >IN +! ;
Now perhaps to you, this is casually readable. It's certainly not to me. The mental gymnastics of tracking the stacks [plural], notably in PARSE-WORD and PARSE, makes my head spin.
Or:
Code:
Block 55
\ Devices BLOCK I/O 01Apr84map
: UPDATE (S -- ) >UPDATE ON ;
: DISCARD (S -- ) 1 >UPDATE ! ( 1 BUFFER# ON ) ;
: MISSING (S -- )
>END 2- @ 0< IF >END 2- OFF >END 8 - WRITE-BLOCK THEN
>END 4 - @ >BUFFERS 4 + ! ( buffer ) 1 >BUFFERS 6 + !
>BUFFERS DUP 8 + #BUFFERS 8* CMOVE> ;
: (BUFFER) (S n fcb -- a ) PAUSE ABSENT?
IF MISSING 1 BUFFER# 4 + @ THEN ;
: BUFFER (S n -- a ) FILE @ (BUFFER) ;
: (BLOCK) (S n fcb -- a )
(BUFFER) >UPDATE @ 0>
IF 1 BUFFER# DUP READ-BLOCK 6 + OFF THEN ;
: BLOCK (S n -- a ) FILE @ (BLOCK) ;
: IN-BLOCK (S n -- a ) IN-FILE @ (BLOCK) ;
This code is GORGED with Magic Numbers. In most anything else, those would be named structure elements. Could it have been written with better constants, or could they have loaded a whole Structure package to make this easier to consume? Of course they could. But, the point, as practicing, expert Forth developers, they didn't. Not back then.
I'll finally leave this:
Code:
Block 76
\ Extensible Layer Defining Words 08Apr84map
: ,VIEW (S -- ) BLK @ DUP IF VIEW# @ 4096 * + THEN , ;
: "CREATE (S str -- ) COUNT HERE EVEN 4 + PLACE
ALIGN ,VIEW HERE 0 , ( reserve link )
HERE LAST ! ( remember nfa ) HERE ( lfa nfa ) WARNING @
IF FIND
IF HERE COUNT TYPE ." isn't unique " THEN DROP HERE
THEN ( lfa nfa ) CURRENT @ HASH DUP @ ( lfa tha prev )
HERE 2- ROT ! ( lfa prev ) SWAP ! ( Resolve link field)
HERE DUP C@ WIDTH @ MIN 1+ ALLOT ALIGN
128 SWAP CSET 128 HERE 1- CSET ( delimiter Bits )
COMPILE [ [FORTH] ASSEMBLER DOCREATE , META ] ;
: CREATE (S -- )
BL WORD ?UPPERCASE "CREATE ;
See, this is "representative" Forth to me, this is the code *I* see, code from "expert" Forth developers. I've shown examples before from Chuck Moore. If there's any notoriety for Forth code, it stems from stuff like this.
Now perhaps it's much different with modern Forth on modern systems, beyond the constraints of 1K blocks.
But then, maybe not. This is from eForth, and comes from a simple text file with no block constraints:
Code:
: parse ( b u c -- b u delta \ <string> )
temp ! OVER >R DUP \ b u u
IF 1 - temp @ BL =
IF \ b u' \ 'skip'
FOR COUNT temp @ SWAP - 0< INVERT WHILE
NEXT ( b) R> DROP 0 DUP EXIT \ all delim
THEN 1 - R>
THEN OVER SWAP \ b' b' u' \ 'scan'
FOR COUNT temp @ SWAP - temp @ BL =
IF 0< THEN WHILE
NEXT DUP >R ELSE R> DROP DUP >R 1 -
THEN OVER - R> R> - EXIT
THEN ( b u) OVER R> - ;
Again, dominated by stack operations, clouding (IMHO) the logic.
As a consumer of source code, the invisible stack shenanigans raises the cognitive load, at least for me. When the code is jumping in and out of named variables, the variables convey information germane to the context. Obviously, with badly named variables (a, b, x, q1, q2), you're just a step above the invisible stack. But at least the data flow is first class in the code, and not hidden.
Quote:
When done properly one can easily skip over parts that don't need such depth. Strings
like " 45 ms Delay " or " 45 Degrees CounterClockwise " are not hard to read.
What is missing is all the boiler plate noise found in languages like C.
I can except that there is a learning curve needed for all the ! @ SWAP DUP low level
words of Forth but I think people that see Forth that way are spending
too much time looking at the rebar, gravel, sand and Portland cement to see
the bridge that was built.
All of the Forth I've seen is pretty much nothing but sand and gravel, and it's apparent that the developers were comfortable at this level.
All of that "boiler plate noise", like the parentheses of the Lisps, vanish during reading, at least for me. Assuming the code is properly indented. Its still a reality as a developer, you have maintain all of that "noise", but from as a consumer of source code, that stuff all goes away. I don't even see it.